Le app per Android possono inviare o ricevere annunci dal sistema Android e altre app per Android, simili pubblicare-sottoscrivere pattern di progettazione. Queste trasmissioni vengono inviate quando si verifica un evento di interesse. Ad esempio, il sistema Android invia annunci quando vari eventi di sistema quando il sistema si avvia o il dispositivo inizia a ricaricarsi. App Possono anche inviare annunci personalizzati, ad esempio per informare altre app di qualcosa a cui potrebbero essere interessati (ad esempio, alcuni nuovi dati sono scaricati).
Il sistema ottimizza la distribuzione delle trasmissioni per mantenere integrità ottimale del sistema. Pertanto, i tempi di consegna delle trasmissioni garantito. Le app che richiedono una comunicazione tra processi a bassa latenza prendi in considerazione i servizi associati.
Le app possono registrarsi per ricevere trasmissioni specifiche. Quando viene inviata una trasmissione, il sistema instrada automaticamente le trasmissioni alle app a cui è abbonato ricevere quel particolare tipo di trasmissione.
In generale, le trasmissioni possono essere utilizzate come sistema di messaggistica tra app. e al di fuori del normale flusso utente. Bisogna però fare attenzione a non abusare l'opportunità di rispondere alle trasmissioni ed eseguire job in background che può contribuire a rallentare le prestazioni del sistema.
Informazioni sulle trasmissioni di sistema
Il sistema invia automaticamente gli annunci quando si verificano vari eventi di sistema, ad esempio quando il sistema attiva e disattiva la modalità aereo. Sistema vengono inviati a tutte le app iscritte per ricevere i .
Il messaggio broadcast stesso è aggregato in Intent
la cui stringa di azione identifica l'evento che si è verificato (ad esempio
android.intent.action.AIRPLANE_MODE
). L'intento può anche includere
informazioni aggiuntive raggruppate nel relativo campo aggiuntivo. Ad esempio, l'aereo
l'intent mode include un extra booleano che indica se la modalità Aereo
La modalità è attiva.
Per ulteriori informazioni su come leggere gli intent e ottenere la stringa di azione da per intenti, consulta Intent Filtri.
Per un elenco completo delle azioni di trasmissione del sistema, consulta
BROADCAST_ACTIONS.TXT
nell'SDK Android. Ogni azione di trasmissione ha un
campo costante associato. Ad esempio, il valore della costante
ACTION_AIRPLANE_MODE_CHANGED
è
android.intent.action.AIRPLANE_MODE
. Documentazione per ogni azione di trasmissione
è disponibile nel relativo campo della costante associata.
Modifiche alle trasmissioni di sistema
Con l'evoluzione della piattaforma Android, cambia periodicamente il modo in cui il sistema trasmette comportarsi. Tieni presente le modifiche che seguono per supportare tutte le versioni di Android.
Android 14
Mentre le app sono memorizzate nella cache
, la distribuzione della trasmissione
ottimizzate per l'integrità del sistema. Ad esempio, gli annunci di sistema meno importanti
come ACTION_SCREEN_ON
sono
differita quando l'app è in stato di cache. Una volta che l'app passa dalla cache
in un processo attivo
ciclo di vita, il sistema offre
eventuali trasmissioni differite.
Le trasmissioni importanti che sono dichiarate nel nel file manifest, di rimuovere temporaneamente le app per il caricamento.
Android 9
A partire da Android 9 (livello API 28), la funzionalità
NETWORK_STATE_CHANGED_ACTION
la trasmissione non riceve informazioni sulla posizione o sull'identità personale dell'utente
identificabili.
Inoltre, se la tua app è installata su un dispositivo con Android 9 o versioni successive:
le trasmissioni di sistema da Wi-Fi non contengono SSID, BSSID, connessioni
informazioni o i risultati della scansione. Per ottenere queste informazioni, chiama
getConnectionInfo()
.
Android 8.0
A partire da Android 8.0 (livello API 26), il sistema impone restrizioni sui destinatari dichiarati da manifest.
Se la tua app ha come target Android 8.0 o versioni successive, non puoi utilizzare il file manifest per dichiarare un ricevitore per la maggior parte delle trasmissioni implicite (le trasmissioni che non hanno come target specifica la tua app). Puoi comunque utilizzare un ricevitore registrato al contesto quando che l'utente sta utilizzando attivamente la tua app.
Android 7.0
Android 7.0 (livello API 24) e versioni successive non inviano il seguente sistema annunci:
Inoltre, le app destinate ad Android 7.0 e versioni successive devono registrare la trasmissione CONNECTIVITY_ACTION
utilizzando registerReceiver(BroadcastReceiver, IntentFilter)
.
La dichiarazione di un destinatario nel file manifest non funziona.
Ricezione di annunci
Le app possono ricevere annunci in due modi: tramite ricevitori dichiarati da un manifest e i destinatari registrati al contesto.
Destinatari dichiarati nei file manifest
Se dichiari un broadcast receiver nel tuo manifest, il sistema avvia il tuo (se non è già in esecuzione) quando viene inviata la trasmissione.
Per dichiarare un broadcast receiver nel manifest, segui questi passaggi:
Specifica il campo
<receiver>
nel file manifest dell'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>
I filtri per intent specificano le azioni di trasmissione a cui si registra il destinatario.
Sottoclasse
BroadcastReceiver
e implementaonReceive(Context, Intent)
. La nell'esempio che segue registra il broadcast receiver e ne mostra i contenuti della trasmissione: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(); } }
Per attivare l'associazione delle viste, configurare viewBinding a livello di modulo il file build.gradle.
Il gestore di pacchetti di sistema registra il ricevitore quando l'app è installata. Il destinatario diventa quindi un punto di accesso separato nella tua app, il che significa in modo che il sistema possa avviare l'app e trasmettere il broadcast se l'app non attualmente in esecuzione.
Il sistema crea un nuovo componente BroadcastReceiver
per gestire ogni trasmissione ricevuta. Questo oggetto è valido solo
per l'intera durata della chiamata a onReceive(Context, Intent)
. Una volta che il codice
da questo metodo, il sistema considera il componente non più
attivo.
Destinatari registrati al contesto
I ricevitori registrati al contesto ricevono le trasmissioni finché la loro registrazione
il contesto sia valido. Ad esempio, se ti registri all'interno di un
Activity
contesto, si ricevono trasmissioni purché l'attività non venga distrutta. Se
registrati con il contesto dell'applicazione, ricevi trasmissioni finché l'app
in esecuzione.
Per registrare un destinatario con un contesto, segui questi passaggi:
Nel file di build a livello di modulo dell'app, includi la versione 1.9.0 o una versione successiva di la libreria AndroidX Core:
Alla moda
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-alpha02" }
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-alpha02") }
Crea un'istanza di
BroadcastReceiver
:Kotlin
val br: BroadcastReceiver = MyBroadcastReceiver()
Java
BroadcastReceiver br = new MyBroadcastReceiver();
Crea un'istanza di
IntentFilter
:Kotlin
val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
Java
IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
Scegli se il broadcast receiver deve essere esportato e visibile a altre app sul dispositivo. Se questo ricevitore sta ascoltando gli annunci inviati dal sistema o da altre app, anche da altre app di tua proprietà, usa
RECEIVER_EXPORTED
flag. Se invece questo ricevitore ascolta solo annunci inviati dalla tua app, usa il 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; }
Registra il destinatario chiamando
registerReceiver()
:Kotlin
ContextCompat.registerReceiver(context, br, filter, receiverFlags)
Java
ContextCompat.registerReceiver(context, br, filter, receiverFlags);
Per interrompere la ricezione degli annunci, chiama
unregisterReceiver(android.content.BroadcastReceiver)
. Assicurati di annullare la registrazione del destinatario quando non ti serve più o il contesto non è più valido.Fai attenzione a dove ti registri e annulli la registrazione del destinatario, Ad esempio, se registri un destinatario in
onCreate(Bundle)
utilizzando il contesto dell'attività, dovrebbe annullare la sua registrazione inonDestroy()
per evitare che il destinatario venga divulgato fuori dal contesto dell'attività. Se ti registri ricevitore inonResume()
, annulla la sua registrazione inonPause()
per evitare registrandolo più volte (se non vuoi ricevere annunci quando sono in pausa, per ridurre l'overhead superfluo del sistema). Azioni sconsigliate annulla registrazione inonSaveInstanceState(Bundle)
, perché non viene chiamato se l'utente torna indietro nell'elenco della cronologia.
Effetti sullo stato del processo
Se BroadcastReceiver
sta funzionando o non influisce sul processo contenuto, il che può alterare i suoi
probabilità di uccidere i sistemi. Un processo in primo piano esegue il metodo onReceive()
di un destinatario. La
di sistema esegue il processo, tranne in caso di estrema pressione di memoria.
Il BroadcastRicevir viene disattivato dopo il giorno onReceive()
. L'host del destinatario
è importante solo quanto i componenti dell'app. Se questo processo ospita solo
un ricevitore dichiarato da manifest (si verifica frequentemente per le app che l'utente non ha mai
o non ha interagito di recente), il sistema potrebbe terminarlo dopo onReceive()
per
e le risorse disponibili per altri processi più critici.
Di conseguenza, i broadcast receiver non dovrebbero avviare thread in background a lunga esecuzione.
Il sistema può interrompere la procedura in qualsiasi momento dopo il giorno onReceive()
per la rivendicazione
memoria, terminando il thread creato. Per mantenere attivo il processo, pianifica una
JobService
dal destinatario utilizzando il JobScheduler
in modo che il sistema sappia che la procedura è ancora in corso.
Panoramica del lavoro in background fornisce ulteriori dettagli.
Invio di annunci
Android offre alle app tre modi per inviare annunci:
sendOrderedBroadcast(Intent, String)
invia annunci a un ricevitore alla volta. Quando ogni ricevitore esegue a sua volta, può propagare un risultato al ricevitore successivo oppure interrompere completamente la trasmissione in modo che non venga passata ad altri o ricevitori. L'ordine di esecuzione dei ricevitori può essere controllato con l'attributo android:Priority del filtro per intent corrispondente; con il la stessa priorità verrà eseguita in un ordine arbitrario.- Il metodo
sendBroadcast(Intent)
invia trasmette a tutti i ricevitori in un ordine indefinito. Questo fenomeno è chiamato Trasmetti. Questa modalità è più efficiente, ma significa che i destinatari non possono leggere i risultati da altri ricevitori, propagare i dati ricevuti dalla trasmissione interrompere la trasmissione.
Il seguente snippet di codice mostra come inviare un annuncio creando un
Intent e chiamata a 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);
Il messaggio broadcast è aggregato in un oggetto Intent
.
La stringa di azione dell'intent deve fornire la sintassi del nome del pacchetto Java dell'app e
a identificare in modo univoco l'evento di trasmissione. Puoi allegare ulteriori informazioni
all'intent con putExtra(String, Bundle)
.
Puoi anche limitare una trasmissione a un insieme di app nella stessa organizzazione
chiamando setPackage(String)
per l'intent.
Limitazione delle trasmissioni con autorizzazioni
Le autorizzazioni ti consentono di limitare le trasmissioni all'insieme di app che contengono alcune autorizzazioni. Puoi applicare restrizioni al mittente o ricevente di un annuncio.
Invio con autorizzazioni
Quando chiami sendBroadcast(Intent, String)
o
sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
, puoi specificare
parametro di autorizzazione. Solo i destinatari che hanno richiesto l'autorizzazione con
il tag
Kotlin
sendBroadcast(Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
Java
sendBroadcast(new Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
Per ricevere la trasmissione, l'app ricevente deve richiedere l'autorizzazione in quanto come mostrato di seguito:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
Puoi specificare un'autorizzazione di sistema esistente, come
BLUETOOTH_CONNECT
oppure definisci un'autorizzazione personalizzata
Elemento <permission>
. Per
informazioni sulle autorizzazioni e sulla sicurezza in generale, consulta le Informazioni sul
Autorizzazioni.
Ricezione con autorizzazioni
Se specifichi un parametro di autorizzazione durante la registrazione di un broadcast receiver
(con registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
o in
Tag <receiver>
in
), solo gli emittenti che hanno richiesto l'autorizzazione con il
Tag <uses-permission>
nel proprio file manifest (e successivamente riceve l'autorizzazione, se
pericoloso) possono inviare un intent al destinatario.
Ad esempio, supponiamo che la tua app ricevente abbia un destinatario dichiarato nel file manifest come come mostrato di seguito:
<receiver android:name=".MyBroadcastReceiver"
android:permission="android.permission.BLUETOOTH_CONNECT">
<intent-filter>
<action android:name="android.intent.action.ACTION_FOUND"/>
</intent-filter>
</receiver>
In alternativa, l'app ricevente ha un ricevitore registrato in base al contesto, come mostrato di seguito:
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 );
Quindi, per poter inviare annunci a questi ricevitori, l'app di invio deve richiedi l'autorizzazione come illustrato di seguito:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
Considerazioni sulla sicurezza e best practice
Di seguito sono riportate alcune considerazioni sulla sicurezza e best practice per l'invio e la ricezione di trasmissioni:
Se molte app si sono registrate per ricevere lo stesso annuncio manifest, può causare l'avvio di molte app da parte del sistema, causando un un impatto significativo sia sulle prestazioni del dispositivo sia sull'esperienza utente. Da evitare In questo caso, è preferibile utilizzare la registrazione del contesto piuttosto che la dichiarazione del file manifest. A volte, il sistema Android stesso impone l'uso di o ricevitori. Ad esempio, la trasmissione
CONNECTIVITY_ACTION
viene consegnata solo a destinatari registrati a contesto.Non trasmettere informazioni sensibili utilizzando un intent implicito. La le informazioni possono essere lette da qualsiasi app che si registra per ricevere la trasmissione. Esistono tre modi per controllare chi può ricevere i tuoi annunci:
- Puoi specificare un'autorizzazione per l'invio di una trasmissione.
- In Android 4.0 e versioni successive, puoi specificare
package con
setPackage(String)
durante l'invio di un la trasmissione. Il sistema limita la trasmissione all'insieme di app che corrispondono al pacchetto.
Quando registri un destinatario, qualsiasi app può inviare messaggi potenzialmente dannosi gli annunci al ricevitore della tua app. Esistono diversi modi per limitare il annunci ricevuti dalla tua app:
- Puoi specificare un'autorizzazione quando registri un broadcast receiver.
- Per i destinatari dichiarati da un file manifest, puoi impostare android:esportato attributo su "false" nel file manifest. Il destinatario non riceve da fonti esterne all'app.
Lo spazio dei nomi per le azioni di trasmissione è globale. Assicurati che i nomi delle azioni e altre stringhe sono scritte in uno spazio dei nomi di tua proprietà, oppure entrare inavvertitamente in conflitto con altre app.
Perché il metodo
onReceive(Context, Intent)
di un destinatario viene eseguito nel thread principale, dovrebbe essere eseguito e restituito rapidamente. Per eseguire lavori a lunga durata, fare attenzione a generare fili o avviare in background perché il sistema può terminare l'intero processo Resi aonReceive()
. Per ulteriori informazioni, consulta la sezione Effetto sul processo Per eseguire lavori a lunga durata, consiglia:- Chiamata a
goAsync()
nel tuo metodoonReceive()
del destinatario e passareBroadcastReceiver.PendingResult
a un thread in background. Questa operazione mantiene attiva la trasmissione dopo il ritorno daonReceive()
. Tuttavia, anche con questo approccio il sistema si aspetta che tu finisca con molto rapidamente (meno di 10 secondi). Ti permette invece di spostare lavora su un altro thread per evitare di creare problemi con il thread principale. - Pianificazione di un job con
JobScheduler
. Per ulteriori informazioni informazioni, vedi Job intelligente Programmazione.
- Chiamata a
Non avviare attività da broadcast receiver perché l'esperienza utente è irritante; soprattutto se c'è più di un ricevitore. Prendi in considerazione invece mostrare una notifica.