简体   繁体   English

如何检查 Chrome 是否支持 Chrome 自定义标签?

[英]How can I check whether Chrome supports Chrome custom tabs?

I have an activity that loads an external url into a webview within my app.我有一个活动将外部 url 加载到我的应用程序中的 web 视图中。 I'd like to use Chrome Custom tabs when it's available but I support devices that might not have a version of Chrome that supports them.我想在 Chrome 自定义标签可用时使用它,但我支持的设备可能没有支持它们的 Chrome 版本。

In the case of CustomTabs not being supported I'd like to use my old code but use the CustomTabsIntent.Builder() when they are.在不支持 CustomTabs 的情况下,我想使用我的旧代码,但在它们支持时使用 CustomTabsIntent.Builder()。 The old code loads the content in a WebView contained in an Activity where I can still manage the ActionBar.旧代码将内容加载到包含在 Activity 中的 WebView 中,我仍然可以在其中管理 ActionBar。

I'd like to write a helper method that will tell me if it's supported but I'm not sure how.我想编写一个辅助方法来告诉我它是否受支持,但我不确定如何支持。 The info on the developer page is pretty slim: https://developer.chrome.com/multidevice/android/customtabs开发者页面上的信息非常少: https : //developer.chrome.com/multidevice/android/customtabs

It says if you bind succeeds the custom tabs can be safely used.它说如果您绑定成功,则可以安全地使用自定义选项卡。 Is there an easy way to bind to test this?有没有一种简单的方法来绑定来测试这个?

Like this I assume:像这样我假设:

Intent serviceIntent = new Intent("android.support.customtabs.action.CustomTabsService");
serviceIntent.setPackage("com.android.chrome");
boolean customTabsSupported = bindService(serviceIntent, new CustomTabsServiceConnection() {
            @Override
            public void onCustomTabsServiceConnected(final ComponentName componentName, final CustomTabsClient customTabsClient) {}

            @Override
            public void onServiceDisconnected(final ComponentName name) {}
        },
        Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY);

if (customTabsSupported) {
    // is supported
}

Instead of binding and unbinding the service, you can use the PackageManager to check if Custom Tabs is supported.您可以使用 PackageManager 检查是否支持自定义选项卡,而不是绑定和取消绑定服务。

  private static final String SERVICE_ACTION = "android.support.customtabs.action.CustomTabsService";
    private static final String CHROME_PACKAGE = "com.android.chrome";

    private static boolean isChromeCustomTabsSupported(@NonNull final Context context) {
        Intent serviceIntent = new Intent(SERVICE_ACTION);
        serviceIntent.setPackage(CHROME_PACKAGE);
        List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentServices(serviceIntent, 0);
        return !(resolveInfos == null || resolveInfos.isEmpty());
    }

Be aware that other browsers may support Custom Tabs in the future, so you may want to modify that to support this case.请注意,将来其他浏览器可能会支持自定义选项卡,因此您可能需要对其进行修改以支持这种情况。

You can try following code to figure out if you have a browser that supports custom tab:您可以尝试以下代码来确定您的浏览器是否支持自定义选项卡:

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

private String getPackageName(Context context) {
    if (mPackageNameToUse != null) {
        return mPackageNameToUse;
    }

    // Get default VIEW intent handler that can view a web url.
    Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.test-url.com"));

    // Get all apps that can handle VIEW intents.
    PackageManager pm = context.getPackageManager();
    List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(activityIntent, 0);
    List<String> packagesSupportingCustomTabs = new ArrayList<>();
    for (ResolveInfo info : resolvedActivityList) {
        Intent serviceIntent = new Intent();
        serviceIntent.setAction(CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION);
        serviceIntent.setPackage(info.activityInfo.packageName);
        if (pm.resolveService(serviceIntent, 0) != null) {
            packagesSupportingCustomTabs.add(info.activityInfo.packageName);
        }
    }

    // Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents
    // and service calls.
    if (packagesSupportingCustomTabs.isEmpty()) {
        mPackageNameToUse = null;
    } else if (packagesSupportingCustomTabs.size() == 1) {
        mPackageNameToUse = packagesSupportingCustomTabs.get(0);
    } else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) {
        mPackageNameToUse = STABLE_PACKAGE;
    } else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) {
        mPackageNameToUse = BETA_PACKAGE;
    } else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) {
        mPackageNameToUse = DEV_PACKAGE;
    } else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) {
        mPackageNameToUse = LOCAL_PACKAGE;
    }
    return mPackageNameToUse;
}

When calling, you can do something like this:调用时,您可以执行以下操作:

public void openCustomTab(Uri uri, Activity activity) {
    //If we cant find a package name, it means there's no browser that supports
    //Chrome Custom Tabs installed. So, we fallback to the default browser
    if (getPackageName(activity) == null) {
        activity.startActivity(new Intent(Intent.ACTION_VIEW, uri));
    } else {
        CustomTabsIntent.Builder intentBuilder = new CustomTabsIntent.Builder();
        intentBuilder.enableUrlBarHiding();
        intentBuilder.setToolbarColor(activity.getResources().getColor(R.color.purple_a_01));

        CustomTabsIntent customTabsIntent = intentBuilder.build();
        customTabsIntent.intent.setPackage(mPackageNameToUse);

        customTabsIntent.launchUrl(activity, uri);
    }
}

I ended up writing a static method in my Utils class so I can check and handle the case where it isn't supported:我最终在我的 Utils 类中编写了一个静态方法,以便我可以检查和处理它不受支持的情况:

/**
     * Check if Chrome CustomTabs are supported. 
     * Some devices don't have Chrome or it may not be
     * updated to a version where custom tabs is supported.
     *
     * @param context the context
     * @return whether custom tabs are supported
     */
    public static boolean isChromeCustomTabsSupported(@NonNull final Context context) {
        Intent serviceIntent = new Intent("android.support.customtabs.action.CustomTabsService");
        serviceIntent.setPackage("com.android.chrome");

        CustomTabsServiceConnection serviceConnection = new CustomTabsServiceConnection() {
            @Override
            public void onCustomTabsServiceConnected(final ComponentName componentName, final CustomTabsClient customTabsClient) { }

            @Override
            public void onServiceDisconnected(final ComponentName name) { }
        };

        boolean customTabsSupported =
                context.bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY);
        context.unbindService(serviceConnection);

        return customTabsSupported;
    }

I solved this problem by handling ActivityNotFound exception in catch block.我通过处理 catch 块中的ActivityNotFound异常解决了这个问题。

The trick is to check if the browser activity of chrome can be started or not, if it can't be started or throws an exception then simply open the link through Intent.ACTION_VIEW .诀窍是检查 chrome 的浏览器活动是否可以启动,如果无法启动或抛出异常,则只需通过Intent.ACTION_VIEW打开链接Intent.ACTION_VIEW

Here is all the relevant code ....这是所有相关代码....

private void onBtnLinkClicked(View v, int pos) {
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            openCustomTab(url);
        } else {
            openBrowserActivity(url);
        }
    } catch (Exception e) {
        e.printStackTrace();
        openBrowserActivity(url);
    }
}

private void openBrowserActivity(String url) {
    Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
    context.startActivity(browserIntent);
}

What is openCustomTab(url) you say : Here is the relevant code for it.你说的是什么openCustomTab(url) :这是它的相关代码。

private void openCustomTab(String url) {
    CustomTabsIntent.Builder intentBuilder = new CustomTabsIntent.Builder();

    int color = context.getResources().getColor(R.color.colorPrimary);
    intentBuilder.setToolbarColor(color);
    intentBuilder.setShowTitle(true);

    String menuItemTitle = context.getString(R.string.menu_title_share);
    PendingIntent menuItemPendingIntent = createPendingShareIntent();
    intentBuilder.addMenuItem(menuItemTitle, menuItemPendingIntent);     

    intentBuilder.setStartAnimations(context,
            R.anim.slide_in_right, R.anim.slide_out_left);
    intentBuilder.setExitAnimations(context,
            android.R.anim.slide_in_left, android.R.anim.slide_out_right);

    CustomTabActivityHelper.openCustomTab(
            activity, intentBuilder.build(), Uri.parse(url), new WebviewFallback());
}

My style of answer may seem cocky but before clicking downvote let me know if you have run into any unexpected bug or any other problem that this approach may have cause.我的回答风格可能看起来很自大,但在单击 downvote 之前,请告诉我您是否遇到任何意外错误或此方法可能导致的任何其他问题。 Do give your feedback, we are a community afterall.请提供您的反馈,毕竟我们是一个社区。

From developer site of Chrome , I found the followings -Chrome 的开发者站点,我发现了以下内容 -

As of Chrome 45, Chrome Custom Tabs is now generally available to all users of Chrome, on all of Chrome's supported Android versions (Jellybean onwards).从 Chrome 45 开始,Chrome 自定义选项卡现在通常可供所有 Chrome 用户使用,适用于所有 Chrome 支持的 Android 版本(Jellybean 及更高版本)。

Link: https://developer.chrome.com/multidevice/android/customtabs#whencaniuseit链接: https : //developer.chrome.com/multidevice/android/customtabs#whencaniuseit

So, I checked whether Chrome supports Chrome Custom Tab by version.所以,我检查了Chrome是否按版本支持Chrome 自定义标签

Check my code:检查我的代码:

String chromePackageName = "com.android.chrome";
int chromeTargetVersion  = 45;

boolean isSupportCustomTab = false;
try {
    String chromeVersion = getApplicationContext().getPackageManager().getPackageInfo(chromePackageName, 0).versionName;
    if(chromeVersion.contains(".")) {
        chromeVersion = chromeVersion.substring(0, chromeVersion.indexOf('.'));
    }
    isSupportCustomTab = (Integer.valueOf(chromeVersion) >= chromeTargetVersion);
} catch (PackageManager.NameNotFoundException ex) {
} catch (Exception ex) { }

if (isSupportCustomTab) {
    //Use Chrome Custom Tab
} else {
    //Use WebView or other Browser
}

I don't know how efficient it is, just want to share.我不知道它的效率如何,只是想分享。

New issues may arise if you are targeting API level 30 and running on an Android 11 device.如果您的目标是 API 级别 30 并在 Android 11 设备上运行,则可能会出现新问题。

You will need to add a section to your manifest, such as:您需要在清单中添加一个部分,例如:

<queries>
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="https" />
    </intent>
</queries>

OR或者

<queries>
    <intent>
        <action android:name="android.support.customtabs.action.CustomTabsService" />
    </intent>
</queries>

Without this, some of the calls to PackageManager mentioned in the above posts will not work as you expect.没有这个,上面帖子中提到的一些对 PackageManager 的调用将不会像你期望的那样工作。

https://developer.android.com/training/package-visibility/use-cases https://developer.android.com/training/package-visibility/use-cases

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

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