Broadcasts – Übersicht

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:

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

  2. Erstellen Sie eine Unterklasse von BroadcastReceiver und implementieren Sie onReceive(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:

  1. 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.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. Erstellen Sie eine Instanz von BroadcastReceiver:

    Kotlin

    val br: BroadcastReceiver = MyBroadcastReceiver()
    

    Java

    BroadcastReceiver br = new MyBroadcastReceiver();
    
  3. Erstellen Sie eine Instanz von IntentFilter:

    Kotlin

    val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
    

    Java

    IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
    
  4. 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 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. Registrieren Sie den Empfänger durch Aufrufen von registerReceiver():

    Kotlin

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

    Java

    ContextCompat.registerReceiver(context, br, filter, receiverFlags);
    
  6. 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 in onDestroy() aufheben, damit der Empfänger nicht aus dem Aktivitätskontext herausläuft. Wenn Sie einen Empfänger in onResume() registrieren, sollten Sie die Registrierung in onPause() 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 in onSaveInstanceState(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 -Tag in ihrem Manifest angefordert und die Berechtigung später erhalten haben, wenn sie gefährlich ist, können den Broadcast empfangen. Der folgende Code sendet beispielsweise einen Broadcast:

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, nachdem onReceive() zurückgegeben wurde. Weitere Informationen finden Sie unter Auswirkung auf den Prozessstatus. Für lang andauernde Arbeiten empfehlen wir Folgendes:

    • goAsync() in der Methode onReceive() des Empfängers aufrufen und BroadcastReceiver.PendingResult an einen Hintergrundthread übergeben Dadurch bleibt die Übertragung nach der Rückkehr von onReceive() 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.