繁体   English   中英

Android Chrome自定义标签回退

[英]Android Chrome custom tabs fallback

我正在实施fallback 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的源代码,它只不过是一个帮助器来创建使用Intent.ACTION_VIEW打开URL的常规隐式意图。 它可以帮助您使用Chrome识别的特定键向意图添加额外数据,Chrome随后会使用这些键来呈现自定义UI。

以下是官方网页的解释:

自定义选项卡使用ACTION_VIEW Intent和关键Extras来自定义UI。 这意味着默认情况下,页面将在系统浏览器或用户的默认浏览器中打开。

如果用户安装了Chrome并且它是默认浏览器,它将自动获取EXTRAS并显示自定义UI。 另一个浏览器也可以使用Intent附加功能来提供类似的自定义界面。

对于链接上的解决方案,源代码取自此处 正如您在CustomTabActivityHelper#openCustomTab看到的,首先它将查找支持自定义选项卡的应用程序。 如果可用,则启动CustomTabsIntent描述的隐式intent。 如果没有,请打开WebViewActivity

如何找出是否有任何应用支持自定义标签? 您可以在CustomTabsHelper.getPackageNameToUse 首先,它将解析所有可以使用Intent.ACTION_VIEW打开URL的应用程序。 然后,它将检查该应用是否支持自定义标签。

然后,

  • 如果没有可用的应用,则返回null
  • 如果只有1个应用程序可用,请将其退回
  • 如果有超过1个应用程序且其中1个是默认应用程序,请将其返回。
  • 如果有超过1个可用应用,其中1个是Chrome,请将其退回。
  • 否则,返回null
  • (如果有超过1个应用程序可用,您可以设置一个逻辑来要求用户选择他们想要的任何浏览器)

现在,您的解决方案如何?

如果我们使用您的解决方案,如果没有应用程序可以处理CustomTabsIntent创建的隐式意图,则会打开WebviewActivity ,在这种情况下没有安装浏览器? 如果我们有浏览器并且它们都不支持自定义标签会发生什么? 您的应用仍会要求在浏览器中打开链接,而不是在WebViewActivityWebViewActivity

请记住, CustomTabsIntent只是一个帮助器,可以创建一个正常的隐式意图,使用Intent.ACTION_VIEW打开一个URL,并使用各种EXTRA数据来自定义UI。 如何自定义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;
        }

        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;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM