Broadcast Receiver in Android

Android Entwicklung: Grundlagen Logo
Was ist ein Broadcast Receiver?

Bei einem Broadcast Receiver handelt es sich um eine App-Komponente ohne Benutzeroberfläche, die auf Broadcast-Nachrichten (Broadcast-Intents) reagiert, die vom Android-System oder von App-Komponenten (z.B. Services, Activites) verschickt werden.

Info: Allgemein versteht man in der Informatik und Nachrichtentechnik unter einer Broadcast-Nachricht einen Rundruf ohne spezifischen Empfänger, der an alle Teilnehmer eines Netzwerks versendet wird. 

Jeder Broadcast Receiver nimmt eine versendete Broadcast-Nachricht entgegen und reagiert geeignet darauf. Somit übernimmt jeder Receiver eine wichtige Rolle bei der Kommunikation zwischen

  • System und App
  • Komponenten verschiedener Apps
  • Komponenten einer App

Broadcast Receiver (Übersicht der Kommunikation)

 

Was ist ein Broadcast-Intent?
Ein (Broadcast-)Intent ist eine Hintergrund-Operation, die vom Benutzer normalerweise nicht wahrgenommen wird. Allgemein gibt es in Android insgesamt drei verschiedene Intent-Arten, die zu folgenden Zwecken verwendet werden:

-> Expliziter Intent: Zum Starten einer App-Komponente (z.B. Activity)
-> Impliziter Intent: Zum Starten einer Aktion (z.B. Anzeigen von Daten)
-> Broadcast-Intent: Zum Versenden von Broadcast-Nachrichten 

Info: Wir beschäftigen uns in diesem Beitrag lediglich mit den Broadcast-Intents und gehen nicht näher auf die anderen beiden Intents ein, da diese für das Verständnis von Broadcasts unwichtig sind. Sofern du jedoch weitergehende Informationen zu den anderen beiden Intent-Arten möchtest, empfehlen wir dir unseren Artikel "Intents in Android".  

 

Welche Arten von Broadcast-Intents gibt es?
Es gibt in Android zwei Arten von Broadcast-Intents, auf die Broadcast-Receiver reagieren können:

-> Broadcast-Intents vom System: Broadcasts, die vom System (Android) geliefert werden
-> Broadcast-Intents von Apps: Broadcasts, die von einer App geliefert werden

System-Broadcast-Intents: 
Dieser Broadcast-Typ wird von Android selbst geliefert, wenn ein bestimmtes System-Ereignis auftritt. Es gibt unter Android eine ganze Reihe an verschiedenen Events, zu denen unter anderem die folgenden gehören:

Event: Zeitzone hat sich geändert 
System-Broadcast: ACTION_TIMEZONE_CHANGED

Event: Externe Stromversorgung wurde angeschlossen
System-Broadcast: ACTION_POWER_CONNECTED

Event: Batteriestand ist niedrig
System-Broadcast: ACTION_BATTERY_LOW


App-Broadcast-Intents: 
Bei diesem Broadcast-Typ werden die Broadcast-Intents durch Apps verschickt. Als Android-Entwickler kannst du diesen Broadcast-Typ verwenden, um z.B. anderen Apps mitzuteilen, dass Daten heruntergeladen wurden und nun für diese Apps zur Verfügung stehen.

Für das Versenden eines Broadcast-Intents kannst du folgende Methoden verwenden:

 -> sendBroadcast(Intent): Über diese Methode werden Broadcast-Nachrichten in einer ungeordneten Reihenfolge an alle Receiver verschickt. 

-> sendOrderedBroadcast(Intent, String): Über diese Methode werden Broadcast-Nachrichten nacheinander an jeweils nur einen Receiver verschickt. 

-> LocalBroadcastManager.sendBroadcast(): Über diese Methode der Klasse "LocalBroadcastManager" werden Broadcast-Nachrichten nur an Receiver verschickt, die sich in der gleichen App wie der Broadcast-Sender befinden.

Beispiel: 
public void versendeBroadcast() {
   Intent intent = new Intent(); // Neuen Intent anlegen      
   /* 
   Der Methode "setAction()" wird ein String übergeben, der für die Identifizierung des
   Broadcast-Events verwendet wird. Für diesen String wird normalerweise
   der vollständige Java-Paket-Name der App verwendet und muss eindeutig sein. 
   */
   intent.setAction("com.example.superindy.mybroadcast"); 
   sendBroadcast(intent); // Intent mit Broadcast-Nachricht an alle Receiver verschicken
}

 

Wie wird ein Broadcast Receiver implementiert?

Wie bei allen App-Komponenten üblich, ist es auch beim Broadcast Receiver vor der Verwendung verpflichtend, diesen zu registrieren. Dabei muss der Receiver allerdings nicht unbedingt in das Manifest einer App eingetragen werden, sondern kann alternativ auch über eine Methode registriert werden.

Nachfolgend zeigen wir dir beide Registrierungsvarianten mit jeweils einem Beispiel und der zugehörigen Implementierung des Broadcast Receivers:

Statische Registrierung: 
Bei der statischen Registrierung wird der Broadcast Receiver mittels des "receiver"-Elements in das "Android-Manifest" eingetragen. Sofern der Broadcast Receiver auf diese Weise registriert wird, startet Android automatisch die App (falls nicht bereits gestartet), sobald eine Broadcast-Nachricht versendet wird. Wenn du nicht möchtest, dass dein Receiver auf alle möglichen Broadcast-Nachrichten reagiert, kannst du über einen "Intent-Filter" spezifizieren, dass der Receiver nur auf bestimmte Broadcast-Intents lauscht. Das "receiver"-Element kann dabei unter anderem folgende Attribute enthalten:

-> name: Der Name der Klasse, die den Receiver implementiert
-> enabled: Legt fest, ob der Receiver vom System instanziiert werden kann oder nicht
-> exported: Legt fest, ob der Receiver Broadcasts von außerhalb der App empfangen kann

Beispiel-Registrierung im Manifest:
<receiver
      android:name=".MyReceiver"
      android:enabled="true" //"True" bedeutet, dass Android den Receiver instanziieren kann
      android:exported="true"> //"True" bedeutet, dass der Receiver auf externe Broadcasts reagiert
      <intent-filter>
            <action android:name="com.example.superindy.mybroadcast" />
      </intent-filter>
</receiver>

Beispiel-Erklärung:
Bei der obigen statischen Registrierung wird in der "AndroidManifest.xml"-Datei zwischen den "Application"-Tags das "receiver"-Element eingetragen und die Attribute "name", "enabled" und "exported" angelegt. Mit dem "intent-filter"-Element spezifizierst du, auf welche Broadcast-Nachrichten (z.B. Aktionen) der Receiver letztendlich reagieren soll. In unserem Beispiel oben haben wir etwa festgelegt, dass der Receiver auf das benutzerdefinierte App-Event "com.example.superindy.mybroadcast" reagieren soll.

Implementierung: 
Nun musst du eine Klasse schreiben, die einen Broadcast-Intent empfangen kann. Für die Implementierung des Receivers leitest du zunächst über das Schlüsselwort "extends" von der Oberklasse "BroadcastReceiver" ab und implementierst anschließend die "onReceive()"-Methode. Dieser Methode werden der aktuelle App-Kontext und der Broadcast-Intent übergeben, wobei du diese beiden Parameter dann innerhalb der "onReceive()"-Methode weiterverarbeiten kannst.

Beispiel-Implementierung für Broadcast-Receiver:
public class MyReceiver extends BroadcastReceiver {

      @Override
      public void onReceive(Context context, Intent intent) {
            /*
            Wir zeigen auf der Benutzeroberfläche einen Toast an, sobald ein Broadcast
            angekommen ist.
            */
            Toast.makeText(context, "Broadcast-Intent angekommen!", Toast.LENGTH_LONG).show();
      }
}

 

Dynamische Registrierung:
Du kannst einen Broadcast Receiver auch innerhalb einer Activity dynamisch über Java registrieren und das Android-Manifest komplett unberührt lassen. Dafür musst du die folgenden beiden Methoden verwenden:

-> registerReceiver(): Zur Registrierung eines Broadcast-Receivers
-> unregisterReceiver(): Zur Abmeldung eines zuvor registrierten Broadcast Receivers

Beispiel-Registrierung in der MainActivity:
public class MainActivity extends AppCompatActivity {

    MyReceiver myreceiver; //Receiver-Objekt deklarieren
    IntentFilter intentfilter; //IntentFilter anlegen

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //Receiver instanziieren
        myreceiver = new MyReceiver(); 
        //IntentFilter-Objekt instanziieren
        intentfilter = new IntentFilter(Intent.ACTION_BATTERY_LOW);
    }

    @Override
    protected void onResume() {
        super.onResume();
        //Receiver- und Intent-Filter-Objekt an "registerReceiver"-Methode übergeben
        registerReceiver(myreceiver, intentfilter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        //Die Receiver-Registrierung wieder aufheben
        unregisterReceiver(myreceiver);
    }    
}

Beispiel-Erklärung: 
In unserem Beispiel oben legen wir in der "MainActivity" zunächst zwei Objekte für den Receiver "myreceiver" und den Intent-Filter "intentfilter" an. Danach instanziieren wir beide Objekte innerhalb der "onCreate()"-Methode, wobei wir dem Konstruktor des Intent-Filters einen Broadcast-Intent ("ACTION_BATTERY_LOW") mitgeben. Die Registrierung des Receivers erfolgt bei uns in der "onResume()"-Methode, da wir den Broadcast-Receiver nur dann benötigen, wenn die Activity sichtbar wird. Die Aufhebung der Receiver-Registrierung wird demzufolge bei uns in der "onPause()"-Methode vorgenommen, da wir möchten, dass der Receiver abgemeldet wird, sobald die Activity von der Oberfläche verschwindet.

Implementierung:
Die Implementierung des Broadcast-Receivers erfolgt hier exakt auf die gleiche Weise wie zuvor bei der statischen Registrierung. Sofern du also nochmal wissen möchtest, wie ein Receiver konkret implementiert wird, musst du nach oben scrollen.

 

Wie kann die Sicherheit bei Broadcasts erhöht werden?

Die Kommunikation über Broadcast-Intents birgt verständlicherweise Risiken, da es sich hier schließlich um einen Nachrichtenaustausch zwischen verschiedenen Apps handelt. Es soll deswegen nicht jede installierte App auf deinem Android-Gerät auf Broadcast-Intents lauschen können oder dein Broadcast-Receiver soll nicht auf jede Nachricht reagieren. Aus diesem Grund musst du dir also unbedingt dieser Risiken bewusst sein und dich an mehrere Ratschläge halten. Ein paar der wichtigsten Ratschläge möchten wir dir nachfolgend kurz vorstellen, wobei du sowohl beim Versenden als auch beim Empfangen von Broadcasts etwas tun kannst:

LocalBroadcastManager: 
Ein LocalBroadcastManager ermöglicht dir das Senden und Empfangen von Broadcast-Intents innerhalb eines einzigen Prozesses bzw. einer einzigen App, so dass du dir keine Sorgen um die appübergreifende Sicherheit machen musst. Sofern du also Broadcasts nur innerhalb derselben App verschicken musst, empfehlen wir dir dringend diese Klasse zu verwenden. 

Versenden eines lokalen Broadcast-Intents:
Besorge dir zunächst eine Instanz der "LocalBroadcastManager"-Klasse, indem du die "getInstance()"-Methode aufrufst und mit "this" den App-Kontext übergibst. Verwende nun diese Instanz, um damit die "sendBroadcast()"-Methode aufzurufen und als Parameter einen beliebigen Intent zu übergeben.

Beispiel: 
Intent intent = new Intent();
intent.setAction(Intent.ACTION_BATTERY_LOW);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

Registrierung eines lokalen Broadcast-Receivers: 
Die Registrierung eines lokalen Broadcast-Receivers erfolgt ausschließlich dynamisch über Java-Code. Hole dir also zunächst wieder über die "getInstance()"-Methode eine Instanz der "LocalBroadcastManager"-Klasse und übergebe dieser Methode mit "this" den App-Kontext. Verwende nun diese Instanz, um damit die "registerReceiver()"-Methode aufzurufen und als Parameter den Receiver und den Intent-Filter zu übergeben.

Beispiel: 
MyReceiver myreceiver = new MyReceiver(); 
IntentFilter intentfilter = new IntentFilter(Intent.ACTION_BATTERY_LOW);
LocalBroadcastManager.getInstance(this).registerReceiver(myreceiver, intentfilter);

 

Exported-Attribut auf "false" stellen 
Wenn du den Broadcast-Receiver über die "AndroidManifest.xml"-Datei statisch registrierst, kann jede andere App im System Broadcasts an deinen Receiver senden, egal ob du Intent-Filter gesetzt hast oder nicht. Um nun zu verhindern, dass andere Apps an deinen Broadcast-Receiver Broadcasts versenden können, setze einfach das Attribut "exported" in der Manifest-Datei auf "false".

ACHTUNG: Dieser Tipp sollte nur dann befolgt werden, wenn du wirklich nur Broadcast-Intents deiner eigenen App empfangen möchtest und keine Broadcasts von anderen Apps oder dem System!

Beispiel: 
<receiver
    android:name=".MyReceiver"
    android:enabled="true"
    android:exported="false"> //Setze dieses Attribut auf den Wert "false"
</receiver>

 

Zugriffsberechtigungen verwenden
Eine weitere Möglichkeit die Sicherheit bei der Broadcast-Kommunikation zu erhöhen, ist die Verwendung von Zugriffsberechtigungen bei Broadcast-Sendern und Broadcast-Receivern. Wie diese Berechtigungen jeweils gesetzt werden, zeigen wir dir in den nachfolgenden Abschnitten.

Zugriffsberechtigung für Broadcast-Receiver: 
Um eine Berechtigung für den Empfang eines Broadcast-Intents zu erzwingen, musst du in der "AndroidManifest.xml"-Datei eine entsprechende Berechtigung angeben. Dabei legst du über dem "Application"-Tag zunächst die Deklaration der Berechtigung fest und erzwingst danach im "Receiver"-Element diese Zugriffsberechtigung.

Beispiel-Eintrag in Android-Manifest: 
<manifest ...>
//Deklaration der Zugriffsberechtigung
<permission android:name="neuedomain.example.superindy.mypermission" />

<receiver
    android:name=".MyReceiver"
    android:enabled="true"
    android:exported="true"> 
    //Erzwingen der Berechtigung für die Übermittlung von Broadcasts an diesen Receiver
    android:permission="neuedomain.example.superindy.mypermission">
</receiver>

</ manifest>


Zugriffsberechtigung für Broadcast-Sender: 
In derjenigen Activity, von der aus ein Broadcast-Intent losgeschickt wird, muss der Besitz einer Berechtigung erklärt werden. Nur dann kann ein Broadcast an den oben genannten Receiver gesendet werden. Um diesen Berechtigungs-Besitz zu erklären, trägst du das "uses-permission"-Element über dem "Application"-Tag in das Android-Manifest ein. 

Beispiel-Eintrag in Android-Manifest: 
<manifest ...>
<uses-permission android:name="neuedomain.example.superindy.mypermission" />
</ manifest>