在 Android 11 上使用自訂分頁

Android 11 針對應用程式與使用者在裝置上安裝的其他應用程式互動的方式,導入了相關異動。如要進一步瞭解這些異動,請參閱 Android 說明文件

如果使用自訂 Tabs 的 Android 應用程式指定 SDK 級別 30 以上,可能需要進行一些變更。本文將說明這些應用程式可能需要的變更。

在最簡單的情況下,您可以使用一行程式碼啟動自訂分頁,如下所示:

new CustomTabsIntent.Builder().build()
        .launchUrl(this, Uri.parse("https://www.example.com"));

應用程式只要使用這項功能啟動應用程式,甚至加入 UI 自訂項目 (例如變更工具列顏色新增動作按鈕),就不需要在應用程式中進行任何變更。

偏好原生應用程式

不過,如果您遵循最佳做法,可能需要進行一些變更。

第一個相關的最佳做法是,如果已安裝可處理意圖的應用程式,應用程式應優先使用原生應用程式處理意圖,而非自訂分頁。

Android 11 以上版本

Android 11 推出了新的 Intent 標記 FLAG_ACTIVITY_REQUIRE_NON_BROWSER,這是嘗試開啟原生應用程式的建議方式,因為它不需要應用程式宣告任何套件管理員查詢。

static boolean launchNativeApi30(Context context, Uri uri) {
    Intent nativeAppIntent = new Intent(Intent.ACTION_VIEW, uri)
            .addCategory(Intent.CATEGORY_BROWSABLE)
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                    Intent.FLAG_ACTIVITY_REQUIRE_NON_BROWSER);
    try {
        context.startActivity(nativeAppIntent);
        return true;
    } catch (ActivityNotFoundException ex) {
        return false;
    }
}

解決方法是嘗試啟動 Intent,並使用 FLAG_ACTIVITY_REQUIRE_NON_BROWSER 要求 Android 在啟動時避免使用瀏覽器。

如果找不到可處理此意圖的原生應用程式,系統會擲回 ActivityNotFoundException

Android 11 之前

雖然應用程式可能指定 Android 11 或 API 級別 30,但先前的 Android 版本無法解讀 FLAG_ACTIVITY_REQUIRE_NON_BROWSER 標記,因此在這些情況下,我們需要改為查詢 Package Manager:

private static boolean launchNativeBeforeApi30(Context context, Uri uri) {
    PackageManager pm = context.getPackageManager();

    // Get all Apps that resolve a generic url
    Intent browserActivityIntent = new Intent()
            .setAction(Intent.ACTION_VIEW)
            .addCategory(Intent.CATEGORY_BROWSABLE)
            .setData(Uri.fromParts("http", "", null));
    Set<String> genericResolvedList = extractPackageNames(
            pm.queryIntentActivities(browserActivityIntent, 0));

    // Get all apps that resolve the specific Url
    Intent specializedActivityIntent = new Intent(Intent.ACTION_VIEW, uri)
            .addCategory(Intent.CATEGORY_BROWSABLE);
    Set<String> resolvedSpecializedList = extractPackageNames(
            pm.queryIntentActivities(specializedActivityIntent, 0));

    // Keep only the Urls that resolve the specific, but not the generic
    // urls.
    resolvedSpecializedList.removeAll(genericResolvedList);

    // If the list is empty, no native app handlers were found.
    if (resolvedSpecializedList.isEmpty()) {
        return false;
    }

    // We found native handlers. Launch the Intent.
    specializedActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(specializedActivityIntent);
    return true;
}

這裡採用的方法是向 Package Manager 查詢支援一般 http 意圖的應用程式。這些應用程式可能是瀏覽器。

接著,請查詢應用程式,以便處理我們要啟動的特定網址。這會傳回瀏覽器和原生應用程式設定,以便處理該網址。

接著,從第二個清單中移除第一個清單中的所有瀏覽器,這樣就只剩下原生應用程式。

如果清單為空白,表示沒有原生處理常式,因此會傳回 false。否則,我們會啟動原生處理常式的意圖。

全面整合使用

我們需要確保在每個情況下都使用正確的方法:

static void launchUri(Context context, Uri uri) {
    boolean launched = Build.VERSION.SDK_INT >= 30 ?
            launchNativeApi30(context, uri) :
            launchNativeBeforeApi30(context, uri);

    if (!launched) {
        new CustomTabsIntent.Builder()
                .build()
                .launchUrl(context, uri);
    }
}

Build.VERSION.SDK_INT 提供我們需要的資訊。如果等於或大於 30,Android 就會知道 FLAG_ACTIVITY_REQUIRE_NON_BROWSER,我們就可以嘗試使用新方法啟動原生應用程式。否則,我們會嘗試使用舊方法啟動。

如果啟動原生應用程式失敗,我們會啟動自訂分頁。

這個最佳做法涉及一些樣板。我們正在努力透過將複雜性封裝在程式庫中,讓這項作業變得更簡單。請密切留意 android-browser-helper 支援資料庫的更新。

偵測支援自訂分頁的瀏覽器

另一個常見的模式是使用 PackageManager 偵測裝置上支援自訂分頁的瀏覽器。這類常見用途包括在 Intent 上設定套件,以避免應用程式不清晰對話方塊,或是在連線至自訂分頁服務時選擇要連線的瀏覽器。

開發人員在指定 API 級別 30 時,必須在 Android 資訊清單中新增查詢專區,宣告與支援自訂分頁的瀏覽器相符的意圖篩選器。

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

標記完成後,用於查詢支援自訂分頁的瀏覽器的現有程式碼就會正常運作。

常見問題

問:尋找自訂分頁提供者的程式碼會針對可處理 https:// 意圖的應用程式執行查詢,但查詢篩選器只會宣告 android.support.customtabs.action.CustomTabsService 查詢。您不應該宣告 https:// 意圖的查詢嗎?

答:宣告查詢篩選器時,它會將對 PackageManager 的查詢回應篩除,而非查詢本身。由於支援 Custom Tabs 的瀏覽器會宣告處理 CustomTabsService,因此不會遭到篩除。系統會篩除不支援自訂分頁的瀏覽器。

結論

這些就是將現有自訂分頁整合功能調整為與 Android 11 搭配運作所需的所有變更。如要進一步瞭解如何將自訂分頁整合至 Android 應用程式,請先參閱實作指南,然後查看最佳做法,瞭解如何建構一流的整合作業。

如有任何問題或意見,歡迎與我們聯絡!