Bergabunglah bersama kami di ⁠#Android11: The Beta Launch Show pada tanggal 3 Juni!

Visibilitas paket di Android 11

Android 11 mengubah cara aplikasi membuat kueri dan berinteraksi dengan aplikasi terinstal lainnya di perangkat yang sama. Jika aplikasi Anda menargetkan Android 11, Anda mungkin perlu menambahkan elemen <queries> di file manifes aplikasi sehingga sistem mengetahui aplikasi lain mana yang akan ditampilkan ke aplikasi Anda.

Elemen <queries> memungkinkan Anda menjelaskan aplikasi lain mana yang mungkin diperlukan aplikasi Anda untuk berinteraksi. Anda dapat menentukan aplikasi menurut nama paket atau menurut tanda tangan intent dalam satu elemen <queries>.

Metode PackageManager yang menampilkan hasil tentang aplikasi lain, misalnya queryIntentActivities(), akan difilter berdasarkan deklarasi <queries> aplikasi yang memanggil. Interaksi eksplisit dengan aplikasi lain, seperti startService(), juga mengharuskan aplikasi target mencocokkan salah satu deklarasi di <queries>.

Kami menantikan masukan Anda. Selesaikan survei singkat ini untuk memberi tahu kami pendapat Anda selama menggunakan fitur tersebut. Khususnya, beri tahu kami tentang kasus penggunaan yang terdampak oleh fitur ini.

Membuat kueri dan berinteraksi dengan paket tertentu

Jika Anda mengetahui kumpulan spesifik aplikasi yang ingin dibuat kuerinya atau dilibatkan dalam interaksi, seperti aplikasi yang dapat terintegrasi dengan aplikasi Anda, atau aplikasi yang layanannya Anda gunakan, sertakan nama paketnya dalam kumpulan elemen <package> di dalam tag <queries>:

<manifest package="com.example.game">
    <queries>
        <package android:name="com.example.store" />
        <package android:name="com.example.services" />
    </queries>
    ...
</manifest>

Membuat kueri dan berinteraksi dengan aplikasi menggunakan filter intent

Aplikasi Anda mungkin perlu membuat kueri atau berinteraksi dengan kumpulan aplikasi yang memiliki tujuan tertentu, tetapi Anda mungkin tidak mengetahui nama paket khusus yang perlu disertakan. Dalam situasi ini, Anda dapat mencantumkan tanda tangan filter intent dalam tag <queries>. Aplikasi Anda kemudian dapat menemukan aplikasi yang cocok dengan tag <intent-filter>.

Contoh berikut memungkinkan aplikasi Anda melihat aplikasi terinstal yang mendukung berbagi gambar JPEG:

<manifest package="com.example.game">
    <queries>
        <intent>
            <action android:name="android.intent.action.SEND" />
            <data android:mimeType="image/jpeg" />
        </intent>
    </queries>
    ...
</manifest>

Elemen <intent> memiliki beberapa batasan:

  • Anda harus menyertakan tepat satu elemen <action>.
  • Anda tidak boleh menggunakan atribut path, pathPrefix, pathPattern, atau port dalam elemen <data>. Sistem berperilaku seolah-olah Anda menetapkan setiap nilai atribut menjadi karakter pengganti generik (*).
  • Anda tidak boleh menggunakan atribut mimeGroup dari elemen <data>.
  • Dalam beberapa elemen <data> dari satu elemen <intent>, Anda dapat menggunakan masing-masing atribut berikut sebanyak satu kali:

    • mimeType
    • scheme
    • host

    Anda dapat mendistribusikan atribut ini di beberapa elemen <data> atau menggunakannya dalam satu elemen <data>.

Elemen <intent> mendukung nilai karakter pengganti generik (*) sebagai nilai untuk beberapa atribut:

  • Atribut name dari elemen <action>.
  • Subjenis atribut mimeType dari elemen <data> (image/*).
  • Jenis dan subjenis atribut mimeType dari elemen <data> (*/*).
  • Atribut scheme dari elemen <data>.
  • Atribut host dari elemen <data>.

Kecuali ditentukan lain dalam daftar sebelumnya, sistem tidak mendukung perpaduan karakter teks dan karakter pengganti, seperti prefix*.

Membuat kueri dan berinteraksi dengan semua aplikasi

Dalam kasus yang jarang terjadi, aplikasi Anda mungkin perlu membuat kueri atau berinteraksi dengan semua aplikasi terinstal yang ada di perangkat, terlepas dari komponen yang ada di dalamnya. Contohnya adalah app store seperti Google Play. Agar aplikasi Anda dapat melihat semua aplikasi terinstal lainnya, Android 11 memperkenalkan izin QUERY_ALL_PACKAGES.

Catatan: Pada sebagian besar kasus, Anda dapat memenuhi kasus penggunaan aplikasi dengan mendeklarasikan tag <queries>.

Dalam versi Pratinjau Developer mendatang, Google Play akan menyediakan panduan bagi aplikasi yang memerlukan izin ini.

Pesan log untuk pemfilteran paket

Untuk mengetahui detail selengkapnya tentang bagaimana perubahan pada visibilitas paket memengaruhi aplikasi, Anda dapat mengaktifkan pesan log untuk pemfilteran paket. Jika Anda mengembangkan aplikasi pengujian atau aplikasi yang dapat di-debug di Android Studio, kemampuan ini akan diaktifkan untuk Anda. Jika tidak, Anda dapat menjalankan perintah berikut di jendela terminal untuk mengaktifkannya secara manual:

adb shell pm log-visibility --enable your-package-name

Kemudian, setiap kali paket difilter dari nilai hasil objek PackageManager, Anda akan melihat pesan seperti berikut di Logcat:

I/AppsFilter: interaction: PackageSetting{7654321 \
  com.example.myapp/12345} -> PackageSetting{...} BLOCKED

Menguji perubahan

Untuk menguji apakah perubahan perilaku ini telah diterapkan dalam aplikasi Anda, selesaikan langkah-langkah berikut:

  1. Instal Android Studio 3.6.1 atau versi yang lebih baru.
  2. Instal Gradle versi terbaru yang didukung oleh Android Studio.
  3. Tetapkan targetSdkVersion aplikasi ke 'R'.
  4. Jangan sertakan elemen <queries> di file manifes aplikasi Anda.
  5. Panggil getInstalledApplications() atau getInstalledPackages(). Kedua metode tersebut akan menampilkan daftar yang difilter.
  6. Lihat fitur mana saja di aplikasi Anda yang tidak berfungsi.
  7. Perkenalkan entri <queries> yang sesuai untuk memperbaiki fitur ini.

Kasus penggunaan yang tidak terpengaruh oleh perubahan tersebut

Daftar berikut menyertakan beberapa contoh kasus penggunaan yang tidak memerlukan deklarasi <queries>:

  • Aplikasi target adalah aplikasi Anda sendiri.
  • Anda menggunakan intent implisit untuk memulai aktivitas. Aplikasi Anda mungkin membatasi penggunaannya atas intent implisit untuk berinteraksi dengan aplikasi lain.
  • Aplikasi Anda berinteraksi dengan paket sistem tertentu, seperti penyedia media, yang mengimplementasikan fungsionalitas Android inti.
  • Aplikasi lain mengharapkan hasil dari aplikasi Anda. Situasi ini berlaku jika aplikasi Anda adalah penyedia konten, saat aplikasi lain memanggil aplikasi Anda dengan memanggil startActivityForResult(), dan jika aplikasi Anda adalah layanan yang akan dimulai atau digunakan untuk terhubung oleh aplikasi lain.

Misalnya, jika aplikasi lain membuat permintaan ke penyedia konten di aplikasi Anda, sistem akan mengizinkan aplikasi Anda melihat aplikasi lain tersebut.

Menambahkan batasan pada proses memulai aktivitas

Android 11 menambahkan beberapa tanda yang memungkinkan Anda menentukan kapan panggilan ke startActivity() dari aplikasi Anda harus menghasilkan ActivityNotFoundException, bukan meminta aplikasi lain memenuhi intent tersebut. Menggunakan tanda ini, Anda tidak perlu memanggil resolveActivity() atau queryIntentActivities().

Tanda ini sangat berguna untuk intent web. Jika aplikasi Anda ingin membuat deep link ke aplikasi yang terinstal dan aplikasi tersebut tidak tersedia, aplikasi Anda dapat menangani intent tersebut dengan memuat URL di tab kustom atau browser dalam aplikasi.

Meluncurkan intent web di aplikasi non-browser

Jika Anda menyertakan tanda intent FLAG_ACTIVITY_REQUIRE_NON_BROWSER, intent hanya akan dimulai pada kondisi berikut:

  • Aplikasi non-browser akan menangani intent tersebut secara langsung.
  • Pengguna dapat memilih aplikasi non-browser dalam dialog disambiguasi.

Jika tidak, ActivityNotFoundException akan ditampilkan, dan aplikasi Anda diharapkan dapat menangani intent tersebut sendiri.

Kotlin

try {
    val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply {
        // The URL should either launch directly in a non-browser app (if it's
        // the default), or in the disambiguation dialog.
        addCategory(CATEGORY_BROWSABLE)
        flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER
    }
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // Only browser apps are available, or a browser is the default.
    tryLoadInCustomTabs(url) // Or use an in-app browser.
}

Java

try {
    Intent intent = new Intent(ACTION_VIEW, Uri.parse(url));
    // The URL should either launch directly in a non-browser app (if it's the
    // default), or in the disambiguation dialog.
    intent.addCategory(CATEGORY_BROWSABLE);
    intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER);
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Only browser apps are available, or a browser is the default.
    tryLoadInCustomTabs(url); // Or use an in-app browser.
}

Menetapkan hanya satu aktivitas yang cocok

Jika Anda menyertakan tanda intent FLAG_ACTIVITY_REQUIRE_DEFAULT, intent aplikasi Anda dipanggil hanya saat ada satu aplikasi di perangkat yang dapat menanganinya, atau saat aplikasi menjadi pengendali default untuk intent tersebut. Tanda ini mengurangi konflik dengan tidak menampilkan dialog disambiguasi, tetapi memungkinkan aplikasi menentukan bagaimana konten ditampilkan bagi pengguna.

Kotlin


val url = url-to-load
try {
    // In order for this intent to be invoked, the system must directly launch a
    // non-browser app.
    val intent = Intent(ACTION_VIEW, Uri.parse(url).apply {
        addCategory(CATEGORY_BROWSABLE)
        flags = FLAG_ACTIVITY_NEW_TASK or FLAG_REQUIRE_NON_BROWSER or
                FLAG_ACTIVITY_REQUIRE_DEFAULT
    }
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // This code executes in one of the following cases:
    // 1. Only browser apps can handle the intent.
    // 2. The user has set a browser app as the default app.
    // 3. The user hasn't set any app as the default for handling URLs.
    tryLoadInCustomTabs(url)
}

Java

String url = url-to-load;
try {
    // In order for this intent to be invoked, the system must directly launch a
    // non-browser app.
    Intent intent = new Intent(ACTION_VIEW, Uri.parse(url));
    intent.addCategory(CATEGORY_BROWSABLE);
    intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_REQUIRE_NON_BROWSER |
            FLAG_ACTIVITY_REQUIRE_DEFAULT);
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // This code executes in one of the following cases:
    // 1. Only browser apps can handle the intent.
    // 2. The user has set a browser app as the default app.
    // 3. The user hasn't set any app as the default for handling URLs.
    tryLoadInCustomTabs(url);
}