簡體   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