Menggunakan Tab Khusus dengan Android 11

Android 11 memperkenalkan perubahan tentang cara aplikasi berinteraksi dengan aplikasi lain yang telah diinstal pengguna di perangkat. Anda dapat membaca selengkapnya tentang perubahan tersebut di dokumentasi Android.

Bila aplikasi Android yang menggunakan Tab Khusus menargetkan SDK level 30 atau yang lebih tinggi, beberapa perubahan mungkin diperlukan. Artikel ini membahas perubahan yang mungkin diperlukan untuk aplikasi tersebut.

Dalam kasus yang paling sederhana, Custom Tabs dapat diluncurkan dengan satu baris seperti:

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

Aplikasi yang meluncurkan aplikasi menggunakan pendekatan ini, atau bahkan menambahkan penyesuaian UI seperti mengubah warna toolbar, menambahkan tombol tindakan tidak perlu melakukan perubahan apa pun pada aplikasi.

Lebih Memilih Aplikasi Native

Namun, jika Anda mengikuti praktik terbaik, beberapa perubahan mungkin diperlukan.

Praktik terbaik pertama yang relevan adalah aplikasi sebaiknya memilih aplikasi native untuk menangani intent, bukan Tab Khusus jika aplikasi yang dapat menanganinya telah diinstal.

Di Android 11 dan yang lebih baru

Android 11 memperkenalkan flag Intent baru, FLAG_ACTIVITY_REQUIRE_NON_BROWSER, yang merupakan cara yang direkomendasikan untuk mencoba membuka aplikasi native karena tidak mengharuskan aplikasi mendeklarasikan kueri pengelola paket apa pun.

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

Solusinya adalah mencoba meluncurkan Intent dan menggunakan FLAG_ACTIVITY_REQUIRE_NON_BROWSER untuk meminta Android menghindari browser saat diluncurkan.

Jika aplikasi native yang mampu menangani Intent ini tidak ditemukan, ActivityNotFoundException akan ditampilkan.

Sebelum Android 11

Meskipun aplikasi dapat menargetkan Android 11, atau API level 30, versi Android sebelumnya tidak akan memahami flag FLAG_ACTIVITY_REQUIRE_NON_BROWSER, sehingga kita perlu terpaksa membuat kueri Pengelola Paket dalam kasus tersebut:

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

Pendekatan yang digunakan di sini adalah untuk mengkueri Pengelola Paket untuk aplikasi yang mendukung intent http generik. Aplikasi tersebut kemungkinan adalah browser.

Kemudian, buat kueri untuk aplikasi yang menangani URL tertentu yang ingin kita luncurkan. Tindakan ini akan menampilkan penyiapan browser dan aplikasi native untuk menangani URL tersebut.

Sekarang, hapus semua browser yang ditemukan pada daftar pertama dari daftar kedua, dan kita hanya akan tersisa pada aplikasi native.

Jika daftar kosong, kita tahu bahwa tidak ada pengendali native dan menampilkan nilai salah. Jika tidak, kami akan meluncurkan intent untuk pengendali native.

Penutup

Kita perlu memastikan bahwa penggunaan metode yang tepat untuk setiap kesempatan:

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 memberikan informasi yang kita butuhkan. Jika sama dengan atau lebih besar dari 30, Android akan mengetahui FLAG_ACTIVITY_REQUIRE_NON_BROWSER dan kita dapat mencoba meluncurkan aplikasi nativa dengan pendekatan baru. Jika tidak, kami akan mencoba meluncurkannya dengan pendekatan lama.

Jika peluncuran aplikasi asli gagal, kami akan meluncurkan Tab Khusus.

Terdapat beberapa boilerplate yang terlibat dalam praktik terbaik ini. Kami berupaya menyederhanakannya dengan mengenkapsulasi kompleksitas di library. Nantikan update pada support library android-browser-helper.

Mendeteksi browser yang mendukung Tab Khusus

Pola umum lainnya adalah menggunakan PackageManager untuk mendeteksi browser yang mendukung Tab Khusus di perangkat. Kasus penggunaan yang umum untuk hal ini adalah menyetel paket pada Intent untuk menghindari dialog disambiguasi aplikasi atau memilih browser yang akan dihubungkan ketika terhubung ke layanan Tab Khusus.

Saat menargetkan API level 30, developer perlu menambahkan bagian kueri ke Manifes Android mereka, mendeklarasikan filter intent yang cocok dengan browser dengan dukungan Tab Khusus.

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

Dengan menerapkan markup, kode yang sudah ada yang digunakan untuk membuat kueri untuk browser yang mendukung Tab Khusus akan berfungsi seperti yang diharapkan.

Pertanyaan Umum (FAQ)

T: Kode yang mencari kueri penyedia Tab Khusus untuk aplikasi yang dapat menangani intent https://, tetapi filter kueri hanya mendeklarasikan kueri android.support.customtabs.action.CustomTabsService. Bukankah kueri untuk intent https:// harus dideklarasikan?

J: Saat mendeklarasikan filter kueri, filter akan memfilter respons terhadap kueri ke PackageManager, bukan kueri itu sendiri. Karena browser yang mendukung Tab Khusus mendeklarasikan penanganan CustomTabsService, Tab tersebut tidak akan difilter. Browser yang tidak mendukung Tab Khusus akan difilter.

Kesimpulan

Itulah semua perubahan yang diperlukan untuk menyesuaikan integrasi Tab Khusus yang ada agar berfungsi dengan Android 11. Untuk mempelajari lebih lanjut cara mengintegrasikan Tab Khusus ke dalam aplikasi Android, mulailah dengan panduan penerapan, lalu lihat praktik terbaik untuk mempelajari cara membangun integrasi kelas satu.

Beri tahu kami jika ada pertanyaan atau masukan.