Intent dan filter intent

Intent adalah objek pesan yang dapat Anda gunakan untuk meminta tindakan dari komponen aplikasi lainnya. Meskipun intent memfasilitasi komunikasi antar komponen dengan beberapa cara, ada tiga kasus penggunaan mendasar:

  • Memulai aktivitas

    Activity mewakili satu layar dalam aplikasi. Anda dapat memulai instance baru Activity dengan meneruskan Intent ke startActivity(). Intent menjelaskan aktivitas yang akan dimulai dan membawa data yang diperlukan.

    Jika Anda ingin menerima hasil dari aktivitas setelah selesai, panggil startActivityForResult(). Aktivitas Anda menerima hasil sebagai objek Intent terpisah dalam callback onActivityResult() aktivitas Anda. Untuk mengetahui informasi selengkapnya, lihat panduan Aktivitas.

  • Memulai layanan

    Service adalah komponen yang melakukan operasi di latar belakang tanpa antarmuka pengguna. Dengan Android 5.0 (API level 21) dan yang lebih baru, Anda dapat memulai layanan dengan JobScheduler. Untuk informasi selengkapnya tentang JobScheduler, lihat API-reference documentation-nya.

    Untuk versi sebelum Android 5.0 (API level 21), Anda dapat memulai layanan menggunakan metode class Service. Anda dapat memulai layanan untuk melakukan operasi satu kali (seperti mendownload file) dengan meneruskan Intent ke startService(). Intent menjelaskan layanan yang akan dimulai dan membawa data yang diperlukan.

    Jika layanan didesain dengan antarmuka klien-server, Anda dapat mengikat ke layanan dari komponen lain dengan meneruskan Intent ke bindService(). Untuk mengetahui informasi selengkapnya, lihat panduan Layanan.

  • Mengirimkan siaran

    Siaran adalah pesan yang bisa diterima aplikasi apa saja. Sistem mengirimkan berbagai siaran untuk peristiwa sistem, seperti saat sistem melakukan booting atau perangkat mulai mengisi daya. Anda dapat mengirim siaran ke aplikasi lain dengan meneruskan Intent ke sendBroadcast() atau sendOrderedBroadcast().

Selebihnya dari halaman ini menjelaskan cara intent bekerja dan cara menggunakannya. Untuk informasi terkait, lihat Berinteraksi dengan Aplikasi Lain dan Berbagi Konten.

Tipe intent

Ada dua tipe intent:

  • Intent eksplisit menentukan komponen aplikasi mana yang akan memenuhi intent, dengan menentukan ComponentName lengkap. Anda akan biasanya menggunakan intent eksplisit untuk memulai komponen dalam aplikasi Anda sendiri, karena Anda mengetahui nama class aktivitas atau layanan yang ingin dimulai. Sebagai misalnya, Anda dapat memulai aktivitas baru dalam aplikasi sebagai respons terhadap tindakan pengguna, atau memulai layanan untuk mengunduh file di latar belakang.
  • Intent implisit tidak menyebutkan komponen tertentu, melainkan mendeklarasikan tindakan umum dijalankan, yang memungkinkan komponen dari aplikasi lain untuk menanganinya. Misalnya, jika Anda ingin memperlihatkan kepada pengguna sebuah lokasi di peta, Anda bisa menggunakan intent implisit untuk meminta aplikasi yang menunjukkan lokasi tertentu pada peta.

Gambar 1 menunjukkan cara intent digunakan saat memulai aktivitas. Jika objek Intent memberi nama komponen aktivitas tertentu secara eksplisit, sistem akan segera memulai komponen tersebut.

Gambar 1. Cara intent implisit disampaikan melalui sistem untuk memulai aktivitas lain: [1] Aktivitas A membuat Intent dengan deskripsi tindakan dan meneruskannya ke startActivity(). [2] Sistem Android menelusuri semua aplikasi untuk menemukan filter intent yang cocok dengan intent. Jika kecocokan ditemukan, [3] sistem memulai aktivitas pencocokan (Aktivitas B) dengan memanggil metode onCreate() dan meneruskannya Intent.

Jika Anda menggunakan intent implisit, sistem Android akan menemukan komponen yang sesuai untuk memulai dengan membandingkan konten intent dengan filter intent yang dideklarasikan dalam file manifes aplikasi lain di perangkat seluler. Jika intent cocok dengan filter intent, sistem akan memulai komponen tersebut dan mengirimkannya objek Intent. Jika beberapa filter intent kompatibel, sistem akan menampilkan dialog sehingga pengguna dapat memilih aplikasi yang akan digunakan.

Filter intent adalah ekspresi dalam file manifes aplikasi yang menetapkan jenis intent yang ingin diterima komponen. Misalnya, dengan mendeklarasikan filter intent untuk aktivitas, Anda memungkinkan aplikasi lain untuk langsung memulai aktivitas Anda dengan intent tertentu. Demikian pula, jika Anda tidak mendeklarasikan filter intent untuk suatu aktivitas, filter tersebut dapat dimulai hanya dengan maksud eksplisit.

Perhatian: Untuk memastikan aplikasi Anda aman, selalu gunakan intent eksplisit saat memulai Service dan jangan deklarasikan filter intent untuk layanan Anda. Menggunakan intent implisit untuk memulai layanan dapat membahayakan keamanan, karena Anda tidak dapat memastikan layanan yang akan merespons intent tersebut, dan pengguna tidak dapat melihat layanan yang dimulai. Mulai dari Android 5.0 (API level 21), sistem akan menampilkan pengecualian jika Anda memanggil bindService() dengan intent implisit.

Membuat intent

Objek Intent membawa informasi yang digunakan sistem Android untuk menentukan komponen mana yang akan dimulai (seperti nama atau komponen komponen yang tepat kategori yang seharusnya menerima intent), ditambah informasi yang digunakan komponen penerima dalam agar dapat melakukan tindakan dengan benar (seperti tindakan yang harus diambil dan data untuk ditindaklanjuti).

Informasi utama yang dimuat dalam Intent adalah sebagai berikut:

Nama komponen
Nama komponen yang akan memulai.

Ini opsional, tetapi merupakan bagian informasi penting yang membuat intent eksplisit, yang berarti intent hanya boleh dikirim ke komponen aplikasi yang ditentukan oleh nama komponen. Tanpa nama komponen, intent bersifat implisit dan sistem memutuskan komponen mana yang harus menerima intent berdasarkan informasi intent lainnya (seperti tindakan, data, dan kategori—dijelaskan di bawah). Jika Anda perlu memulai di aplikasi, Anda harus menetapkan nama komponennya.

Catatan: Saat memulai Service, selalu tentukan nama komponen. Jika tidak, Anda tidak dapat memastikan layanan yang akan merespons intent tersebut, dan pengguna tidak dapat melihat layanan mana yang dimulai.

Kolom Intent ini adalah ComponentName, yang dapat Anda tentukan menggunakan nama kelas yang memenuhi syarat dari komponen target, termasuk nama paket aplikasi, misalnya, com.example.ExampleActivity. Anda dapat menetapkan nama komponen dengan setComponent(), setClass(), setClassName(), atau dengan konstruktor Intent.

Tindakan
String yang menentukan tindakan umum yang akan dilakukan (seperti lihat atau pilih).

Dalam kasus intent siaran, hal ini merupakan tindakan yang terjadi dan sedang dilaporkan. Sebagian besar tindakan menentukan bagaimana seluruh intent disusun—terutama informasi yang terkandung dalam data dan tambahan.

Anda dapat menentukan tindakan sendiri yang akan digunakan oleh intent dalam aplikasi (atau digunakan oleh aplikasi lain untuk memanggil komponen dalam aplikasi), tetapi Anda biasanya menentukan konstanta tindakan yang ditentukan oleh class Intent atau class framework lainnya. Berikut beberapa tindakan umum untuk memulai aktivitas:

ACTION_VIEW
Gunakan tindakan ini dalam intent dengan startActivity() jika Anda memiliki beberapa informasi yang aktivitas dapat ditampilkan kepada pengguna, seperti foto untuk dilihat di aplikasi galeri, atau alamat untuk lihat di aplikasi peta.
ACTION_SEND
Juga dikenal sebagai intent share, Anda harus menggunakannya dalam intent dengan startActivity() jika Anda memiliki beberapa data yang dapat digunakan pengguna dibagikan melalui aplikasi lain, seperti aplikasi email atau aplikasi berbagi ke media sosial.

Lihat referensi class Intent untuk mengetahui informasi selengkapnya yang mendefinisikan tindakan generik. Tindakan lainnya ditentukan di tempat lain dalam framework Android, seperti di Settings untuk tindakan yang membuka layar tertentu di aplikasi {i>Settings<i} sistem.

Anda dapat menentukan tindakan untuk intent dengan setAction() atau dengan konstruktor Intent.

Jika Anda menentukan tindakan Anda sendiri, pastikan untuk menyertakan nama paket aplikasi sebagai awalan, seperti yang ditunjukkan pada contoh berikut:

KotlinJava
const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
Data
URI (objek Uri) yang mereferensikan data untuk diproses dan/atau jenis MIME data tersebut. Jenis data yang disediakan umumnya didikte oleh tindakan intent. Misalnya, jika tindakannya adalah ACTION_EDIT, data harus berisi URI dokumen yang akan diedit.

Saat membuat intent, maka penting untuk menentukan jenis data (jenis MIME) selain URI-nya. Misalnya, aktivitas yang dapat menampilkan gambar mungkin tidak akan dapat memutar file audio, meskipun format URI-nya mungkin serupa. Menentukan jenis data MIME Anda membantu sistem Android menemukan komponen terbaik untuk menerima intent Anda. Namun, jenis MIME terkadang dapat disimpulkan dari URI—terutama jika data adalah URI content:. URI content: menunjukkan data berada di perangkat dan dikontrol oleh ContentProvider, yang membuat jenis MIME data terlihat oleh sistem.

Untuk menyetel hanya URI data, panggil setData(). Untuk menyetel hanya jenis MIME, panggil setType(). Jika perlu, Anda dapat menetapkan keduanya secara eksplisit dengan setDataAndType().

Perhatian: Jika ingin menetapkan URI dan jenis MIME, jangan memanggil setData() dan setType() karena keduanya masing-masing membatalkan nilai satu sama lain. Selalu gunakan setDataAndType() untuk menetapkan URI dan jenis MIME.

Kategori
String yang berisi informasi tambahan tentang jenis komponen yang harus menangani intent. Keterangan kategori dalam jumlah berapa pun dapat dimasukkan dalam intent, tetapi sebagian besar intent tidak memerlukan kategori. Berikut beberapa kategori umum:
CATEGORY_BROWSABLE
Aktivitas target memungkinkan dirinya dimulai oleh browser web untuk menampilkan data yang direferensikan oleh link, misalnya gambar atau pesan email.
CATEGORY_LAUNCHER
Aktivitas tersebut adalah aktivitas awal dari sebuah tugas dan dicantumkan dalam peluncur aplikasi sistem.

Lihat deskripsi class Intent untuk mengetahui daftar lengkap kategori.

Anda dapat menentukan kategori dengan addCategory().

Properti yang tercantum di atas (nama komponen, tindakan, data, dan kategori) mewakili karakteristik yang mendefinisikan intent. Dengan membaca properti ini, sistem Android mampu memutuskan komponen aplikasi mana yang harus dimulai. Namun, intent dapat membawa informasi tambahan yang tidak memengaruhi cara intent ditetapkan pada komponen aplikasi. Intent juga bisa menyediakan informasi berikut:

Tambahan
Pasangan nilai kunci yang membawa informasi tambahan yang diperlukan untuk mencapai tindakan yang diminta. Seperti halnya beberapa tindakan menggunakan jenis tertentu URI data, beberapa tindakan juga menggunakan tambahan tertentu.

Anda dapat menambahkan data tambahan dengan berbagai metode putExtra(), masing-masing menerima dua parameter: nama kunci dan nilai. Anda juga dapat membuat objek Bundle dengan semua data tambahan, lalu menyisipkan Bundle di Intent dengan putExtras().

Misalnya, saat membuat intent untuk mengirim email dengan ACTION_SEND, Anda dapat menentukan penerima kepada dengan kunci EXTRA_EMAIL, dan menentukan subjek dengan kunci EXTRA_SUBJECT.

Class Intent menentukan banyak konstanta EXTRA_* untuk jenis data standar. Jika perlu mendeklarasikan kunci ekstra Anda sendiri (untuk intent yang diterima aplikasi Anda), pastikan untuk menyertakan nama paket aplikasi sebagai awalan, seperti yang ditunjukkan dalam contoh berikut:

KotlinJava
const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";

Perhatian: Jangan gunakan data Parcelable atau Serializable saat mengirim intent yang Anda harapkan diterima aplikasi lain. Jika aplikasi mencoba mengakses data dalam objek Bundle, tetapi tidak memiliki akses ke class yang dipaketkan atau diserialisasi, sistem akan memunculkan RuntimeException.

Flag
Tanda ditentukan di class Intent yang berfungsi sebagai metadata untuk intent. Flag tersebut dapat menginstruksikan sistem Android cara meluncurkan aktivitas (misalnya, tugas aktivitas harus menjadi bagian dan cara menanganinya setelah diluncurkan (misalnya, apakah ID tersebut ada dalam daftar lainnya).

Untuk informasi selengkapnya, lihat metode setFlags().

Contoh intent eksplisit

Intent eksplisit adalah intent yang Anda gunakan untuk meluncurkan komponen aplikasi tertentu, seperti aktivitas atau layanan tertentu dalam aplikasi Anda. Untuk membuat intent eksplisit, tentukan nama komponen untuk objek Intent—semua properti intent lainnya bersifat opsional.

Misalnya, jika Anda membuat layanan di aplikasi Anda, bernama DownloadService, yang dirancang untuk mendownload file dari web, Anda dapat memulainya dengan kode berikut:

KotlinJava
// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
val downloadIntent = Intent(this, DownloadService::class.java).apply {
    data = Uri.parse(fileUrl)
}
startService(downloadIntent)
// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);

Konstruktor Intent(Context, Class) menyediakan Context aplikasi dan objek Class komponen. Dengan demikian, intent ini secara eksplisit memulai class DownloadService dalam aplikasi.

Untuk informasi selengkapnya tentang cara membangun dan memulai layanan, lihat dokumentasi Panduan Layanan.

Contoh intent implisit

Intent implisit menentukan tindakan yang dapat memanggil aplikasi pada perangkat yang mampu melakukan tindakan. Menggunakan intent implisit berguna jika aplikasi Anda tidak dapat melakukan tindakan, tetapi aplikasi lain mungkin dapat melakukannya dan Anda ingin pengguna memilih aplikasi mana yang akan digunakan.

Misalnya, jika Anda memiliki konten yang ingin dibagikan pengguna kepada orang lain, buat intent dengan tindakan ACTION_SEND dan tambahkan tambahan yang menentukan konten yang akan dibagikan. Saat Anda memanggil startActivity() dengan intent tersebut, pengguna dapat memilih aplikasi yang akan digunakan untuk membagikan konten.

KotlinJava
// Create the text message with a string.
val sendIntent = Intent().apply {
    action = Intent.ACTION_SEND
    putExtra(Intent.EXTRA_TEXT, textMessage)
    type = "text/plain"
}

// Try to invoke the intent.
try {
    startActivity(sendIntent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}
// Create the text message with a string.
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");

// Try to invoke the intent.
try {
    startActivity(sendIntent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

Saat startActivity() dipanggil, sistem akan memeriksa semua aplikasi yang terinstal untuk menentukan aplikasi mana yang dapat menangani intent jenis ini (intent dengan tindakan ACTION_SEND dan yang membawa data "text/plain"). Jika hanya ada satu aplikasi yang dapat menanganinya, aplikasi tersebut akan langsung terbuka dan diberi intent. Jika tidak ada aplikasi lain yang dapat menanganinya, aplikasi Anda dapat menangkap ActivityNotFoundException yang terjadi. Jika beberapa aktivitas menerima intent, sistem menampilkan dialog seperti yang ditampilkan dalam Gambar 2, sehingga pengguna dapat memilih aplikasi yang akan digunakan.

Informasi selengkapnya tentang meluncurkan aplikasi lain juga disediakan dalam panduan mengirim pengguna ke aplikasi lain.

Gambar 2. Dialog pilihan.

Memaksakan pemilih aplikasi

Jika ada lebih dari satu aplikasi yang merespons intent implisit Anda, pengguna dapat memilih aplikasi mana yang akan digunakan dan menjadikan aplikasi tersebut sebagai pilihan default untuk tindakan. Kemampuan untuk memilih nilai default sangat membantu saat melakukan tindakan yang berkaitan dengan mungkin ingin menggunakan aplikasi yang sama setiap saat, seperti saat membuka halaman web (pengguna sering kali hanya memilih satu browser web).

Akan tetapi, jika beberapa aplikasi bisa merespons intent tersebut dan pengguna mungkin ingin menggunakan aplikasi setiap kali, Anda harus secara eksplisit menampilkan dialog pilihan. Dialog pilihan menanyakan pengguna untuk memilih aplikasi yang akan digunakan untuk tindakan (pengguna tidak dapat memilih aplikasi default untuk tindakan). Misalnya, saat aplikasi Anda melakukan "berbagi" dengan tindakan ACTION_SEND, pengguna mungkin ingin berbagi menggunakan aplikasi lain, bergantung pada situasi mereka saat ini, jadi Anda harus selalu menggunakan dialog pemilih, seperti yang ditampilkan dalam Gambar 2.

Untuk menampilkan pemilih, buat Intent menggunakan createChooser() dan teruskan ke startActivity(), seperti yang ditunjukkan pada contoh berikut. Contoh ini menampilkan dialog berisi daftar aplikasi yang merespons intent yang diteruskan ke metode createChooser() dan menggunakan teks yang disediakan sebagai judul dialog.

KotlinJava
val sendIntent = Intent(Intent.ACTION_SEND)
...

// Always use string resources for UI text.
// This says something like "Share this photo with"
val title: String = resources.getString(R.string.chooser_title)
// Create intent to show the chooser dialog
val chooser: Intent = Intent.createChooser(sendIntent, title)

// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(packageManager) != null) {
    startActivity(chooser)
}
Intent sendIntent = new Intent(Intent.ACTION_SEND);
...

// Always use string resources for UI text.
// This says something like "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
// Create intent to show the chooser dialog
Intent chooser = Intent.createChooser(sendIntent, title);

// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

Mendeteksi peluncuran intent yang tidak aman

Aplikasi Anda mungkin meluncurkan intent untuk beralih di antara komponen di dalam aplikasi, atau menjalankan tindakan atas nama aplikasi lain. Untuk meningkatkan keamanan platform, Android 12 (API level 31) dan yang lebih tinggi menyediakan fitur proses debug yang memperingatkan Anda jika aplikasi melakukan peluncuran intent yang tidak aman. Misalnya, aplikasi Anda mungkin melakukan peluncuran intent bertingkat yang tidak aman, yaitu intent yang diteruskan sebagai tambahan dalam intent lain.

Jika aplikasi Anda melakukan kedua tindakan berikut, sistem akan mendeteksi aktivitas peluncuran intent, dan pelanggaran StrictMode terjadi:

  1. Aplikasi Anda memisahkan intent bertingkat dari tambahan intent yang dikirim.
  2. Aplikasi Anda akan segera memulai komponen aplikasi menggunakan intent bertingkat tersebut, seperti meneruskan intent ke startActivity(), startService(), atau bindService().

Untuk detail selengkapnya tentang cara mengidentifikasi situasi ini dan membuat perubahan pada aplikasi Anda, baca postingan blog tentang Android Nesting Intent di Medium.

Memeriksa peluncuran intent yang tidak aman

Untuk memeriksa peluncuran intent yang tidak aman di aplikasi Anda, panggil detectUnsafeIntentLaunch() saat Anda mengonfigurasi VmPolicy, seperti yang ditunjukkan dalam cuplikan kode berikut. Jika aplikasi Anda mendeteksi adanya pelanggaran StrictMode, Anda mungkin ingin menghentikan eksekusi aplikasi untuk melindungi informasi yang berpotensi sensitif.

KotlinJava
fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build())
}
protected void onCreate() {
    StrictMode.setVmPolicy(new VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build());
}

Menggunakan intent dengan lebih bertanggung jawab

Untuk meminimalkan kemungkinan peluncuran intent yang tidak aman, dan pelanggaran StrictMode, ikuti praktik terbaik berikut.

Salin saja tambahan esensial ke dalam intent dan lakukan pembersihan dan validasi yang diperlukan. Aplikasi Anda mungkin akan menyalin tambahan dari satu intent ke intent lain yang digunakan untuk meluncurkan komponen baru. Hal ini terjadi saat aplikasi Anda memanggil putExtras(Intent) atau putExtras(Bundle). Jika aplikasi Anda melakukan salah satu operasi ini, salin saja tambahan yang diharapkan komponen penerima. Jika intent lain (yang menerima salinan) meluncurkan komponen yang tidak diekspor, bersihkan dan validasikan tambahan sebelum menyalinnya ke intent yang meluncurkan komponen.

Jangan mengekspor komponen aplikasi Anda secara tidak perlu. Misalnya, jika Anda bermaksud meluncurkan komponen aplikasi menggunakan intent tersarang internal, yang mengatur atribut android:exported komponen ke false.

Gunakan PendingIntent, bukan intent bertingkat. Dengan begitu, saat aplikasi lain mengurai paket PendingIntent-nya yang berisi Intent, aplikasi lain dapat meluncurkan PendingIntent menggunakan identitas aplikasi Anda. Konfigurasi ini memungkinkan aplikasi lain diluncurkan dengan aman komponen apa pun, termasuk komponen yang tidak diekspor, dalam aplikasi Anda.

Diagram pada gambar 2 menunjukkan cara sistem meneruskan kontrol dari aplikasi (klien) Anda ke aplikasi (layanan) lain, dan kembali ke aplikasi Anda:

  1. Aplikasi Anda membuat intent yang memanggil aktivitas di aplikasi lain. Di dalam intent tersebut, tambahkan objek PendingIntent sebagai tambahan. Intent tertunda ini memanggil komponen di aplikasi Anda; komponen ini tidak diekspor.
  2. Setelah menerima intent aplikasi Anda, aplikasi lain akan mengekstrak Objek PendingIntent.
  3. Aplikasi lain memanggil metode send() pada objek PendingIntent.
  4. Setelah mengembalikan kontrol ke aplikasi Anda, sistem akan memanggil metode menggunakan konteks aplikasi Anda.

Gambar 2. Diagram komunikasi antar-aplikasi saat menggunakan metode bertingkat intent.

Menerima intent implisit

Untuk mengiklankan intent implisit mana yang dapat diterima aplikasi Anda, deklarasikan satu atau beberapa filter intent untuk setiap komponen aplikasi dengan <intent-filter> dalam file manifes. Setiap filter intent menentukan jenis intent yang diterimanya berdasarkan tindakan, data, dan kategori intent. Sistem akan mengirim intent implisit ke komponen aplikasi Anda hanya jika intent tersebut bisa diteruskan melalui salah satu filter intent Anda.

Catatan: Intent eksplisit selalu dikirim ke targetnya, apa pun filter intent yang dideklarasikan komponen.

Komponen aplikasi harus mendeklarasikan filter terpisah untuk setiap tugas unik yang dapat dilakukannya. Misalnya, satu aktivitas dalam aplikasi galeri gambar dapat memiliki dua filter: satu filter untuk melihat gambar, dan filter lainnya untuk mengedit gambar. Saat aktivitas dimulai, aktivitas akan memeriksa Intent dan menentukan cara berperilaku berdasarkan informasi dalam Intent (misalnya menampilkan kontrol editor atau tidak).

Setiap filter intent ditentukan oleh <intent-filter> di file manifes aplikasi, yang disarangkan dalam komponen aplikasi terkait (seperti sebagai <activity> ).

Di setiap komponen aplikasi yang menyertakan elemen <intent-filter>, tetapkan nilai untuk android:exported secara eksplisit. Atribut ini menunjukkan apakah komponen aplikasi dapat diakses oleh aplikasi lain. Di beberapa situasi, seperti aktivitas yang filter intent-nya menyertakan LAUNCHER kategori, sebaiknya tetapkan atribut ini ke true. Jika tidak, atribut ini akan lebih aman jika ditetapkan ke false.

Peringatan: Jika aktivitas, layanan, atau penerima siaran di aplikasi Anda menggunakan filter intent dan tidak menetapkan nilai untuk android:exported secara eksplisit, aplikasi Anda tidak dapat diinstal di perangkat yang menjalankan Android 12 atau yang lebih tinggi.

Di dalam <intent-filter>, Anda dapat menentukan jenis intent yang akan diterima menggunakan satu atau beberapa dari tiga elemen ini:

<action>
Mendeklarasikan tindakan intent yang diterima dalam atribut name. Nilai harus berupa nilai string literal dari tindakan, bukan konstanta class.
<data>
Mendeklarasikan jenis data yang diterima menggunakan satu atau beberapa atribut yang menentukan berbagai aspek URI data (scheme, host, port, path) dan jenis MIME.
<category>
Mendeklarasikan kategori intent yang diterima, dalam atribut name. Nilai harus berupa nilai string literal dari tindakan, bukan konstanta class.

Catatan: Untuk menerima intent implisit, Anda harus menyertakan kategori CATEGORY_DEFAULT dalam filter intent. Metode startActivity() dan startActivityForResult() memperlakukan semua intent seolah-olah mereka mendeklarasikan kategori CATEGORY_DEFAULT. Jika Anda tidak mendeklarasikan kategori ini dalam filter intent, tidak ada intent implisit yang akan dicocokkan ke aktivitas Anda.

Misalnya, berikut adalah deklarasi aktivitas dengan filter intent untuk menerima intent ACTION_SEND jika jenis datanya berupa teks:

<activity android:name="ShareActivity" android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

Anda dapat membuat filter yang menyertakan lebih dari satu instance <action>, <data>, atau <category>. Jika Anda melakukannya, Anda harus yakin bahwa komponennya dapat menangani semua kombinasi dari elemen-elemen filter tersebut.

Bila Anda ingin menangani beragam jenis intent, namun hanya dalam kombinasi tertentu tindakan, data, dan jenis kategori, maka Anda perlu membuat beberapa filter intent.

Intent implisit diuji terhadap filter dengan membandingkan intent dengan masing-masing tiga elemen. Agar dikirim ke komponen, intent harus lolos ketiga pengujian tersebut. Jika gagal cocok dengan salah satunya, sistem Android tidak akan mengirimkan intent ke komponen. Namun, karena sebuah komponen mungkin memiliki beberapa filter intent, intent yang tidak melalui salah satu filter komponen mungkin saja lulus di filter lainnya. Informasi selengkapnya tentang cara sistem me-resolve intent disediakan di bagian di bawah tentang Resolusi Intent.

Perhatian: Menggunakan filter intent bukanlah cara yang aman untuk mencegah aplikasi lain dimulai komponen Anda. Meskipun filter intent membatasi komponen agar hanya merespons jenis intent implisit tertentu, aplikasi lain berpotensi memulai komponen aplikasi Anda dengan menggunakan intent eksplisit jika developernya menentukan nama komponen Anda. Jika hanya aplikasi Anda sendiri yang dapat memulai salah satu komponen Anda, tidak mendeklarasikan filter intent dalam manifes Anda. Sebagai gantinya, tetapkan atribut exported ke "false" untuk komponen tersebut.

Demikian pula, untuk menghindari secara tidak sengaja menjalankan Service aplikasi yang berbeda, selalu gunakan intent eksplisit untuk memulai layanan Anda sendiri.

Catatan: Untuk semua aktivitas, Anda harus mendeklarasikan filter intent di file manifes. Namun, filter untuk penerima siaran dapat didaftarkan secara dinamis dengan memanggil registerReceiver(). Kemudian, Anda dapat membatalkan pendaftaran penerima dengan unregisterReceiver(). Melakukan hal ini memungkinkan aplikasi Anda untuk mendengarkan siaran tertentu hanya selama jangka waktu tertentu saat aplikasi sedang berjalan.

Contoh filter

Untuk mendemonstrasikan beberapa perilaku filter intent, berikut adalah contoh dari file manifes aplikasi berbagi jejaring sosial:

<activity android:name="MainActivity" android:exported="true">
    <!-- This activity is the main entry, should appear in app launcher -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name="ShareActivity" android:exported="false">
    <!-- This activity handles "SEND" actions with text data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
    <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <action android:name="android.intent.action.SEND_MULTIPLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="application/vnd.google.panorama360+jpg"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="video/*"/>
    </intent-filter>
</activity>

Aktivitas pertama, MainActivity, adalah titik masuk utama aplikasi—aktivitas yang akan terbuka saat pengguna pertama kali meluncurkan aplikasi dengan ikon peluncur:

  • Tindakan ACTION_MAIN menunjukkan bahwa ini adalah titik entri utama dan tidak mengharapkan data intent apa pun.
  • Kategori CATEGORY_LAUNCHER menunjukkan bahwa aktivitas harus ditempatkan dalam peluncur aplikasi sistem. Jika elemen <activity> tidak menentukan ikon dengan icon, sistem akan menggunakan ikon dari elemen <application>.

Keduanya harus dipasangkan bersama agar aktivitas muncul dalam peluncur aplikasi.

Aktivitas kedua, ShareActivity, dimaksudkan untuk memfasilitasi berbagi konten teks dan media. Meskipun pengguna mungkin memasuki aktivitas ini dengan membukanya dari MainActivity, mereka juga dapat memasukkan ShareActivity langsung dari aplikasi lain yang mengeluarkan intent implisit yang cocok dengan salah satu dari dua filter intent.

Catatan: Jenis MIME, application/vnd.google.panorama360+jpg, adalah jenis data khusus yang menentukan foto panorama, yang dapat Anda tangani dengan Google panoramic API.

Mencocokkan intent dengan filter intent aplikasi lain

Jika aplikasi lain menargetkan Android 13 (API level 33) atau yang lebih tinggi, aplikasi tersebut dapat menangani intent aplikasi Anda hanya jika intent Anda cocok dengan tindakan dan kategori elemen <intent-filter> di aplikasi lain tersebut. Jika sistem tidak menemukan kecocokan, sistem akan menampilkan ActivityNotFoundException. Aplikasi pengirim harus menangani pengecualian ini.

Demikian pula, jika Anda mengupdate aplikasi agar menargetkan Android 13 atau yang lebih tinggi, semua intent yang berasal dari aplikasi eksternal akan dikirim ke komponen aplikasi yang diekspor hanya jika intent tersebut cocok dengan tindakan dan kategori elemen <intent-filter> yang dideklarasikan aplikasi Anda. Perilaku ini terjadi terlepas dari versi SDK target aplikasi pengirim.

Dalam kasus berikut, pencocokan intent tidak diterapkan:

  • Intent yang dikirim ke komponen yang tidak mendeklarasikan filter intent apa pun.
  • Intent yang berasal dari dalam aplikasi yang sama.
  • Intent yang berasal dari sistem; yaitu, intent yang dikirim dari "UID sistem" (uid=1000). Aplikasi sistem mencakup system_server dan aplikasi yang menyetel android:sharedUserId ke android.uid.system.
  • Intent yang berasal dari root.

Pelajari pencocokan intent lebih lanjut.

Menggunakan intent tertunda

Objek PendingIntent adalah wrapper di sekitar objek Intent. Tujuan utama PendingIntent adalah untuk memberikan izin ke aplikasi asing untuk menggunakan Intent yang dimuat seolah-olah dieksekusi dari proses aplikasi Anda sendiri.

Kasus penggunaan utama untuk intent tertunda mencakup hal berikut:

  • Mendeklarasikan intent untuk dijalankan saat pengguna melakukan tindakan dengan Notification (NotificationManager sistem Android mengeksekusi Intent).
  • Mendeklarasikan intent untuk dieksekusi saat pengguna melakukan tindakan dengan Widget Aplikasi (aplikasi Layar utama mengeksekusi Intent).
  • Mendeklarasikan intent untuk dijalankan pada masa mendatang yang telah ditentukan (AlarmManager sistem Android akan menjalankan Intent).

Sama seperti setiap objek Intent yang dirancang untuk ditangani oleh jenis komponen aplikasi (baik Activity, Service, atau sebuah BroadcastReceiver), jadi PendingIntent harus dibuat dengan pertimbangan yang sama. Saat menggunakan intent yang tertunda, aplikasi Anda tidak mengeksekusi intent dengan panggilan seperti startActivity(). Sebagai gantinya, Anda harus mendeklarasikan jenis komponen yang dimaksud saat membuat PendingIntent dengan memanggil metode kreator masing-masing:

Kecuali aplikasi Anda menerima intent yang tertunda dari aplikasi lain, metode di atas untuk membuat PendingIntent mungkin satu-satunya metode PendingIntent yang akan Anda perlukan.

Setiap metode mengambil Context aplikasi saat ini, Intent yang ingin Anda gabungkan, dan satu atau beberapa flag yang menentukan cara penggunaan intent (misalnya apakah intent dapat digunakan lebih dari sekali).

Untuk informasi selengkapnya tentang penggunaan intent yang tertunda, lihat dokumentasi untuk masing-masing intent sesuai kasus penggunaan masing-masing, seperti dalam Notifikasi dan App Widgets API.

Menentukan mutabilitas

Jika aplikasi Anda menargetkan Android 12 atau yang lebih tinggi, Anda harus menentukan mutabilitas setiap objek PendingIntent yang dibuat oleh aplikasi Anda. Untuk menyatakan bahwa objek PendingIntent tertentu dapat diubah atau tidak, gunakan tanda PendingIntent.FLAG_MUTABLE atau PendingIntent.FLAG_IMMUTABLE.

Jika aplikasi Anda mencoba membuat objek PendingIntent tanpa menetapkan penanda mutabilitas, sistem akan menampilkan IllegalArgumentException, dan pesan berikut akan muncul di Logcat:

PACKAGE_NAME: Targeting S+ (version 31 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.

Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.

Membuat intent tertunda yang tidak dapat diubah jika memungkinkan

Pada umumnya, aplikasi Anda harus membuat objek PendingIntent yang tidak dapat diubah, seperti yang ditampilkan dalam cuplikan kode berikut. Jika objek PendingIntent tidak dapat diubah, aplikasi lain tidak dapat mengubah intent untuk menyesuaikan hasil pemanggilan intent.

KotlinJava
val pendingIntent = PendingIntent.getActivity(applicationContext,
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE)
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE);

Namun, kasus penggunaan tertentu memerlukan objek PendingIntent yang dapat diubah:

  • Mendukung tindakan balasan langsung di notifikasi. Tujuan balasan langsung memerlukan perubahan pada data klip di objek PendingIntent yang terkait dengan balasan. Biasanya, Anda meminta perubahan ini dengan meneruskan FILL_IN_CLIP_DATA sebagai flag ke fillIn() .
  • Mengaitkan notifikasi dengan framework Android Auto, menggunakan instance CarAppExtender.
  • Menempatkan percakapan dalam gelembung menggunakan instance dari PendingIntent. Objek PendingIntent yang dapat diubah memungkinkan sistem menerapkan tanda yang benar, seperti FLAG_ACTIVITY_MULTIPLE_TASK dan FLAG_ACTIVITY_NEW_DOCUMENT.
  • Meminta informasi lokasi perangkat dengan memanggil requestLocationUpdates() atau API serupa. Objek PendingIntent yang dapat berubah memungkinkan sistem menambahkan tambahan intent yang mewakili peristiwa siklus proses lokasi. Peristiwa ini mencakup perubahan lokasi dan penyedia yang tersedia.
  • Menjadwalkan alarm menggunakan AlarmManager. Objek PendingIntent yang dapat diubah memungkinkan sistem menambahkan EXTRA_ALARM_COUNT intent tambahan. Tambahan ini mewakili berapa kali alarm berulang telah dipicu. Dengan menyertakan tambahan ini, intent dapat memberi tahu aplikasi secara akurat apakah alarm berulang dipicu beberapa kali, seperti saat perangkat dalam mode tidur.

Jika aplikasi Anda membuat objek PendingIntent yang dapat berubah, kami sangat direkomendasikan Anda menggunakan intent eksplisit dan mengisi ComponentName Dengan begitu, setiap kali aplikasi lain memanggil PendingIntent dan meneruskan kontrol kembali ke aplikasi Anda, komponen yang sama di aplikasi Anda akan selalu dimulai.

Menggunakan intent eksplisit dalam intent yang tertunda

Untuk mendefinisikan dengan lebih baik cara aplikasi lain menggunakan intent tertunda aplikasi Anda, selalu menggabungkan intent yang tertunda dengan intent eksplisit. Untuk membantu mengikuti praktik terbaik ini, lakukan hal berikut:

  1. Pastikan kolom tindakan, paket, dan komponen intent dasar telah ditetapkan.
  2. Gunakan FLAG_IMMUTABLE, yang ditambahkan di Android 6.0 (API level 23), untuk membuat intent yang tertunda. Tanda ini mencegah aplikasi yang menerima PendingIntent agar tidak mengisi properti yang kosong. Jika minSdkVersion aplikasi Anda 22 atau lebih rendah, Anda dapat memberikan keamanan dan kompatibilitas secara bersamaan menggunakan kode berikut:

    if (Build.VERSION.SDK_INT >= 23) {
      // Create a PendingIntent using FLAG_IMMUTABLE.
    } else {
      // Existing code that creates a PendingIntent.
    }

Resolusi intent

Saat sistem menerima intent implisit untuk memulai aktivitas, sistem akan menelusuri aktivitas terbaik untuk intent tersebut dengan membandingkannya dengan filter intent berdasarkan tiga aspek:

  • Beraksi.
  • Data (baik URI maupun tipe data)
  • Kategori.

Bagian berikut menjelaskan cara pencocokan intent dengan komponen yang sesuai sehubungan dengan cara pendeklarasian intent dalam file manifes aplikasi.

Pengujian tindakan

Untuk menentukan tindakan intent yang diterima, filter intent dapat mendeklarasikan nol atau beberapa elemen <action>, seperti yang ditunjukkan pada contoh berikut:

<intent-filter>
    <action android:name="android.intent.action.EDIT" />
    <action android:name="android.intent.action.VIEW" />
    ...
</intent-filter>

Untuk meneruskan filter ini, tindakan yang ditentukan dalam Intent harus cocok dengan salah satu tindakan yang tercantum dalam filter.

Jika filter tidak mencantumkan tindakan apa pun, maka tidak ada intent yang dicocokkan, jadi semua intent gagal dalam pengujian. Namun, jika Intent tidak menentukan tindakan, Intent akan lulus pengujian selama filter berisi setidaknya satu tindakan.

Pengujian kategori

Untuk menentukan kategori intent yang diterima, filter intent dapat mendeklarasikan nol atau beberapa elemen <category>, seperti yang ditunjukkan pada contoh berikut:

<intent-filter>
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    ...
</intent-filter>

Agar intent lulus pengujian kategori, setiap kategori dalam Intent harus cocok dengan kategori dalam filter. Kebalikannya tidak diperlukan—filter intent dapat mendeklarasikan lebih banyak kategori daripada yang ditentukan dalam Intent dan Intent tetap lolos. Oleh karena itu, intent tanpa kategori selalu lolos pengujian ini, kategori apa pun yang dideklarasikan dalam filter.

Catatan: Android secara otomatis menerapkan kategori CATEGORY_DEFAULT ke semua intent implisit yang diteruskan ke startActivity() dan startActivityForResult(). Jika ingin aktivitas Anda menerima intent implisit, aktivitas itu harus menyertakan kategori untuk "android.intent.category.DEFAULT" dalam filter intent-nya, seperti yang ditunjukkan dalam contoh <intent-filter> sebelumnya.

Pengujian data

Untuk menentukan data intent yang diterima, filter intent dapat mendeklarasikan nol atau beberapa elemen <data>, seperti yang ditunjukkan pada contoh berikut:

<intent-filter>
    <data android:mimeType="video/mpeg" android:scheme="http" ... />
    <data android:mimeType="audio/mpeg" android:scheme="http" ... />
    ...
</intent-filter>

Setiap <data> dapat menentukan struktur URI dan jenis data (jenis media MIME). Setiap bagian URI merupakan bagian atribut: scheme, host, port, dan path:

<scheme>://<host>:<port>/<path>

Contoh berikut menampilkan nilai yang mungkin untuk atribut ini:

content://com.example.project:200/folder/subfolder/etc

Dalam URI ini, skemanya adalah content, host-nya adalah com.example.project, port-nya adalah 200, dan jalurnya adalah folder/subfolder/etc.

Setiap atribut ini bersifat opsional dalam elemen <data>, tetapi terdapat dependensi linier:

  • Jika skema tidak ditetapkan, host akan diabaikan.
  • Jika host tidak ditetapkan, porta akan diabaikan.
  • Jika skema dan host tidak ditetapkan, jalur akan diabaikan.

Jika URI dalam intent dibandingkan dengan spesifikasi URI dalam filter, pembandingannya hanya dengan bagian URI yang disertakan dalam filter. Contoh:

  • Jika sebuah filter menetapkan hanya satu skema, semua URI dengan skema tersebut akan cocok {i>filter<i}.
  • Jika sebuah filter menetapkan satu skema dan satu otoritas namun tidak ada jalur, semua URI dengan skema dan otoritas yang sama dapat melewati filter, terlepas dari jalur mereka.
  • Jika sebuah filter menetapkan skema, otoritas, dan jalur, hanya URI dengan skema yang sama, {i>authority<i}, dan jalur melewati filter.

Catatan: Spesifikasi jalur dapat berisi tanda bintang (*) karakter pengganti untuk hanya mencocokkan nama jalur secara parsial.

Pengujian data membandingkan URI maupun tipe MIME dalam intent dengan URI dan tipe MIME yang ditetapkan dalam filter. Aturannya adalah sebagai berikut:

  1. Intent yang tidak berisi URI maupun tipe MIME hanya akan lolos pengujian jika filter tersebut tidak menetapkan URI atau tipe MIME apa pun.
  2. Intent yang berisi URI namun tanpa jenis MIME (baik eksplisit maupun tidak dapat disimpulkan dari URI) hanya lulus pengujian jika URI-nya cocok dengan format URI filter dan filternya juga tidak menetapkan tipe MIME.
  3. Intent yang berisi jenis MIME, tetapi tidak berisi URI yang akan lolos pengujian hanya jika filter mencantumkan jenis MIME yang sama dan tidak menetapkan format URI.
  4. Intent yang berisi URI maupun tipe MIME (baik secara eksplisit maupun bisa ditebak dari URI) hanya akan lolos pengujian bagian tipe MIME jika tipe tersebut sama dengan tipe yang dicantumkan dalam filter. Ini meneruskan bagian URI pengujian jika URI-nya cocok dengan URI dalam filter atau jika memiliki URI content: atau file: dan filter tidak menentukan URI. Dengan kata lain, komponen dianggap mendukung data content: dan file: jika filternya hanya mencantumkan jenis MIME.

Catatan: Jika intent menentukan jenis URI atau MIME, pengujian data akan gagal jika tidak ada elemen <data> di <intent-filter>.

Aturan terakhir, aturan (d), mencerminkan ekspektasi bahwa komponen dapat mendapatkan data lokal dari file atau penyedia konten. Oleh karena itu, filternya dapat hanya mencantumkan jenis data dan tidak perlu secara eksplisit beri nama skema content: dan file:. Contoh berikut menunjukkan kasus umum saat elemen <data> memberi tahu Android bahwa komponen bisa mendapatkan data gambar dari konten penyedia dan menampilkannya:

<intent-filter>
    <data android:mimeType="image/*" />
    ...
</intent-filter>

Filter yang menentukan jenis data, tetapi bukan URI, mungkin adalah yang paling umum karena sebagian besar data yang tersedia dikeluarkan oleh penyedia konten.

Konfigurasi umum yang lain adalah filter dengan skema dan tipe data. Misalnya, elemen <data> seperti berikut memberi tahu Android bahwa komponen dapat mengambil data video dari jaringan untuk melakukan tindakan:

<intent-filter>
    <data android:scheme="http" android:mimeType="video/*" />
    ...
</intent-filter>

Pencocokan intent

Intent dicocokkan dengan filter intent selain untuk menemukan komponen target yang akan diaktifkan, juga untuk menemukan sesuatu tentang rangkaian komponen pada perangkat. Misalnya, aplikasi Home mengisi peluncur aplikasi dengan menemukan semua aktivitas dengan filter intent yang menentukan ACTION_MAIN tindakan dan CATEGORY_LAUNCHER kategori. Pencocokan hanya berhasil jika tindakan dan kategori dalam Intent cocok dengan filter, seperti yang dijelaskan dalam dokumentasi untuk class IntentFilter.

Aplikasi Anda bisa menggunakan pencocokan intent dengan cara serupa. PackageManager memiliki kumpulan query...() yang mengembalikan semua komponen yang bisa menerima intent tertentu dan serangkaian metode resolve...() serupa yang menentukan untuk merespons intent. Misalnya, queryIntentActivities() menampilkan daftar semua aktivitas yang dapat dilakukan intent yang diteruskan sebagai argumen, dan queryIntentServices() menampilkan daftar layanan yang serupa. Tidak ada metode yang mengaktifkan komponen; mereka hanya mencantumkan yang mana yang dapat merespons. Ada metode serupa, queryBroadcastReceivers(), untuk penerima siaran.