Aplikasi Android dapat mengirim atau menerima pesan siaran dari sistem Android dan aplikasi Android lainnya, mirip dengan pola desain publish-subscribe. Siaran ini dikirim saat peristiwa menarik terjadi. Misalnya, sistem Android mengirimkan siaran saat berbagai peristiwa sistem terjadi, seperti saat sistem melakukan booting atau perangkat mulai mengisi daya. Aplikasi juga dapat mengirim siaran kustom, misalnya, untuk memberi tahu aplikasi lain tentang sesuatu yang mungkin menarik baginya (misalnya, beberapa data baru telah didownload).
Sistem mengoptimalkan pengiriman siaran untuk menjaga kesehatan sistem yang optimal. Oleh karena itu, waktu pengiriman siaran tidak dijamin. Aplikasi yang memerlukan komunikasi antar-proses berlatensi rendah harus mempertimbangkan layanan terikat.
Aplikasi dapat mendaftar untuk menerima siaran tertentu. Saat siaran dikirim, sistem akan otomatis mengarahkan siaran ke aplikasi yang telah berlangganan untuk menerima jenis siaran tertentu tersebut.
Secara umum, siaran dapat digunakan sebagai sistem pesan di seluruh aplikasi dan di luar alur penggunaan normal. Namun, Anda harus berhati-hati agar tidak menyalahgunakan kesempatan untuk merespons siaran dan menjalankan tugas di latar belakang yang dapat berkontribusi pada performa sistem yang lambat.
Tentang siaran sistem
Sistem akan otomatis mengirim siaran saat berbagai peristiwa sistem terjadi, seperti saat sistem beralih masuk dan keluar dari mode pesawat. Siaran sistem dikirim ke semua aplikasi yang berlangganan untuk menerima peristiwa.
Pesan siaran itu sendiri digabungkan dalam objek Intent
yang string tindakannya mengidentifikasi peristiwa yang terjadi (misalnya,
android.intent.action.AIRPLANE_MODE
). Intent juga dapat menyertakan
informasi tambahan yang dipaketkan ke dalam kolom ekstra. Misalnya, intent mode pesawat menyertakan tambahan boolean yang menunjukkan apakah Mode Pesawat aktif atau tidak.
Untuk informasi selengkapnya tentang cara membaca intent dan mendapatkan string tindakan dari intent, lihat Intent dan Filter Intent.
Untuk daftar lengkap tindakan siaran sistem, lihat
file BROADCAST_ACTIONS.TXT
di Android SDK. Setiap tindakan siaran memiliki
bidang konstan yang terkait dengannya. Misalnya, nilai konstanta
ACTION_AIRPLANE_MODE_CHANGED
adalah
android.intent.action.AIRPLANE_MODE
. Dokumentasi untuk setiap tindakan siaran
tersedia di kolom konstanta terkaitnya.
Perubahan pada siaran sistem
Seiring berkembangnya platform Android, platform ini secara berkala mengubah cara perilaku siaran sistem. Perhatikan perubahan berikut untuk mendukung semua versi Android.
Android 14
Saat aplikasi berada dalam status
di-cache, pengiriman siaran dioptimalkan
untuk kesehatan sistem. Misalnya, siaran sistem yang kurang penting seperti
ACTION_SCREEN_ON
akan
ditangguhkan saat aplikasi dalam status cache. Setelah aplikasi beralih dari status
cache ke dalam siklus proses
aktif, sistem akan mengirimkan
siaran yang ditangguhkan.
Siaran penting yang dideklarasikan dalam manifes akan menghapus sementara aplikasi dari status cache untuk pengiriman.
Android 9
Mulai Android 9 (level API 28), Siaran
NETWORK_STATE_CHANGED_ACTION
tidak menerima informasi tentang lokasi pengguna atau data
identitas pribadi.
Selain itu, jika aplikasi Anda diinstal di perangkat yang menjalankan Android 9 atau yang lebih tinggi,
siaran sistem dari Wi-Fi tidak akan berisi SSID, BSSID, informasi
koneksi, atau hasil pemindaian. Untuk mendapatkan informasi ini, panggil
getConnectionInfo()
.
Android 8.0
Mulai Android 8.0 (API level 26), sistem menerapkan pembatasan tambahan pada penerima yang dideklarasikan manifes.
Jika aplikasi menargetkan Android 8.0 atau yang lebih tinggi, Anda tidak dapat menggunakan manifes untuk mendeklarasikan penerima untuk sebagian besar siaran implisit (siaran yang tidak menargetkan aplikasi Anda secara khusus). Anda masih dapat menggunakan penerima yang terdaftar dalam konteks saat pengguna aktif menggunakan aplikasi Anda.
Android 7.0
Android 7.0 (API level 24) dan yang lebih tinggi tidak mengirim siaran sistem berikut:
Selain itu, aplikasi yang menargetkan Android 7.0 dan yang lebih tinggi harus mendaftarkan siaran CONNECTIVITY_ACTION
menggunakan registerReceiver(BroadcastReceiver, IntentFilter)
.
Menyatakan penerima dalam manifes tidak akan berfungsi.
Menerima siaran
Aplikasi dapat menerima siaran dengan dua cara: melalui penerima yang dideklarasikan manifes dan penerima yang terdaftar dalam konteks.
Penerima yang dinyatakan manifes
Jika Anda mendeklarasikan penerima siaran dalam manifes, sistem akan meluncurkan aplikasi Anda (jika aplikasi belum berjalan) saat siaran dikirim.
Untuk menyatakan penerima siaran dalam manifes, lakukan langkah-langkah berikut:
Tetapkan elemen
<receiver>
dalam manifes aplikasi Anda.<!-- If this receiver listens for broadcasts sent from the system or from other apps, even other apps that you own, set android:exported to "true". --> <receiver android:name=".MyBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="APP_SPECIFIC_BROADCAST" /> </intent-filter> </receiver>
Filter intent akan menentukan tindakan siaran yang menjadi langganan penerima Anda.
Sediakan subclass
BroadcastReceiver
dan implementasikanonReceive(Context, Intent)
. Penerima siaran dalam contoh berikut membuat log dan menampilkan konten siaran:Kotlin
private const val TAG = "MyBroadcastReceiver" class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { StringBuilder().apply { append("Action: ${intent.action}\n") append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}\n") toString().also { log -> Log.d(TAG, log) val binding = ActivityNameBinding.inflate(layoutInflater) val view = binding.root setContentView(view) Snackbar.make(view, log, Snackbar.LENGTH_LONG).show() } } } }
Java
public class MyBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "MyBroadcastReceiver"; @Override public void onReceive(Context context, Intent intent) { StringBuilder sb = new StringBuilder(); sb.append("Action: " + intent.getAction() + "\n"); sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n"); String log = sb.toString(); Log.d(TAG, log); ActivityNameBinding binding = ActivityNameBinding.inflate(layoutInflater); val view = binding.root; setContentView(view); Snackbar.make(view, log, Snackbar.LENGTH_LONG).show(); } }
Untuk mengaktifkan view binding, konfigurasi viewBinding di file build.gradle level modul.
Pengelola paket sistem akan mendaftarkan penerima setelah aplikasi terinstal. Penerima kemudian menjadi titik entri terpisah ke aplikasi Anda, yang berarti bahwa sistem dapat memulai aplikasi dan mengirimkan siaran jika aplikasi tidak sedang berjalan.
Sistem membuat objek komponen BroadcastReceiver
baru
untuk menangani setiap siaran yang diterimanya. Objek ini hanya valid
selama durasi panggilan ke onReceive(Context, Intent)
. Setelah kode
ditampilkan dari metode ini, sistem menganggap komponen tersebut tidak lagi
aktif.
Penerima yang terdaftar dalam konteks
Penerima yang terdaftar dalam konteks akan menerima siaran selama konteks pendaftarannya
valid. Misalnya, jika mendaftar dalam konteks
Activity
, Anda akan menerima siaran selama aktivitas tidak dihancurkan. Jika
mendaftar dengan konteks Aplikasi, Anda akan menerima siaran selama aplikasi
berjalan.
Untuk mendaftarkan penerima dalam konteks, lakukan langkah-langkah berikut:
Dalam file build level modul aplikasi Anda, sertakan Library AndroidX Core versi 1.9.0 atau yang lebih tinggi:
Groovy
dependencies { def core_version = "1.13.1" // Java language implementation implementation "androidx.core:core:$core_version" // Kotlin implementation "androidx.core:core-ktx:$core_version" // To use RoleManagerCompat implementation "androidx.core:core-role:1.0.0" // To use the Animator APIs implementation "androidx.core:core-animation:1.0.0" // To test the Animator APIs androidTestImplementation "androidx.core:core-animation-testing:1.0.0" // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation "androidx.core:core-performance:1.0.0" // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation "androidx.core:core-google-shortcuts:1.1.0" // Optional - to support backwards compatibility of RemoteViews implementation "androidx.core:core-remoteviews:1.1.0" // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation "androidx.core:core-splashscreen:1.2.0-alpha01" }
Kotlin
dependencies { val core_version = "1.13.1" // Java language implementation implementation("androidx.core:core:$core_version") // Kotlin implementation("androidx.core:core-ktx:$core_version") // To use RoleManagerCompat implementation("androidx.core:core-role:1.0.0") // To use the Animator APIs implementation("androidx.core:core-animation:1.0.0") // To test the Animator APIs androidTestImplementation("androidx.core:core-animation-testing:1.0.0") // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation("androidx.core:core-performance:1.0.0") // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation("androidx.core:core-google-shortcuts:1.1.0") // Optional - to support backwards compatibility of RemoteViews implementation("androidx.core:core-remoteviews:1.1.0") // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation("androidx.core:core-splashscreen:1.2.0-alpha01") }
Buat instance
BroadcastReceiver
:Kotlin
val br: BroadcastReceiver = MyBroadcastReceiver()
Java
BroadcastReceiver br = new MyBroadcastReceiver();
Buat instance
IntentFilter
:Kotlin
val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
Java
IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
Pilih apakah penerima siaran harus diekspor dan terlihat oleh aplikasi lain di perangkat. Jika penerima ini memproses siaran yang dikirim dari sistem atau dari aplikasi lain—bahkan aplikasi lain yang Anda miliki—gunakan tanda
RECEIVER_EXPORTED
. Jika penerima ini hanya memproses siaran yang dikirim oleh aplikasi Anda, gunakan flagRECEIVER_NOT_EXPORTED
.Kotlin
val listenToBroadcastsFromOtherApps = false val receiverFlags = if (listenToBroadcastsFromOtherApps) { ContextCompat.RECEIVER_EXPORTED } else { ContextCompat.RECEIVER_NOT_EXPORTED }
Java
boolean listenToBroadcastsFromOtherApps = false; if (listenToBroadcastsFromOtherApps) { receiverFlags = ContextCompat.RECEIVER_EXPORTED; } else { receiverFlags = ContextCompat.RECEIVER_NOT_EXPORTED; }
Daftarkan penerima dengan memanggil
registerReceiver()
:Kotlin
ContextCompat.registerReceiver(context, br, filter, receiverFlags)
Java
ContextCompat.registerReceiver(context, br, filter, receiverFlags);
Untuk berhenti menerima siaran, panggil
unregisterReceiver(android.content.BroadcastReceiver)
. Pastikan untuk membatalkan pendaftaran penerima saat Anda tidak lagi memerlukannya atau konteksnya tidak lagi valid.Berhati-hatilah dengan tempat Anda mendaftar dan membatalkan pendaftaran penerima. Misalnya, jika Anda mendaftarkan penerima di
onCreate(Bundle)
menggunakan konteks aktivitas, Anda harus membatalkan pendaftarannya dionDestroy()
untuk mencegah membocorkan penerima keluar dari konteks aktivitas. Jika mendaftarkan penerima dionResume()
, Anda harus membatalkan pendaftarannya dionPause()
untuk mencegah pendaftarannya beberapa kali (Jika Anda tidak ingin menerima siaran saat dijeda, dan ini dapat mengurangi overhead sistem yang tidak perlu). Jangan membatalkan pendaftaran dionSaveInstanceState(Bundle)
, karena ini tidak akan dipanggil jika pengguna kembali ke tumpukan histori.
Efek pada status proses
Apakah BroadcastReceiver
Anda
beroperasi atau tidak memengaruhi proses yang ada di dalamnya, yang dapat mengubah
kemungkinan penghentian sistemnya. Proses latar depan menjalankan metode onReceive()
penerima. Sistem
akan menjalankan proses kecuali dalam tekanan memori ekstrem.
BroadcastReceiver akan dinonaktifkan setelah onReceive()
. Proses host
penerima hanya akan sepenting komponen aplikasinya. Jika proses tersebut hanya menghosting
penerima yang dideklarasikan manifes (kemunculan yang sering terjadi untuk aplikasi yang belum pernah
berinteraksi dengan pengguna atau tidak baru-baru ini digunakan), sistem dapat menghentikannya setelah onReceive()
agar
resource tersedia untuk proses lain yang lebih penting.
Dengan demikian, penerima siaran tidak boleh memulai thread latar belakang yang berjalan lama.
Sistem dapat menghentikan proses kapan saja setelah onReceive()
untuk mengklaim kembali
memori, menghentikan thread yang dibuat. Agar proses tetap aktif, jadwalkan
JobService
dari penerima menggunakan JobScheduler
agar sistem mengetahui bahwa proses tersebut masih berjalan.
Ringkasan Pekerjaan Latar Belakang memberikan detail selengkapnya.
Mengirimkan siaran
Android memberikan tiga cara bagi aplikasi untuk mengirim siaran:
- Metode
sendOrderedBroadcast(Intent, String)
mengirimkan siaran ke satu penerima dalam satu waktu. Karena dijalankan secara bergantian, setiap penerima dapat menyebarkan hasil ke penerima berikutnya, atau dapat membatalkan siaran sepenuhnya sehingga tidak akan diteruskan ke penerima lain. Urutan penerima yang dijalankan dapat dikontrol dengan atribut android:priority dari filter intent yang cocok; penerima dengan prioritas yang sama akan dijalankan dalam urutan arbitrer. - Metode
sendBroadcast(Intent)
mengirim siaran ke semua penerima dalam urutan yang tidak ditentukan. Ini disebut Siaran Normal. Ini lebih efisien, tetapi artinya penerima tidak dapat membaca hasil dari penerima lain, menyebarkan data yang diterima dari siaran, atau membatalkan siaran.
Cuplikan kode berikut menunjukkan cara mengirim siaran dengan membuat
Intent dan memanggil sendBroadcast(Intent)
.
Kotlin
Intent().also { intent -> intent.setAction("com.example.broadcast.MY_NOTIFICATION") intent.putExtra("data", "Nothing to see here, move along.") sendBroadcast(intent) }
Java
Intent intent = new Intent(); intent.setAction("com.example.broadcast.MY_NOTIFICATION"); intent.putExtra("data", "Nothing to see here, move along."); sendBroadcast(intent);
Pesan siaran dikemas dalam objek Intent
.
String tindakan intent harus menyediakan sintaksis nama paket Java aplikasi dan
secara unik mengidentifikasi peristiwa siaran. Anda dapat melampirkan informasi tambahan
ke intent dengan putExtra(String, Bundle)
.
Anda juga dapat membatasi siaran ke sekumpulan aplikasi dalam organisasi yang sama dengan
memanggil setPackage(String)
pada intent.
Membatasi siaran dengan izin
Izin memungkinkan Anda membatasi siaran ke kumpulan aplikasi yang memiliki izin tertentu. Anda dapat menerapkan pembatasan pada pengirim atau penerima siaran.
Mengirim dengan izin
Saat memanggil sendBroadcast(Intent, String)
atau
sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
, Anda dapat menentukan
parameter izin. Hanya penerima yang telah meminta izin dengan
tag
Kotlin
sendBroadcast(Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
Java
sendBroadcast(new Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
Untuk menerima siaran, aplikasi penerima harus meminta izin seperti yang ditunjukkan di bawah ini:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
Anda dapat menentukan izin sistem yang ada seperti
BLUETOOTH_CONNECT
atau menentukan izin kustom dengan
elemen <permission>
. Untuk
informasi tentang izin dan keamanan secara umum, lihat Izin
Sistem.
Menerima dengan izin
Jika Anda menentukan parameter izin saat mendaftarkan penerima siaran
(baik dengan registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
atau tag
<receiver>
di
manifes Anda), hanya penyiar yang telah meminta izin dengan tag
<uses-permission>
dalam manifesnya (dan kemudian diberi izin jika
berbahaya) yang dapat mengirim Intent ke penerima.
Misalnya, anggaplah aplikasi penerima Anda memiliki penerima yang dinyatakan manifes seperti yang ditunjukkan di bawah ini:
<receiver android:name=".MyBroadcastReceiver"
android:permission="android.permission.BLUETOOTH_CONNECT">
<intent-filter>
<action android:name="android.intent.action.ACTION_FOUND"/>
</intent-filter>
</receiver>
Atau aplikasi penerima Anda memiliki penerima yang terdaftar dalam konteks seperti yang ditunjukkan di bawah ini:
Kotlin
var filter = IntentFilter(Intent.ACTION_FOUND) registerReceiver(receiver, filter, Manifest.permission.BLUETOOTH_CONNECT, null )
Java
IntentFilter filter = new IntentFilter(Intent.ACTION_FOUND); registerReceiver(receiver, filter, Manifest.permission.BLUETOOTH_CONNECT, null );
Kemudian, agar dapat mengirim siaran ke penerima tersebut, aplikasi pengirim harus meminta izin seperti yang ditunjukkan di bawah ini:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
Pertimbangan keamanan dan praktik terbaik
Berikut adalah beberapa pertimbangan keamanan dan praktik terbaik untuk mengirim dan menerima siaran:
Jika banyak aplikasi yang telah mendaftar untuk menerima siaran yang sama dalam manifesnya, hal ini dapat menyebabkan sistem meluncurkan banyak aplikasi, yang menyebabkan dampak yang signifikan pada performa perangkat dan pengalaman pengguna. Untuk menghindarinya, sebaiknya gunakan pendaftaran konteks daripada deklarasi manifes. Terkadang, sistem Android sendiri menerapkan penggunaan penerima yang terdaftar dalam konteks. Misalnya, siaran
CONNECTIVITY_ACTION
hanya dikirimkan ke penerima yang terdaftar dalam konteks.Jangan menyiarkan informasi sensitif menggunakan intent implisit. Informasi ini dapat dibaca oleh aplikasi apa pun yang mendaftar untuk menerima siaran. Ada tiga cara untuk mengontrol siapa saja yang dapat menerima siaran Anda:
- Anda dapat menentukan izin saat mengirimkan siaran.
- Di Android 4.0 dan yang lebih tinggi, Anda dapat menentukan
paket dengan
setPackage(String)
saat mengirim siaran. Sistem membatasi siaran ke kumpulan aplikasi yang cocok dengan paket.
Saat Anda mendaftarkan penerima, aplikasi apa pun dapat mengirim siaran yang berpotensi berbahaya ke penerima aplikasi Anda. Ada beberapa cara untuk membatasi siaran yang diterima aplikasi Anda:
- Anda dapat menentukan izin saat mendaftarkan penerima siaran.
- Untuk penerima yang dinyatakan manifes, Anda dapat menetapkan atribut android:exported ke "false" dalam manifes. Penerima tidak akan menerima siaran dari sumber di luar aplikasi.
Ruang nama untuk tindakan siaran bersifat global. Pastikan nama tindakan dan string lain ditulis dalam namespace yang Anda miliki, atau Anda akan tidak sengaja bertentangan dengan aplikasi lain.
Karena berjalan di thread utama, metode
onReceive(Context, Intent)
penerima seharusnya dapat berjalan dan kembali dengan cepat. Jika Anda perlu melakukan pekerjaan yang berjalan lama, berhati-hatilah saat menghasilkan thread atau memulai layanan latar belakang karena sistem dapat menghentikan seluruh proses setelahonReceive()
ditampilkan. Untuk informasi selengkapnya, lihat Efek pada status proses Untuk melakukan pekerjaan yang berjalan lama, sebaiknya:- Memanggil
goAsync()
dalam metodeonReceive()
penerima dan meneruskanBroadcastReceiver.PendingResult
ke thread latar belakang. Tindakan ini akan membuat siaran tetap aktif setelah kembali darionReceive()
. Namun, meskipun dengan pendekatan ini, sistem mengharapkan Anda menyelesaikan siaran dengan sangat cepat (kurang dari 10 detik). Hal ini memungkinkan Anda memindahkan tugas ke thread lain untuk menghindari gangguan pada thread utama. - Menjadwalkan tugas dengan
JobScheduler
. Untuk informasi selengkapnya, lihat Penjadwalan Tugas Cerdas.
- Memanggil
Jangan memulai aktivitas dari penerima siaran karena pengalaman pengguna akan terasa janggal; terutama jika ada lebih dari satu penerima. Sebagai gantinya, pertimbangkan untuk menampilkan notifikasi.