Ringkasan siaran

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:

  1. 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.

  2. Sediakan subclass BroadcastReceiver dan implementasikan onReceive(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:

  1. 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.12.0"
    
        // 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-rc01"
        // To test the Animator APIs
        androidTestImplementation "androidx.core:core-animation-testing:1.0.0-rc01"
    
        // 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-beta01"
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation "androidx.core:core-splashscreen:1.1.0-rc01"
    }
    

    Kotlin

    dependencies {
        val core_version = "1.12.0"
    
        // 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-rc01")
        // To test the Animator APIs
        androidTestImplementation("androidx.core:core-animation-testing:1.0.0-rc01")
    
        // 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-beta01")
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation("androidx.core:core-splashscreen:1.1.0-rc01")
    }
    
  2. Buat instance BroadcastReceiver:

    Kotlin

    val br: BroadcastReceiver = MyBroadcastReceiver()
    

    Java

    BroadcastReceiver br = new MyBroadcastReceiver();
    
  3. Buat instance IntentFilter:

    Kotlin

    val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
    

    Java

    IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
    
  4. 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 flag RECEIVER_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;
    }
    
  5. Daftarkan penerima dengan memanggil registerReceiver():

    Kotlin

    ContextCompat.registerReceiver(context, br, filter, receiverFlags)
    

    Java

    ContextCompat.registerReceiver(context, br, filter, receiverFlags);
    
  6. 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 di onDestroy() untuk mencegah membocorkan penerima keluar dari konteks aktivitas. Jika mendaftarkan penerima di onResume(), Anda harus membatalkan pendaftarannya di onPause() 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 di onSaveInstanceState(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 dalam manifesnya (dan kemudian diberi izin jika berbahaya) yang dapat menerima siaran. Misalnya, kode berikut mengirimkan siaran:

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 setelah onReceive() ditampilkan. Untuk informasi selengkapnya, lihat Efek pada status proses Untuk melakukan pekerjaan yang berjalan lama, sebaiknya:

    • Memanggil goAsync() dalam metode onReceive() penerima dan meneruskan BroadcastReceiver.PendingResult ke thread latar belakang. Tindakan ini akan membuat siaran tetap aktif setelah kembali dari onReceive(). 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.
  • 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.