Broadcasts – Übersicht

Android-Apps können Nachrichten an alle über das Android-System und anderen Android-Apps, ähnlich wie die publish-Subscribe Designmuster. Diese Broadcasts werden gesendet, wenn ein Ereignis von Interesse auftritt. Beispielsweise sendet das Android-System Broadcasts, wenn verschiedene Systemereignisse z. B. wenn das System hochfährt oder das Gerät aufgeladen wird. Apps können auch benutzerdefinierte Nachrichten senden, um z. B. andere Apps über etwas, das sie interessieren könnte (zum Beispiel, wenn einige neue Daten heruntergeladen wurden).

Das System optimiert die Übertragung von Sendungen, um um den Zustand des Systems zu optimieren. Daher ist die Lieferdauer von Übertragungen garantiert. Anwendungen, die eine Interprozesskommunikation mit niedriger Latenz benötigen, sollten gebundene Dienste in Betracht ziehen

Apps können sich für den Empfang bestimmter Broadcasts registrieren. Wenn eine Nachricht an alle gesendet wird, leitet das System Broadcasts automatisch an Apps weiter, die um diese Art von Übertragung zu empfangen.

Im Allgemeinen können Nachrichten an alle Apps als Nachrichtensystem verwendet werden. und außerhalb des normalen User Flows. Achten Sie jedoch darauf, die Möglichkeit, auf Broadcasts zu reagieren und Jobs im Hintergrund auszuführen, kann die Systemleistung beeinträchtigen.

Informationen zu Systemnachrichten

Das System sendet bei verschiedenen Systemereignissen automatisch Broadcasts, z. B. wenn das System den Flugmodus ein- und ausschaltet. System Broadcasts werden an alle Apps gesendet, die den Empfang von .

Die Broadcast-Nachricht selbst ist in einen Intent umschlossen. Objekt, dessen Aktionsstring das eingetretene Ereignis identifiziert (z. B. android.intent.action.AIRPLANE_MODE). Der Intent kann auch zusätzliche Informationen in einem zusätzlichen Feld. Zum Beispiel könnte das Flugzeug Der Modus-Intent enthält ein boolesches Extra, das angibt, ob ein Flugzeug Modus ist aktiviert.

Weitere Informationen zum Lesen von Intents und zum Abrufen des Aktionsstrings aus eines Intents, siehe Intents und Intents Filter:

Eine vollständige Liste aller System-Broadcast-Aktionen finden Sie in der BROADCAST_ACTIONS.TXT-Datei im Android SDK. Jede Übertragungsaktion hat ein Konstante ein, die damit verknüpft ist. Zum Beispiel ist der Wert der Konstante ACTION_AIRPLANE_MODE_CHANGED ist android.intent.action.AIRPLANE_MODE. Dokumentation für jede Übertragungsaktion im zugehörigen Feld für die Konstante verfügbar.

Änderungen an System-Broadcasts

Im Zuge der Weiterentwicklung der Android-Plattform ändert sich regelmäßig die Art und Weise, wie das System verhalten. Beachte die folgenden Änderungen, damit alle Versionen von Android unterstützt werden können.

Android 14

Solange sich Apps in einem zwischengespeicherten Bundesstaat, Broadcast-Zustellung ist optimiert für Systemzustand. Weniger wichtiges System sendet beispielsweise da ACTION_SCREEN_ON sind verzögert, während sich die Anwendung im Cache-Status befindet. Sobald die Anwendung aus dem Cache in einen aktiven Prozess Lebenszyklus, liefert das System verzögerte Übertragungen.

Wichtige Übertragungen, die in der Manifest vorübergehend Apps aus dem Cache entfernt. für die Auslieferung angeben.

Android 9

Ab Android 9 (API-Level 28) NETWORK_STATE_CHANGED_ACTION keine Informationen über den Standort oder die Person, Daten zu identifizieren.

Wenn Ihre App auf einem Gerät mit Android 9 oder höher installiert ist, System-Broadcasts vom WLAN enthalten keine SSIDs, BSSIDs, oder Scanergebnisse. Diese Informationen erhalten Sie unter getConnectionInfo() .

Android 8.0

Ab Android 8.0 (API-Level 26) schreibt das System zusätzliche Einschränkungen für durch Manifest deklarierte Empfänger.

Wenn deine App auf Android 8.0 oder höher ausgerichtet ist, kannst du das Manifest nicht für folgende Zwecke verwenden: einen Empfänger für die meisten impliziten Broadcasts (Übertragungen, die nicht speziell für Ihre App). Sie können weiterhin ein kontextregistrierten Empfänger Nutzer Ihre App aktiv verwenden.

Android 7.0

Android 7.0 (API-Level 24) und höher senden das folgende System nicht Nachrichten an alle:

Apps, die auf Android 7.0 und höher ausgerichtet sind, müssen außerdem die CONNECTIVITY_ACTION-Übertragung registrieren. mit registerReceiver(BroadcastReceiver, IntentFilter). Die Angabe eines Empfängers im Manifest funktioniert nicht.

Broadcasts werden empfangen

Apps können Broadcasts auf zwei Arten empfangen: über von Manifest deklarierte Empfänger und kontextregistrierten Empfängern.

Durch Manifest deklarierte Empfänger

Wenn du in deinem Manifest einen Übertragungsempfänger deklarierst, startet das System deinen (sofern die App noch nicht ausgeführt wird), wenn die Übertragung gesendet wird.

So deklarierst du einen Übertragungsempfänger im Manifest:

  1. Geben Sie den <receiver> an. -Element im Manifest Ihrer App.

    <!-- 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 abgeleitete Klassen von BroadcastReceiver und implementieren Sie onReceive(Context, Intent). Die Broadcast-Receiver in den folgenden Beispielprotokollen und zeigt den Inhalt an der Übertragung:

    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 Bindung der Ansicht zu aktivieren, Konfigurieren Sie viewBinding auf Ihrer Modulebene. build.gradle-Datei herunter.

Der Systempaketmanager registriert den Empfänger, wenn die App installiert wird. Der Empfänger wird zu einem separaten Einstiegspunkt in Ihre App, was bedeutet, dass das System die App starten und die Übertragung senden kann, wenn die App derzeit ausgeführt wird.

Das System erstellt eine neue BroadcastReceiver-Komponente -Objekt zur Verarbeitung jeder empfangenen Übertragung. Dieses Objekt ist nur gültig für die Dauer des Aufrufs von onReceive(Context, Intent). Sobald Sie Ihren Code gibt diese Methode zurück, betrachtet das System die Komponente nicht mehr aktiv ist.

Kontextregistrierte Empfänger

Kontextregistrierte Empfänger empfangen Broadcasts, Kontext gültig ist. Wenn Sie sich z. B. innerhalb eines Activity erhalten Sie Broadcasts, solange die Aktivität nicht gelöscht wird. Wenn Sie erhalten Sie Broadcasts, solange die App ausgeführt wird.

So registrieren Sie einen Empfänger mit einem Kontext:

  1. Fügen Sie in der Build-Datei auf Modulebene Ihrer App Version 1.9.0 oder höher von der AndroidX Core-Bibliothek:

    Groovy

    dependencies {
        def core_version = "1.15.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"
        // 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-alpha02"
    }

    Kotlin

    dependencies {
        val core_version = "1.15.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")
        // 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-alpha02")
    }
  2. Instanz von erstellen BroadcastReceiver:

    Kotlin

    val br: BroadcastReceiver = MyBroadcastReceiver()
    

    Java

    BroadcastReceiver br = new MyBroadcastReceiver();
    
  3. Instanz von erstellen IntentFilter:

    Kotlin

    val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
    

    Java

    IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
    
  4. Legen Sie fest, ob der Übertragungsempfänger exportiert und sichtbar sein soll für andere Apps auf dem Gerät. Wenn dieser Empfänger auf gesendete Nachrichten wartet aus dem System oder aus anderen Apps – selbst aus Ihren eigenen Apps – Flag RECEIVER_EXPORTED. Wenn dieser Empfänger stattdessen nur Broadcasts, die von deiner App gesendet werden, verwende 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 über folgenden Anruf: registerReceiver():

    Kotlin

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

    Java

    ContextCompat.registerReceiver(context, br, filter, receiverFlags);
    
  6. Wenn du keine Nachrichten an alle mehr erhalten möchtest, ruf unregisterReceiver(android.content.BroadcastReceiver) an. Heben Sie die Registrierung des Empfängers auf, wenn Sie ihn nicht mehr benötigen. Kontext nicht mehr gültig ist.

    Achten Sie darauf, wo Sie den Empfänger registrieren und abmelden: Wenn Sie beispielsweise einen Empfänger in onCreate(Bundle) mit dem Kontext der Aktivität registrieren, sollte es in onDestroy() abmelden, um zu verhindern, dass der Empfänger aus dem Aktivitätskontext gerät. Wenn Sie sich registrieren an einen Empfänger in onResume(), sollten Sie können Sie sie in onPause() abmelden, und registriert haben. Wenn Sie keine Broadcasts empfangen möchten, Dadurch wird unnötiger Systemaufwand reduziert. Das sollten Sie nicht tun: sich in onSaveInstanceState(Bundle) abmelden, da dies nicht aufgerufen wird, wenn der Nutzer in den Verlaufsstapel zurückkehrt.

Auswirkungen auf den Prozessstatus

Ob Ihr BroadcastReceiver funktioniert oder nicht auf den enthaltenen Prozess auswirkt, wodurch seine zum Absterben des Systems. Ein Vordergrundprozess führt die Methode onReceive() eines Empfängers aus. Die führt das System den Prozess aus, außer unter extremer Speicherauslastung.

BroadcastReceiver wird nach onReceive() deaktiviert. Der Host des Empfängers ist nur so wichtig wie die App-Komponenten. Wenn dieser Prozess nur ein durch ein Manifest deklarierter Empfänger (häufig für Apps, die der Nutzer noch nie oder nicht mit ihnen interagiert haben), beendet das System das Gerät möglicherweise nach onReceive(), für andere kritische Prozesse zur Verfügung.

Daher sollten Übertragungsempfänger keine Hintergrundthreads mit langer Ausführungszeit initiieren. Das System kann den Prozess zur Rückforderung jederzeit nach onReceive() beenden Arbeitsspeicher, wodurch der erstellte Thread beendet wird. Um den Prozess am Laufen zu halten, planen Sie JobService vom Empfänger über die JobScheduler damit das System weiß, dass der Prozess noch funktioniert. Weitere Informationen finden Sie in der Übersicht über die Hintergrundarbeit.

Broadcasts werden gesendet

Android bietet drei Möglichkeiten zum Senden von Nachrichten an Apps:

  • Das sendOrderedBroadcast(Intent, String) -Methode Broadcasts an jeweils nur einen Empfänger sendet. Bei Ausführung jedes Empfängers wiederum kann ein Ergebnis an den nächsten Empfänger weitergegeben werden. Übertragung vollständig abbrechen, sodass sie nicht an andere Empfänger. Die Reihenfolge, in der die Empfänger ausgeliefert werden, kann mit dem android:Priority-Attribut des übereinstimmenden Intent-Filters. mit der werden in beliebiger Reihenfolge ausgeführt.
  • Die Methode sendBroadcast(Intent) sendet die in einer undefinierten Reihenfolge an alle Empfänger gesendet werden. Dies wird als „Normal“ bezeichnet. Nachricht an alle. Dies ist effizienter, bedeutet aber, dass Empfänger die Daten von anderen Empfängern empfangene Daten verbreiten brich die Übertragung ab.

Das folgende Code-Snippet zeigt, wie ein Broadcast gesendet wird, indem ein Intent und Aufruf von 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);

Die Nachricht an alle ist in ein Intent-Objekt umschlossen. Der Aktionsstring des Intents muss die Syntax des Java-Paketnamens der App und um das Übertragungsereignis eindeutig zu identifizieren. Sie können zusätzliche Informationen mit putExtra(String, Bundle) hinzu. Sie können eine Übertragung auch auf eine Reihe von Apps in derselben Organisation beschränken. setPackage(String) für den Intent aufrufen.

Broadcasts mit Berechtigungen einschränken

Mit Berechtigungen kannst du Broadcasts auf die Apps beschränken, die bestimmte Berechtigungen. Sie können Einschränkungen für den Absender oder Empfänger einer Nachricht an alle.

Senden mit Berechtigungen

Wenn Sie sendBroadcast(Intent, String) anrufen oder sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) können Sie einen Berechtigungsparameter. Nur Empfänger, die diese Berechtigung mit das -Tag in ihrem Manifest verwenden (und anschließend wurde der falls es gefährlich ist, die Übertragung empfangen können. Beispiel: Der Parameter Der folgende Code sendet eine Nachricht an alle:

Kotlin

sendBroadcast(Intent(BluetoothDevice.ACTION_FOUND),
              Manifest.permission.BLUETOOTH_CONNECT)

Java

sendBroadcast(new Intent(BluetoothDevice.ACTION_FOUND),
              Manifest.permission.BLUETOOTH_CONNECT)

Um die Übertragung zu empfangen, muss die empfangende App die Berechtigung folgendermaßen anfordern: (siehe unten):

<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>

Sie können entweder eine vorhandene Systemberechtigung wie BLUETOOTH_CONNECT oder definieren Sie eine benutzerdefinierte Berechtigung mit dem <permission>-Element. Für Informationen zu Berechtigungen und Sicherheit im Allgemeinen finden Sie im System Berechtigungen:

Empfangen mit Berechtigungen

Wenn Sie bei der Registrierung eines Übertragungsempfängers einen Berechtigungsparameter angeben (entweder mit registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) oder in <receiver>-Tag in Ihrem Manifest) angezeigt werden, sind nur Sender, die die Berechtigung mit dem <uses-permission>-Tag in ihrem Manifest (und haben dann die Berechtigung erhalten, falls sie können einen Intent an den Empfänger senden.

Angenommen, Ihre empfangende App hat einen durch Manifest deklarierten Empfänger als (siehe unten):

<receiver android:name=".MyBroadcastReceiver"
          android:permission="android.permission.BLUETOOTH_CONNECT">
    <intent-filter>
        <action android:name="android.intent.action.ACTION_FOUND"/>
    </intent-filter>
</receiver>

Oder die 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 );

Anschließend muss die sendende App Broadcasts an diese Empfänger senden wie unten gezeigt die Berechtigung anzufordern:

<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>

Sicherheitsüberlegungen und Best Practices

Im Folgenden finden Sie einige Sicherheitsaspekte und Best Practices für das Senden und Broadcasts empfangen:

  • Wenn viele Apps sich für den Empfang derselben Übertragung in ihrem Zuhause registriert haben, kann das System viele Apps starten, was zu einer erheblichen Einfluss auf die Geräteleistung und die Nutzererfahrung. Um dies zu vermeiden sollten Sie die Kontextregistrierung gegenüber der Manifestdeklaration verwenden. Manchmal erzwingt das Android-System selbst die Verwendung kontextregistrierter Empfänger. Beispielsweise wird die Übertragung CONNECTIVITY_ACTION nur kontextregistrierten Empfängern.

  • 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 Übertragung registriert. Es gibt drei Möglichkeiten, festzulegen, wer deine Nachrichten empfangen kann:

    • Du kannst beim Senden eines Broadcasts eine Berechtigung festlegen.
    • Unter Android 4.0 und höher können Sie eine package mit setPackage(String) beim Senden einer Nachricht an alle. Das System beschränkt die Übertragung auf die Apps, die mit dem Paket übereinstimmen.
  • Wenn Sie einen Empfänger registrieren, kann jede App potenziell schädliche Daten senden an den Receiver Ihrer App gesendet. Es gibt mehrere Möglichkeiten, Nachrichten, die Ihre App empfängt:

    • Sie können bei der Registrierung eines Übertragungsempfängers eine Berechtigung angeben.
    • Für durch ein Manifest deklarierte Empfänger können Sie die android:exported Attribut auf „false“ setzen im Manifest. Der Empfänger erhält keine von Quellen außerhalb der App.
  • Der Namespace für Broadcast-Aktionen ist global. Achten Sie darauf, dass Aktionsnamen und andere Strings in einem Namespace geschrieben sind, der Ihnen gehört. Andernfalls können Sie versehentlich mit anderen Apps in Konflikt stehen.

  • Da die Methode onReceive(Context, Intent) eines Empfängers Hauptthreads hat, sollte er schnell ausgeführt werden und zurückgegeben werden. Bei Bedarf lang andauernde Arbeit ausführen, sollten Sie vorsichtig sein, wenn Sie Threads erzeugen oder da das System den gesamten Prozess nach einer onReceive() kehrt zurück. Weitere Informationen finden Sie unter Auswirkung auf Prozesse. State Um lang andauernde Arbeiten auszuführen, empfehlen:

    • goAsync() wird angerufen in deinem onReceive()-Methode des Empfängers und übergibt BroadcastReceiver.PendingResult an einen Hintergrundthread. Dadurch bleibt die Übertragung nach der Rückkehr von onReceive() aktiv. Aber selbst bei diesem Ansatz erwartet das System, dass Sie mit die Übertragung sehr schnell (weniger als 10 Sekunden). Es ermöglicht Ihnen, zu einem anderen Thread wechseln, um Störungen im Hauptthread zu vermeiden.
    • Einen Job mit JobScheduler planen Weitere Informationen erhalten Sie unter Intelligenter Job Planung.
  • Starten Sie keine Aktivitäten von Übertragungsempfängern, da die Nutzererfahrung ist irritierend; vor allem, wenn es mehr als einen Empfänger gibt. Überlegen Sie sich stattdessen, Durch Anzeigen einer Benachrichtigung