0

Ich Ausweich Chrom benutzerdefinierte RegisterkartenAndroid Chrome benutzerdefinierte Registerkarten Rückfall

Umsetzung I bezog sich auf einige Links it has some individuelle Ausweich Implementierung. Ich habe nicht verstanden, warum es erforderlich ist.

Ich habe folgende für die Handhabung Fallback und funktioniert gut.

try { 
     CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); 
     builder.setToolbarColor(ContextCompat.getColor(context, R.color.appthemecolor)); 
     CustomTabsIntent customTabsIntent = builder.build(); 
     customTabsIntent.launchUrl(context, Uri.parse(url)); 
    } catch (ActivityNotFoundException e) { 
     e.printStackTrace(); 
     Intent intent = new Intent(context, WebviewActivity.class); 
     intent.putExtra(WebviewActivity.EXTRA_URL, url); 
     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 
     context.startActivity(intent); 
    } 

Eine Idee, warum solch eine komplexe Implementierung für die Handhabung von Fallback erforderlich ist?

folgende Version der Support-Bibliothek compile 'com.android.support:customtabs:25.3.1'

Antwort

2

mit der Wenn Sie den Quellcode CustomTabsIntent sehen durch, es ist nichts mehr als nur ein Helfer eine normale implizite Absicht erstellen Intent.ACTION_VIEW eine URL zu öffnen verwenden. Es hilft Ihnen, der Absicht zusätzliche Daten hinzuzufügen, indem Sie die von Chrome erkannten Schlüssel verwenden, die später von Chrome zur Darstellung einer benutzerdefinierten Benutzeroberfläche verwendet werden. Hier

ist die Erklärung von the official page:

Benutzerdefinierte Tabs verwendet eine ACTION_VIEW Intent mit den wichtigsten Extras die Benutzeroberfläche anpassen. Dies bedeutet, dass die Seite standardmäßig im Browser des Systems oder im Standardbrowser des Benutzers geöffnet wird.

Wenn der Nutzer Chrome installiert hat und es sich um den Standardbrowser handelt, wird er automatisch die EXTRAS abholen und eine angepasste Benutzeroberfläche präsentieren. Es ist auch möglich für einen anderen Browser, die Intent-Extras eine ähnliche angepasste Schnittstelle zu verwenden.

Für die Lösung auf Ihrer Verbindung, der Quellcode von here übernommen. Wie Sie von CustomTabActivityHelper#openCustomTab sehen können, wird zuerst nach der App gesucht, die Custom Tabs unterstützt. Wenn es verfügbar ist, starten Sie die implizite Absicht, die von CustomTabsIntent beschrieben wird. Wenn nicht, öffnen Sie die WebViewActivity.

Wie kann ich herausfinden, ob eine App benutzerdefinierte Tabs unterstützt? Sie können es auf CustomTabsHelper.getPackageNameToUse sehen. Zuerst werden alle Apps aufgelöst, die eine URL unter Intent.ACTION_VIEW öffnen können. Dann wird überprüft, ob diese Apps benutzerdefinierte Tabs unterstützen. Dann

,

  • Wenn keine Apps verfügbar, kehren null
  • Wenn nur 1 App zur Verfügung, es zurück.
  • Wenn mehr als 1 App verfügbar ist und 1 davon die Standardanwendung ist, geben Sie sie zurück.
  • Wenn mehr als 1 App verfügbar ist und 1 davon Chrome ist, geben Sie es zurück.
  • Else, Rückkehr null
  • (Wenn mehr als 1 App verfügbar sind, können Sie eine Logik setzen einen Benutzer zu fragen, einen beliebigen Browser sie wollen wählen)

Nun, wie wäre Ihre Lösung?

Wenn wir Ihre Lösung verwenden, wird WebviewActivity geöffnet, wenn keine Apps mit impliziten Absichten umgehen können, die von CustomTabsIntent erstellt wurden, in diesem Fall ist kein Browser installiert? Was ist passiert, wenn wir einen Browser haben und keiner davon Custom Tabs unterstützt? Ihre App wird immer noch darum bitten, den Link im Browser zu öffnen und nicht in WebViewActivity.

Denken Sie daran, CustomTabsIntent ist nur ein Helfer, um eine normale implizite Absicht zu erstellen, eine URL zu öffnen, die Intent.ACTION_VIEW mit verschiedenen EXTRA-Daten verwendet, um die Benutzeroberfläche anzupassen. Wie man die Benutzeroberfläche anpasst, wird von den Browsern gehandhabt. Grundsätzlich denke ich, dass wir die Absicht erstellen und starten können, den Browser mit einer benutzerdefinierten Benutzeroberfläche ohne CustomTabsIntent zu öffnen. Ich probiere das nie aus.

Wenn Sie die Hyperlink einfügen mögen jeden Browser in geöffnet werden, unabhängig von dem Browser-Unterstützung Benutzerdefinierte Tabs oder nicht, und der Link in WebViewActivitygeöffnet werden, wenn keine Apps vorhanden, Ihre Lösung es selbst lösen obwohl es nicht die beste Lösung, denke ich.

Aber, wenn Sie den Hyperlink einfügen möchten im Browser geöffnet werden, die benutzerdefinierte Tabs unterstützen, und die Verbindung in WebViewActivity wenn keine Apps geöffnet werden, die benutzerdefinierte Tabs verfügbar, seine Lösung unterstützen, ist der richtige.

Aber wenn Sie wollen, bietet nur Fallback-Mechanismus, sollte es nicht so kompliziert sein. Hier ist der einfachere Code:

public class CustomTabs { 

    private static final String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService"; 

    private static final String STABLE_PACKAGE = "com.android.chrome"; 
    private static final String BETA_PACKAGE = "com.chrome.beta"; 
    private static final String DEV_PACKAGE = "com.chrome.dev"; 
    private static final String LOCAL_PACKAGE = "com.google.android.apps.chrome"; 

    public static void openTab(Context context, String url) { 
     CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); 

     /* do some UI customization here */ 

     CustomTabsIntent customTabsIntent = builder.build(); 

     String packageName = getPackageNameToUse(context); 

     if (packageName == null) { 
      Intent intent = new Intent(context, WebviewActivity.class); 
      intent.putExtra(WebviewActivity.EXTRA_URL, url); 
      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 

      context.startActivity(intent); 
     } else { 
      customTabsIntent.intent.setPackage(packageName); 
      customTabsIntent.launchUrl(context, Uri.parse(url)); 
     } 
    } 

    private static String getPackageNameToUse(Context context) { 
     String packageNameToUse = null; 

     PackageManager pm = context.getPackageManager(); 

     Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com")); 

     ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0); 

     String defaultViewHandlerPackageName = null; 
     if (defaultViewHandlerInfo != null) { 
      defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName; 
     } 

     List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(activityIntent, 0); 

     List<String> packagesSupportingCustomTabs = new ArrayList<>(); 
     for (ResolveInfo info : resolvedActivityList) { 
      Intent serviceIntent = new Intent(); 
      serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION); 
      serviceIntent.setPackage(info.activityInfo.packageName); 
      if (pm.resolveService(serviceIntent, 0) != null) { 
       packagesSupportingCustomTabs.add(info.activityInfo.packageName); 
      } 
     } 

     if (packagesSupportingCustomTabs.isEmpty()) { 
      packageNameToUse = null; 
     } else if (packagesSupportingCustomTabs.size() == 1) { 
      packageNameToUse = packagesSupportingCustomTabs.get(0); 
     } else if (!TextUtils.isEmpty(defaultViewHandlerPackageName) 
       && !hasSpecializedHandlerIntents(context, activityIntent) 
       && packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) { 
      packageNameToUse = defaultViewHandlerPackageName; 
     } else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) { 
      packageNameToUse = STABLE_PACKAGE; 
     } else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) { 
      packageNameToUse = BETA_PACKAGE; 
     } else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) { 
      packageNameToUse = DEV_PACKAGE; 
     } else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) { 
      packageNameToUse = LOCAL_PACKAGE; 
     } 
     return packageNameToUse; 
    } 

    private static boolean hasSpecializedHandlerIntents(Context context, Intent intent) { 
     try { 
      PackageManager pm = context.getPackageManager(); 
      List<ResolveInfo> handlers = pm.queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER); 

      if (handlers == null || handlers.size() == 0) { 
       return false; 
      } 

      for (ResolveInfo resolveInfo : handlers) { 
       IntentFilter filter = resolveInfo.filter; 
       if (filter == null) continue; 
       if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue; 
       if (resolveInfo.activityInfo == null) continue; 
       return true; 
      } 

     } catch (RuntimeException e) { 
      Log.e("LOG", "Runtime exception while getting specialized handlers"); 
     } 

     return false; 
    } 
} 
+0

Hallo, vielen Dank für diesen Beitrag! Aber was ist der Unterschied zwischen LOCAL_PACKAGE und STABLE_PACKAGE? Warum erlauben Sie Benutzern, LOCAL_PACKAGE hier zu verwenden? –

+0

@JiechaoWang Um ehrlich zu sein, ich weiß es nicht. Der Code stammt aus dem Beispielcode, der vom Chrome-Team bereitgestellt wird. 'STABLE_PACKAGE' ist offensichtlich. Es ist die Standardversion von Chrome, die wir normalerweise verwenden. Für 'LOCAL_PACKAGE', aus dem Paketnamen, denke ich, es ist die App mit dem System kommen. – marcelljee

Verwandte Themen