Android-Apps können Broadcast-Nachrichten vom Android-System und von anderen Android-Apps senden oder empfangen, ähnlich dem Designmuster Publish-Subscribe. Diese Broadcasts werden gesendet, wenn ein relevantes Ereignis eintritt. Beispielsweise sendet das Android-System Broadcasts, wenn verschiedene Systemereignisse auftreten, z. B. wenn das System hochgefahren wird oder das Gerät aufgeladen wird. Apps können auch benutzerdefinierte Broadcasts senden, um beispielsweise andere Apps über etwas zu informieren, das sie interessieren könnte (z. B. wenn neue Daten heruntergeladen wurden).
Das System optimiert die Übermittlung von Broadcasts, um einen optimalen Systemzustand aufrechtzuerhalten. Daher werden die Lieferzeiten von Broadcasts nicht garantiert. Anwendungen, die Interprozesskommunikation mit niedriger Latenz benötigen, sollten gebundene Dienste verwenden.
Apps können sich für den Empfang bestimmter Broadcasts registrieren. Wenn eine Nachricht gesendet wird, leitet das System diese automatisch an Apps weiter, die diese bestimmte Art von Broadcast abonniert haben.
Im Allgemeinen können Broadcasts als Messaging-System über Apps hinweg und außerhalb des normalen Nutzerflusses verwendet werden. Achten Sie jedoch darauf, nicht die Möglichkeit zu missbrauchen, auf Broadcasts zu antworten und Jobs im Hintergrund auszuführen, da dies die Systemleistung verlangsamen kann.
System-Broadcasts
Das System sendet automatisch Broadcasts, wenn verschiedene Systemereignisse auftreten, z. B. wenn das System den Flugmodus ein- und ausschaltet. Systemübertragungen werden an alle Anwendungen gesendet, die das Ereignis abonniert haben.
Die Broadcast-Nachricht selbst ist in ein Intent
-Objekt eingeschlossen, dessen Aktionsstring das aufgetretene Ereignis identifiziert (z. B. android.intent.action.AIRPLANE_MODE
). Der Intent kann auch zusätzliche Informationen enthalten, die in sein zusätzliches Feld eingebunden sind. Der Flugmodus-Intent enthält beispielsweise ein boolesches Extra, das angibt, ob der Flugmodus aktiviert ist.
Weitere Informationen zum Lesen von Intents und Abrufen des Aktionsstrings aus einem Intent finden Sie unter Intents und Intent-Filter.
Eine vollständige Liste der Systemübertragungsaktionen finden Sie in der Datei BROADCAST_ACTIONS.TXT
im Android SDK. Jeder Broadcast-Aktion
ist ein konstantes Feld zugeordnet. Der Wert der Konstanten ACTION_AIRPLANE_MODE_CHANGED
ist beispielsweise android.intent.action.AIRPLANE_MODE
. Dokumentation für jede Broadcast-Aktion ist im zugehörigen Konstantenfeld verfügbar.
Änderungen an System-Broadcasts
Im Zuge der Weiterentwicklung der Android-Plattform ändert sie regelmäßig das Broadcast-Verhalten des Systems. Beachte die folgenden Änderungen, damit alle Android-Versionen unterstützt werden.
Android 14
Während sich Anwendungen in einem Cache-Status befinden, ist die Broadcast-Bereitstellung für den Systemzustand optimiert. Beispielsweise werden weniger wichtige System-Broadcasts wie ACTION_SCREEN_ON
ausgesetzt, während die Anwendung im Cache gespeichert ist. Sobald die Anwendung aus dem Cache-Zustand in einen aktiven Prozesslebenszyklus wechselt, liefert das System alle verzögerten Broadcasts.
Bei wichtigen Broadcasts, die im Manifest deklariert sind, werden Apps vorübergehend für die Bereitstellung aus dem Cache entfernt.
Android 9
Ab Android 9 (API-Level 28) erhält die NETWORK_STATE_CHANGED_ACTION
-Übertragung keine Informationen zum Standort des Nutzers oder zu personenidentifizierbaren Daten.
Wenn Ihre App auf einem Gerät mit Android 9 oder höher installiert ist, enthalten System-Broadcasts aus dem WLAN keine SSIDs, BSSIDs, Verbindungsinformationen oder Scanergebnisse. Rufen Sie stattdessen getConnectionInfo()
auf, um diese Informationen zu erhalten.
Android 8.0
Ab Android 8.0 (API-Level 26) wendet das System zusätzliche Einschränkungen für in Manifest deklarierte Empfänger an.
Wenn Ihre App auf Android 8.0 oder höher ausgerichtet ist, können Sie mit dem Manifest für die meisten impliziten Broadcasts (Übertragungen, die nicht spezifisch auf Ihre App ausgerichtet sind) keinen Empfänger deklarieren. Sie können weiterhin einen kontextregistrierten Empfänger verwenden, wenn der Nutzer Ihre Anwendung aktiv verwendet.
Android 7.0
Android 7.0 (API-Level 24) und höher sendet keine folgenden System-Broadcasts:
Außerdem müssen Apps, die auf Android 7.0 und höher ausgerichtet sind, den CONNECTIVITY_ACTION
-Broadcast mit registerReceiver(BroadcastReceiver, IntentFilter)
registrieren.
Sie können im Manifest keinen Empfänger deklarieren.
Empfang von Nachrichten an alle
Anwendungen können Broadcasts auf zwei Arten empfangen: über Manifest-Deklarationen und kontextregistrierte Empfänger.
Vom Manifest deklarierte Empfänger
Wenn Sie in Ihrem Manifest einen Broadcast-Empfänger deklarieren, startet das System Ihre App beim Senden des Broadcasts, sofern sie noch nicht ausgeführt wird.
Führen Sie die folgenden Schritte aus, um einen Broadcast-Empfänger im Manifest zu deklarieren:
Geben Sie das Element
<receiver>
im Manifest Ihrer App an.<!-- 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>
Die Intent-Filter geben die Übertragungsaktionen an, die der Empfänger abonniert.
Erstellen Sie eine Unterklasse von
BroadcastReceiver
und implementieren SieonReceive(Context, Intent)
. Der Broadcast-Empfänger im folgenden Beispiel protokolliert und zeigt den Inhalt des Broadcasts an: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(); } }
Um die Ansichtsbindung zu aktivieren, müssen Sie in der build.gradle-Datei auf Modulebene viewBinding konfigurieren.
Der Systempaketmanager registriert den Empfänger, wenn die App installiert wird. Der Empfänger wird dann zu einem separaten Einstiegspunkt in Ihre App. Das bedeutet, dass das System die App starten und die Übertragung senden kann, wenn die Anwendung gerade nicht ausgeführt wird.
Das System erstellt ein neues BroadcastReceiver
-Komponentenobjekt, um jede empfangene Übertragung zu verarbeiten. Dieses Objekt ist nur für die Dauer des Aufrufs von onReceive(Context, Intent)
gültig. Sobald Ihr Code von dieser Methode zurückgegeben wird, betrachtet das System die Komponente nicht mehr als aktiv.
Kontextregistrierte Empfänger
Kontextregistrierte Empfänger empfangen Broadcasts, solange ihr Registrierungskontext gültig ist. Wenn Sie sich beispielsweise in einem Activity
-Kontext registrieren, erhalten Sie Broadcasts, solange die Aktivität nicht gelöscht wird. Wenn Sie sich mit dem Anwendungskontext registrieren, erhalten Sie Broadcasts, solange die Anwendung ausgeführt wird.
Führe die folgenden Schritte aus, um einen Empfänger mit einem Kontext zu registrieren:
Die Build-Datei auf Modulebene Ihrer App muss Version 1.9.0 oder höher der AndroidX Core-Bibliothek enthalten:
Groovig
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") }
Erstellen Sie eine Instanz von
BroadcastReceiver
:Kotlin
val br: BroadcastReceiver = MyBroadcastReceiver()
Java
BroadcastReceiver br = new MyBroadcastReceiver();
Erstellen Sie eine Instanz von
IntentFilter
:Kotlin
val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
Java
IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
Legen Sie fest, ob der Broadcast-Receiver exportiert und für andere Apps auf dem Gerät sichtbar sein soll. Wenn dieser Empfänger auf Broadcasts wartet, die vom System oder von anderen Apps – auch von anderen Apps, die Ihnen gehören – gesendet werden, verwenden Sie das Flag
RECEIVER_EXPORTED
. Wenn dieser Empfänger stattdessen nur Broadcasts überwacht, die von Ihrer Anwendung gesendet werden, verwenden Sie das 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; }
Registrieren Sie den Empfänger durch Aufrufen von
registerReceiver()
:Kotlin
ContextCompat.registerReceiver(context, br, filter, receiverFlags)
Java
ContextCompat.registerReceiver(context, br, filter, receiverFlags);
Wenn du keine Nachrichten mehr empfangen möchtest, ruf
unregisterReceiver(android.content.BroadcastReceiver)
an. Heben Sie die Registrierung des Empfängers auf, wenn Sie ihn nicht mehr benötigen oder der Kontext nicht mehr gültig ist.Achten Sie darauf, wo Sie den Empfänger registrieren und die Registrierung aufheben. Wenn Sie beispielsweise einen Empfänger in
onCreate(Bundle)
mithilfe des Kontexts der Aktivität registrieren, sollten Sie seine Registrierung inonDestroy()
aufheben, damit der Empfänger nicht aus dem Aktivitätskontext herausläuft. Wenn Sie einen Empfänger inonResume()
registrieren, sollten Sie die Registrierung inonPause()
aufheben, um eine mehrfache Registrierung zu vermeiden. Wenn Sie bei einer Pause keine Broadcasts empfangen möchten und dies unnötigen Systemaufwand reduzieren kann. Heben Sie die Registrierung inonSaveInstanceState(Bundle)
nicht auf, da dies nicht aufgerufen wird, wenn der Nutzer in den Verlaufsstapel zurückkehrt.
Auswirkungen auf den Prozessstatus
Ob das BroadcastReceiver
funktioniert oder nicht, wirkt sich auf den enthaltenen Prozess aus, was die Wahrscheinlichkeit für das Beenden des Systems beeinflussen kann. Ein Vordergrundprozess führt die Methode onReceive()
eines Empfängers aus. Das System führt den Prozess aus, außer bei extremer Speicherauslastung.
BroadcastReceiver wird nach dem onReceive()
deaktiviert. Der Hostprozess des Empfängers ist nur so wichtig wie seine Anwendungskomponenten. Wenn bei diesem Prozess nur ein im Manifest deklarierter Empfänger gehostet wird (was häufig bei Anwendungen der Fall ist, mit denen der Nutzer noch nie interagiert hat oder mit der er in letzter Zeit nicht interagiert hat), kann das System ihn nach onReceive()
beenden, um Ressourcen für andere kritischere Prozesse verfügbar zu machen.
Daher sollten Broadcast-Empfänger keine lang laufenden Hintergrundthreads initiieren.
Das System kann den Prozess jederzeit nach onReceive()
beenden, um Arbeitsspeicher freizugeben und den erstellten Thread zu beenden. Um den Prozess aktiv zu halten, planen Sie mit JobScheduler
einen JobService
vom Empfänger, damit das System weiß, dass der Prozess noch funktioniert.
Weitere Informationen finden Sie unter Überblick über Hintergrundarbeiten.
Nachrichten an alle werden gesendet
Android bietet Apps drei Möglichkeiten, Nachrichten an alle zu senden:
- Die Methode
sendOrderedBroadcast(Intent, String)
sendet Broadcasts jeweils an einen Empfänger. Wenn jeder Empfänger der Reihe nach ein Ergebnis ausführt, kann er ein Ergebnis an den nächsten Empfänger weitergeben oder die Übertragung vollständig abbrechen, damit es nicht an andere Empfänger weitergegeben wird. Die Reihenfolge, in der die Empfänger ausgeführt werden, kann mit dem Attribut „android:priorität“ des entsprechenden Intent-Filters gesteuert werden. Empfänger mit derselben Priorität werden in einer beliebigen Reihenfolge ausgeführt. - Bei der Methode
sendBroadcast(Intent)
werden Broadcasts in einer nicht definierten Reihenfolge an alle Empfänger gesendet. Dies wird als normale Nachricht bezeichnet. Dies ist effizienter, bedeutet jedoch, dass Empfänger keine Ergebnisse von anderen Empfängern lesen, vom Broadcast empfangene Daten weitergeben oder den Broadcast abbrechen können.
Das folgende Code-Snippet zeigt, wie Sie einen Broadcast senden, indem Sie einen Intent erstellen und sendBroadcast(Intent)
aufrufen.
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);
Die Broadcast-Nachricht ist in ein Intent
-Objekt eingebunden.
Der Aktionsstring des Intents muss die Syntax des Java-Paketnamens der App angeben und das Übertragungsereignis eindeutig identifizieren. Mit putExtra(String, Bundle)
können Sie zusätzliche Informationen an den Intent anhängen.
Sie können eine Übertragung auch auf eine Reihe von Apps in derselben Organisation beschränken. Dazu rufen Sie setPackage(String)
für den Intent auf.
Übertragungen mit Berechtigungen einschränken
Mit Berechtigungen kannst du Broadcasts auf eine Gruppe von Apps beschränken, die bestimmte Berechtigungen haben. Sie können Einschränkungen entweder für den Sender oder den Empfänger einer Übertragung erzwingen.
Mit Berechtigungen senden
Wenn Sie sendBroadcast(Intent, String)
oder sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
aufrufen, können Sie einen Berechtigungsparameter angeben. Nur Empfänger, die diese Berechtigung mit dem
Kotlin
sendBroadcast(Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
Java
sendBroadcast(new Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
Um die Nachricht zu empfangen, muss die empfangende App die Berechtigung wie unten gezeigt anfordern:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
Sie können entweder eine vorhandene Systemberechtigung wie BLUETOOTH_CONNECT
angeben oder eine benutzerdefinierte Berechtigung mit dem Element <permission>
definieren. Informationen zu Berechtigungen und Sicherheit im Allgemeinen finden Sie unter Systemberechtigungen.
Empfang mit Berechtigungen
Wenn Sie beim Registrieren eines Broadcast-Empfängers einen Berechtigungsparameter angeben (entweder mit registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
oder im <receiver>
-Tag in Ihrem Manifest), können nur Sender, die die Berechtigung mit dem <uses-permission>
-Tag in ihrem Manifest angefordert haben und die später die Berechtigung erhalten haben, einen Intent an den Empfänger senden.
Angenommen, Ihre empfangende App hat einen in der Manifest-Datei deklarierten Empfänger, wie unten dargestellt:
<receiver android:name=".MyBroadcastReceiver"
android:permission="android.permission.BLUETOOTH_CONNECT">
<intent-filter>
<action android:name="android.intent.action.ACTION_FOUND"/>
</intent-filter>
</receiver>
Oder Ihre empfangende App hat einen kontextregistrierten Empfänger, wie unten gezeigt:
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 );
Die sendende App muss dann wie unten gezeigt die Berechtigung anfordern, um Broadcasts an diese Empfänger zu senden:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
Sicherheitsaspekte und Best Practices
Im Folgenden finden Sie einige Sicherheitsaspekte und Best Practices für das Senden und Empfangen von Broadcasts:
Wenn viele Apps in ihrem Manifest registriert sind, denselben Broadcast zu empfangen, kann das dazu führen, dass das System viele Apps startet, was sich erheblich auf die Geräteleistung und die Nutzererfahrung auswirkt. Um dies zu vermeiden, solltest du die Kontextregistrierung gegenüber der Manifestdeklaration verwenden. Manchmal erzwingt das Android-System selbst die Verwendung von kontextregistrierten Empfängern. Der Broadcast
CONNECTIVITY_ACTION
wird beispielsweise nur an kontextregistrierte Empfänger gesendet.Senden Sie keine vertraulichen Informationen mit einem impliziten Intent. Die Informationen können von jeder App gelesen werden, die sich für den Empfang der Nachricht registriert. Es gibt drei Möglichkeiten zu steuern, wer Ihre Nachrichten erhalten kann:
- Beim Senden einer Nachricht können Sie eine Berechtigung angeben.
- Ab Android 4.0 können Sie ein Paket mit
setPackage(String)
angeben, wenn Sie eine Broadcast senden. Das System beschränkt die Übertragung auf die Gruppe von Apps, die dem Paket entsprechen.
Wenn Sie einen Empfänger registrieren, kann jede Anwendung potenziell schädliche Broadcasts an den Empfänger Ihrer Anwendung senden. Es gibt mehrere Möglichkeiten, die Broadcasts einzuschränken, die Ihre Anwendung empfängt:
- Sie können eine Berechtigung bei der Registrierung eines Rundfunkempfängers angeben.
- Für in Manifest deklarierte Empfänger können Sie das Attribut android:exported im Manifest auf „false“ setzen. Der Empfänger empfängt keine Broadcasts von Quellen außerhalb der App.
Der Namespace für Übertragungsaktionen ist global. Aktionsnamen und andere Strings müssen in einem Namespace geschrieben sein, der Ihnen gehört. Andernfalls kann es zu unbeabsichtigten Konflikten mit anderen Anwendungen kommen.
Da die Methode
onReceive(Context, Intent)
eines Empfängers im Hauptthread ausgeführt wird, sollte sie schnell ausgeführt und zurückgegeben werden. Wenn Sie lange arbeiten müssen, achten Sie darauf, Threads zu erzeugen oder Hintergrunddienste zu starten, da das System den gesamten Prozess beenden kann, nachdemonReceive()
zurückgegeben wurde. Weitere Informationen finden Sie unter Auswirkung auf den Prozessstatus. Für lang andauernde Arbeiten empfehlen wir Folgendes:goAsync()
in der MethodeonReceive()
des Empfängers aufrufen undBroadcastReceiver.PendingResult
an einen Hintergrundthread übergeben Dadurch bleibt die Übertragung nach der Rückkehr vononReceive()
aktiv. Aber selbst bei diesem Ansatz erwartet das System, dass Sie die Übertragung sehr schnell (unter 10 Sekunden) beenden. Sie können die Arbeit in einen anderen Thread verschieben, um eine Störung des Hauptthreads zu vermeiden.- Einen Job mit dem
JobScheduler
planen. Weitere Informationen finden Sie unter Intelligente Jobplanung.
Starten Sie keine Aktivitäten von Übertragungsempfängern aus, da die Nutzererfahrung irritierend ist. Dies gilt insbesondere, wenn es mehr als einen Empfänger gibt. Stattdessen können Sie sich eine Benachrichtigung anzeigen lassen.