我正在实现后备Chrome自定义标签
我指的是几个具有自定义后备实现的链接 。我不明白为什么需要它。
我做了以下处理后备的工作,并且工作正常。
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); }
知道为什么需要这样复杂的实现来处理回退吗?
使用以下版本的支持库compile 'com.android.support:customtabs:25.3.1'
如果您看过的源代码CustomTabsIntent
,它无非是一个帮助程序,它使用来创建一个普通的隐式意图来打开URL Intent.ACTION_VIEW
。它可帮助您使用Chrome识别的特定键向意图添加额外的数据,然后Chrome会使用这些键来呈现自定义UI。
这是官方页面上的说明:
“自定义标签”使用ACTION_VIEW Intent和其他键来自定义UI。这意味着默认情况下该页面将在系统浏览器或用户的默认浏览器中打开。
如果用户安装了Chrome,并且它是默认的浏览器,它将自动选择EXTRAS并显示自定义的UI。其他浏览器也可以使用Intent Extras提供类似的自定义界面。
对于链接上的解决方案,源代码取自here。从中可以看到CustomTabActivityHelper#openCustomTab
,首先它将查找支持“自定义标签”的应用。如果可用,请启动所描述的隐式意图CustomTabsIntent
。如果不是,请打开WebViewActivity
。
如何确定是否有任何应用程序支持“自定义选项卡”?你可以继续CustomTabsHelper.getPackageNameToUse
。首先,它将使用解析所有可以打开URL的应用程序Intent.ACTION_VIEW
。然后,它将检查应用程序是否支持“自定义标签”。
然后,
如果没有可用的应用程序,请返回 null
如果只有1个应用可用,请将其退回。
如果可用的应用程序超过1个,并且其中1个是默认应用程序,则将其返回。
如果可用的应用程序超过1个,并且其中1个是Chrome,则将其退回。
否则,返回 null
(如果有多个应用可用,则可以设置逻辑以要求用户选择所需的任何浏览器)
现在,您的解决方案如何?
如果我们使用您的解决方案,WebviewActivity
那么如果没有应用程序可以处理由创建的隐式意图,那么将打开CustomTabsIntent
,在这种情况下,没有安装浏览器?如果我们有浏览器,但都不支持“定制选项卡”,该怎么办?您的应用仍会要求在浏览器而不是中打开链接WebViewActivity
。
请记住,CustomTabsIntent
它只是创建常规隐式意图的帮助者,可以使用Intent.ACTION_VIEW
各种EXTRA数据来自定义UI 来打开URL 。浏览器处理如何自定义UI。基本上,我认为我们可以创建和启动意图,从而无需使用即可自行通过自定义UI打开浏览器CustomTabsIntent
。我从来没有尝试过。
如果您希望在任何浏览器中打开链接,无论该浏览器是否支持“自定义选项卡”,并且WebViewActivity
如果没有可用的应用程序都可以在其中打开该链接,即使我认为这不是最佳解决方案,您的解决方案也可以解决该问题。
但是,如果您希望在支持“自定义标签”的浏览器中打开链接,并且WebViewActivity
如果没有可用的支持“自定义标签”的应用打开该链接,那么他的解决方案就是正确的选择。
但是,如果您只是想提供后备机制,那么它应该不会那么复杂。这是更简单的代码:
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; } ListresolvedActivityList = pm.queryIntentActivities(activityIntent, 0); List 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 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; } }