Panoramica delle trasmissioni

Le app per Android inviano e ricevono messaggi di trasmissione dal sistema Android e da altre app per Android, in modo simile al pattern di progettazione pubblica-sottoscrivi. Il sistema e le app in genere inviano trasmissioni quando si verificano determinati eventi. Ad esempio, il sistema Android invia trasmissioni quando si verificano vari eventi di sistema, come l'avvio del sistema o la ricarica del dispositivo. Le app inviano anche trasmissioni personalizzate, ad esempio per notificare ad altre app qualcosa che potrebbe interessarle (ad esempio, il download di nuovi dati).

Le app possono registrarsi per ricevere trasmissioni specifiche. Quando viene inviato un broadcast, il sistema lo indirizza automaticamente alle app che hanno eseguito la sottoscrizione per ricevere quel particolare tipo di broadcast.

In generale, le trasmissioni possono essere utilizzate come sistema di messaggistica tra le app e al di fuori del normale flusso utente. Tuttavia, devi fare attenzione a non abusare dell'opportunità di rispondere alle trasmissioni e di eseguire processi in background che possono contribuire a un rallentamento delle prestazioni del sistema.

Informazioni sugli annunci di sistema

Il sistema invia automaticamente trasmissioni quando si verificano vari eventi di sistema, ad esempio quando il sistema attiva e disattiva la modalità aereo. Tutte le app a cui è stato effettuato l'abbonamento ricevono queste trasmissioni.

L'oggetto Intent racchiude l'annuncio. La stringa action identifica l'evento che si è verificato, ad esempio android.intent.action.AIRPLANE_MODE. L'intent potrebbe includere anche informazioni aggiuntive raggruppate nel campo extra. Ad esempio, l'intent Modalità Aereo include un extra booleano che indica se la modalità aereo è attiva o meno.

Per saperne di più su come leggere gli intent e ottenere la stringa di azione da un intent, consulta Intent e filtri per intent.

Azioni di trasmissione di sistema

Per un elenco completo delle azioni di annuncio di sistema, consulta il file BROADCAST_ACTIONS.TXT nell'SDK Android. A ogni azione di trasmissione è associato un campo costante. Ad esempio, il valore della costante ACTION_AIRPLANE_MODE_CHANGED è android.intent.action.AIRPLANE_MODE. La documentazione per ogni azione di trasmissione è disponibile nel campo costante associato.

Modifiche alle trasmissioni di sistema

Man mano che la piattaforma Android si evolve, cambia periodicamente il comportamento delle trasmissioni di sistema. Tieni presente le seguenti modifiche per supportare tutte le versioni di Android.

Android 16

In Android 16, l'ordine di distribuzione delle trasmissioni utilizzando l'attributo android:priority o IntentFilter.setPriority() in processi diversi non sarà garantito. Le priorità di trasmissione vengono rispettate solo all'interno della stessa procedura di candidatura, non in tutte le procedure.

Inoltre, le priorità di trasmissione sono automaticamente limitate all'intervallo (SYSTEM_LOW_PRIORITY + 1, SYSTEM_HIGH_PRIORITY - 1). Solo i componenti di sistema possono impostare SYSTEM_LOW_PRIORITY, SYSTEM_HIGH_PRIORITY come priorità di trasmissione.

Android 14

Quando le app sono in stato memorizzato nella cache, il sistema ottimizza la distribuzione della trasmissione per l'integrità del sistema. Ad esempio, il sistema posticipa le trasmissioni di sistema meno importanti, come ACTION_SCREEN_ON, mentre l'app è in stato memorizzato nella cache. Una volta che l'app passa dallo stato memorizzato nella cache a un ciclo di vita del processo attivo, il sistema distribuisce le trasmissioni differite.

Le trasmissioni importanti dichiarate nel manifest rimuovono temporaneamente le app dallo stato memorizzato nella cache per la distribuzione.

Android 9

A partire da Android 9 (livello API 28), la trasmissione NETWORK_STATE_CHANGED_ACTION non riceve informazioni sulla posizione dell'utente o dati personali identificabili.

Se la tua app è installata su un dispositivo con Android 9.0 (livello API 28) o versioni successive, il sistema non include SSID, BSSID, informazioni sulla connessione o risultati della scansione nelle trasmissioni Wi-Fi. Per ottenere queste informazioni, chiama il numero getConnectionInfo().

Android 8.0

A partire da Android 8.0 (livello API 26), il sistema impone ulteriori limitazioni ai ricevitori dichiarati nel 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 (trasmissioni che non hanno come target specificamente la tua app). Puoi comunque utilizzare un ricevitore registrato nel contesto quando l'utente utilizza attivamente la tua app.

Android 7.0

Android 7.0 (livello API 24) e versioni successive non inviano le seguenti trasmissioni di sistema:

Inoltre, le app che hanno come target Android 7.0 e versioni successive devono registrare la trasmissione CONNECTIVITY_ACTION utilizzando registerReceiver(BroadcastReceiver, IntentFilter). La dichiarazione di un ricevitore nel manifest non funziona.

Ricevere trasmissioni

Le app possono ricevere broadcast in due modi: tramite i ricevitori registrati nel contesto e i ricevitori dichiarati nel manifest.

Ricevitori registrati nel contesto

I ricevitori registrati nel contesto ricevono le trasmissioni finché il contesto di registrazione è valido. In genere, questo avviene tra le chiamate a registerReceiver e unregisterReceiver. Anche il contesto di registrazione diventa non valido quando il sistema distrugge il contesto corrispondente. Ad esempio, se ti registri in un contesto Activity, ricevi le trasmissioni finché l'attività rimane attiva. Se registri il contesto dell'applicazione, ricevi trasmissioni finché l'app è in esecuzione.

Per registrare un ricevitore con un contesto:

  1. Nel file di build a livello di modulo della tua app, includi la versione 1.9.0 o successive della libreria AndroidX Core:

    Groovy

    dependencies {
        def core_version = "1.19.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.1.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"
    }

    Kotlin

    dependencies {
        val core_version = "1.19.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.1.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")
    }
  2. Crea un'istanza di BroadcastReceiver:

    Kotlin

    val myBroadcastReceiver = MyBroadcastReceiver()
    

    Java

    MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
    
  3. Crea un'istanza di IntentFilter:

    Kotlin

    val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")
    

    Java

    IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");
    
  4. Scegli se il broadcast receiver deve essere esportato e visibile ad altre app sul dispositivo. Se questo ricevitore è in ascolto di trasmissioni inviate dal sistema o da altre app, anche altre app di tua proprietà, utilizza il flag RECEIVER_EXPORTED. Se invece questo ricevitore è in ascolto solo delle trasmissioni inviate dalla tua app, utilizza il flag RECEIVER_NOT_EXPORTED.

    Kotlin

    val listenToBroadcastsFromOtherApps = false
    val receiverFlags = if (listenToBroadcastsFromOtherApps) {
        ContextCompat.RECEIVER_EXPORTED
    } else {
        ContextCompat.RECEIVER_NOT_EXPORTED
    }
    

    Java

    boolean listenToBroadcastsFromOtherApps = false;
    int receiverFlags = listenToBroadcastsFromOtherApps
            ? ContextCompat.RECEIVER_EXPORTED
            : ContextCompat.RECEIVER_NOT_EXPORTED;
    
  5. Registra il destinatario chiamando il numero registerReceiver():

    Kotlin

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

    Java

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
    
  6. Per interrompere la ricezione delle trasmissioni, chiama unregisterReceiver(android.content.BroadcastReceiver). Assicurati di annullare la registrazione del ricevitore quando non ti serve più o il contesto non è più valido.

Annullare la registrazione del broadcast receiver

Mentre il broadcast receiver è registrato, contiene un riferimento al contesto con cui è stato registrato. Ciò può potenzialmente causare perdite se l'ambito registrato del destinatario supera l'ambito del ciclo di vita del contesto. Ad esempio, questo può verificarsi quando registri un ricevitore in un ambito di attività, ma dimentichi di annullare la registrazione quando il sistema distrugge l'attività. Pertanto, annulla sempre la registrazione del broadcast receiver.

Kotlin

class MyActivity : ComponentActivity() {
    private val myBroadcastReceiver = MyBroadcastReceiver()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags)
        setContent { MyApp() }
    }

    override fun onDestroy() {
        super.onDestroy()
        // When you forget to unregister your receiver here, you're causing a leak!
        this.unregisterReceiver(myBroadcastReceiver)
    }
}

Java

class MyActivity extends ComponentActivity {
    MyBroadcastReceiver myBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags);
        // Set content
    }
}

Registra i ricevitori nell'ambito più piccolo

Il broadcast receiver deve essere registrato solo quando sei effettivamente interessato al risultato. Scegli l'ambito del destinatario più piccolo possibile:

  • Metodi del ciclo di vita LifecycleResumeEffect o dell'attività onResume/onPause: il broadcast receiver riceve gli aggiornamenti solo quando l'app è nello stato di ripresa.
  • Metodi del ciclo di vita LifecycleStartEffect o dell'attività onStart/onStop: il broadcast receiver riceve gli aggiornamenti solo quando l'app è nello stato di ripresa.
  • DisposableEffect: il broadcast receiver riceve aggiornamenti solo mentre il composable si trova nell'albero di composizione. Questo ambito non è collegato all'ambito del ciclo di vita dell'attività. Valuta la possibilità di registrare il destinatario nel contesto dell'applicazione. Questo perché il composable potrebbe teoricamente sopravvivere all'ambito del ciclo di vita dell'attività e causare una perdita di memoria.
  • Attività onCreate/onDestroy: il broadcast receiver riceve aggiornamenti mentre l'attività è nello stato creato. Assicurati di annullare la registrazione in onDestroy() e non in onSaveInstanceState(Bundle) perché questa potrebbe non essere chiamata.
  • Un ambito personalizzato: ad esempio, puoi registrare un ricevitore nell'ambito ViewModel in modo che sopravviva alla ricreazione dell'attività. Assicurati di utilizzare il contesto dell'applicazione per registrare il ricevitore, poiché il ricevitore può sopravvivere all'ambito del ciclo di vita dell'attività e causare una perdita di memoria.

Crea composable stateful e stateless

Compose ha composable stateful e stateless. La registrazione o l'annullamento della registrazione di un broadcast receiver all'interno di un composable lo rende stateful. Il composable non è una funzione deterministica che esegue il rendering dello stesso contenuto quando vengono passati gli stessi parametri. Lo stato interno può cambiare in base alle chiamate al ricevitore di trasmissione registrato.

Come best practice in Compose, ti consigliamo di dividere i composable in versioni con stato e senza stato. Pertanto, ti consigliamo di estrarre la creazione del broadcast receiver da un elemento componibile per renderlo stateless:

@Composable
fun MyStatefulScreen() {
    val myBroadcastReceiver = remember { MyBroadcastReceiver() }
    val context = LocalContext.current
    LifecycleStartEffect(true) {
        // ...
        ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, flags)
        onStopOrDispose { context.unregisterReceiver(myBroadcastReceiver) }
    }
    MyStatelessScreen()
}

@Composable
fun MyStatelessScreen() {
    // Implement your screen
}

Ricevitori dichiarati nel manifest

Se dichiari un broadcast receiver nel manifest, il sistema avvia la tua app quando viene inviato il broadcast. Se l'app non è già in esecuzione, il sistema la avvia.

Per dichiarare un broadcast receiver nel manifest, segui questi passaggi:

  1. Specifica l'elemento <receiver> nel manifest della tua 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="com.example.snippets.ACTION_UPDATE_DATA" />
        </intent-filter>
    </receiver>
    

    I filtri per intent specificano le azioni di trasmissione a cui si iscrive il ricevitore.

  2. Sottoclasse BroadcastReceiver e implementa onReceive(Context, Intent). Il broadcast receiver nel seguente esempio registra e mostra i contenuti della trasmissione:

    Kotlin

    class MyBroadcastReceiver : BroadcastReceiver() {
    
        @Inject
        lateinit var dataRepository: DataRepository
    
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "com.example.snippets.ACTION_UPDATE_DATA") {
                val data = intent.getStringExtra("com.example.snippets.DATA") ?: "No data"
                // Do something with the data, for example send it to a data repository:
                dataRepository.updateData(data)
            }
        }
    }
    

    Java

    public static class MyBroadcastReceiver extends BroadcastReceiver {
    
        @Inject
        DataRepository dataRepository;
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Objects.equals(intent.getAction(), "com.example.snippets.ACTION_UPDATE_DATA")) {
                String data = intent.getStringExtra("com.example.snippets.DATA");
                // Do something with the data, for example send it to a data repository:
                if (data != null) { dataRepository.updateData(data); }
            }
        }
    }
    

Il gestore di pacchetti di sistema registra il ricevitore quando l'app viene installata. Il ricevitore diventa quindi un punto di accesso separato all'app, il che significa che il sistema può avviare l'app e inviare la trasmissione se l'app non è in esecuzione.

Il sistema crea un nuovo oggetto componente BroadcastReceiver per gestire ogni trasmissione che riceve. Questo oggetto è valido solo per la durata della chiamata a onReceive(Context, Intent). Una volta che il codice viene restituito da questo metodo, il sistema considera il componente non più attivo.

Effetti sullo stato del processo

Il funzionamento o meno del BroadcastReceiver influisce sul processo contenuto, che può alterare la probabilità di arresto del sistema. Un processo in primo piano esegue il metodo onReceive() di un ricevitore. Il sistema esegue la procedura tranne in condizioni di pressione di memoria estrema.

Il sistema disattiva BroadcastReceiver dopo onReceive(). L'importanza del processo host del destinatario dipende dai componenti dell'app. Se questo processo ospita solo un ricevitore dichiarato nel manifest, il sistema potrebbe terminarlo dopo onReceive() per liberare risorse per altri processi più critici. Questo è comune per le app con cui l'utente non ha mai interagito o non ha interagito di recente.

Pertanto, i ricevitori di trasmissione non devono avviare thread in background di lunga durata. Il sistema può interrompere il processo in qualsiasi momento dopo onReceive() per recuperare memoria, terminando il thread creato. Per mantenere attivo il processo, pianifica un JobService dal destinatario utilizzando JobScheduler in modo che il sistema sappia che il processo è ancora in corso. Panoramica del lavoro in background fornisce ulteriori dettagli.

Inviare trasmissioni

Android offre due modi per inviare trasmissioni dalle app:

  • Il metodo sendOrderedBroadcast(Intent, String) invia le trasmissioni a un ricevitore alla volta. Man mano che ogni ricevitore viene eseguito a turno, può propagare un risultato al ricevitore successivo. Può anche interrompere completamente la trasmissione in modo che non raggiunga altri ricevitori. Puoi controllare l'ordine in cui vengono eseguiti i ricevitori all'interno dello stesso processo dell'app. A questo scopo, utilizza l'attributo android:priority dell'intent-filter corrispondente. I ricevitori con la stessa priorità vengono eseguiti in un ordine arbitrario.
  • Il metodo sendBroadcast(Intent) invia trasmissioni a tutti i ricevitori in un ordine indefinito. Questa operazione viene chiamata trasmissione normale. Questo è più efficiente, ma significa che i ricevitori non possono leggere i risultati di altri ricevitori, propagare i dati ricevuti dalla trasmissione o interromperla.

Il seguente snippet di codice mostra come inviare una trasmissione creando un intent e chiamando sendBroadcast(Intent).

Kotlin

val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
    putExtra("com.example.snippets.DATA", newData)
    setPackage("com.example.snippets")
}
context.sendBroadcast(intent)

Java

Intent intent = new Intent("com.example.snippets.ACTION_UPDATE_DATA");
intent.putExtra("com.example.snippets.DATA", newData);
intent.setPackage("com.example.snippets");
context.sendBroadcast(intent);

L'annuncio è racchiuso in un oggetto Intent. La stringa action dell'intent deve fornire la sintassi del nome del pacchetto Java dell'app e 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) nell'intent.

Limitare le trasmissioni con le autorizzazioni

Le autorizzazioni ti consentono di limitare le trasmissioni all'insieme di app che dispongono di determinate autorizzazioni. Puoi applicare limitazioni al mittente o al destinatario di una trasmissione.

Inviare trasmissioni con autorizzazioni

Quando chiami sendBroadcast(Intent, String) o sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) , puoi specificare un parametro di autorizzazione. Solo i ricevitori che hanno richiesto questa autorizzazione con il tag <uses-permission> nel manifest possono ricevere la trasmissione. Se l'autorizzazione è pericolosa, devi concederla prima che il destinatario possa ricevere la trasmissione. Ad esempio, il seguente codice invia una trasmissione con un'autorizzazione:

Kotlin

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)

Java

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);

Per ricevere la trasmissione, l'app ricevente deve richiedere l'autorizzazione come segue:

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

Puoi specificare un'autorizzazione di sistema esistente, ad esempio BLUETOOTH_CONNECT, o definire un'autorizzazione personalizzata con l'elemento <permission>. Per informazioni su autorizzazioni e sicurezza in generale, consulta Autorizzazioni di sistema.

Ricevere trasmissioni con le autorizzazioni

Se specifichi un parametro di autorizzazione durante la registrazione di un broadcast receiver (con registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) o nel tag <receiver> nel manifest), solo i broadcaster che hanno richiesto l'autorizzazione con il tag <uses-permission> nel manifest possono inviare un intent al ricevitore. Se l'autorizzazione è pericolosa, deve essere concessa anche all'emittente.

Ad esempio, supponiamo che l'app di ricezione abbia un ricevitore dichiarato nel manifest come segue:

<!-- 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=".MyBroadcastReceiverWithPermission"
    android:permission="android.permission.ACCESS_COARSE_LOCATION"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
    </intent-filter>
</receiver>

oppure la tua app ricevente ha un ricevitore registrato nel contesto come segue:

Kotlin

ContextCompat.registerReceiver(
    context, myBroadcastReceiver, filter,
    android.Manifest.permission.ACCESS_COARSE_LOCATION,
    null, // scheduler that defines thread, null means run on main thread
    receiverFlags
)

Java

ContextCompat.registerReceiver(
        context, myBroadcastReceiver, filter,
        android.Manifest.permission.ACCESS_COARSE_LOCATION,
        null, // scheduler that defines thread, null means run on main thread
        receiverFlags
);

Quindi, per poter inviare trasmissioni a questi ricevitori, l'app di invio deve richiedere l'autorizzazione nel seguente modo:

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

Evitare le trasmissioni all'interno dello stesso processo

Le trasmissioni sono progettate come meccanismo di comunicazione interprocesso (IPC) per l'invio di messaggi tra app diverse o tra il sistema e le app. L'invio di una trasmissione automatica, ovvero una trasmissione per la quale tutti i destinatari vengono eseguiti nello stesso processo che ha inviato la trasmissione, è molto inefficiente, crea un sovraccarico di sistema non necessario ed è fortemente sconsigliato.

Due scenari comuni in cui le app inviano trasmissioni a se stesse includono:

  • Comunicazione tra componenti nello stesso processo: ad esempio, passaggio di eventi o dati tra attività, frammenti, servizi o thread in background. Anziché inviare trasmissioni, utilizza meccanismi di comunicazione in-process standard come il pattern Observer o i flussi reattivi:

    • Kotlin Flows (SharedFlow e StateFlow): una soluzione moderna e idiomatica in Kotlin per l'emissione e l'osservazione di flussi di eventi o aggiornamenti di stato tra coroutine e componenti dell'app.
    • Condiviso ViewModel: facilita la condivisione di dati ed eventi tra diversi componenti dell'interfaccia utente (come frammenti o composable) all'interno della stessa attività.
    • Callback e listener: callback di interfacce standard o riferimenti a funzioni passati direttamente tra i componenti o registrati con un repository o un controller centrale.
  • Gestione di eventi, job o sveglie di sistema: ad esempio, ricezione di un job programmato, una sveglia o un callback di sistema e poi invio di una trasmissione per attivare il lavoro effettivo. Anziché inviare una trasmissione, completa il lavoro direttamente all'interno del job (ad esempio un worker JobService o WorkManager), un gestore di sveglie o un componente di callback di sistema oppure delega direttamente alle classi di logica di business della tua app.

Sui dispositivi con Android 17 QPR2 o versioni successive, il sistema trasmette le auto-trasmissioni in modo più efficiente restituendole al processo di invio, che le trasmette ai propri ricevitori sul thread principale. L'invio di un'intent di trasmissione automatica non aumenta l'importanza del processo e non impedisce il blocco di un processo memorizzato nella cache, quindi non fare affidamento sulle intent di trasmissione automatica per mantenere in esecuzione l'app o per eseguire operazioni in background. Anche con questa ottimizzazione, le trasmissioni automatiche sono meno efficienti dei meccanismi di comunicazione in-processo, quindi utilizza queste alternative.

Per ulteriori informazioni sulla progettazione della comunicazione tra i componenti dell'app, consulta la Guida all'architettura delle app.

Considerazioni sulla sicurezza

Ecco alcune considerazioni sulla sicurezza per l'invio e la ricezione di trasmissioni:

  • Se molte app sono registrate per ricevere la stessa trasmissione nel manifest, il sistema potrebbe avviare molte app, con un impatto notevole sulle prestazioni del dispositivo e sull'esperienza utente. Per evitare questo problema, preferisci l'utilizzo della registrazione del contesto alla dichiarazione del manifest. A volte, il sistema Android stesso impone l'utilizzo di ricevitori registrati nel contesto. Ad esempio, la trasmissione CONNECTIVITY_ACTION viene inviata solo ai ricevitori registrati nel contesto.

  • Non trasmettere informazioni sensibili utilizzando un intent implicito. Qualsiasi app può leggere le informazioni se si registra per ricevere la trasmissione. Esistono tre modi per controllare chi può ricevere le tue trasmissioni:

    • Puoi specificare un'autorizzazione quando invii una trasmissione.
    • In Android 4.0 (livello API 14) e versioni successive, puoi specificare un pacchetto con setPackage(String) quando invii una trasmissione. Il sistema limita la trasmissione all'insieme di app che corrispondono al pacchetto.
  • Quando registri un ricevitore, qualsiasi app può inviare trasmissioni potenzialmente dannose al ricevitore della tua app. Esistono diversi modi per limitare le trasmissioni ricevute dalla tua app:

    • Puoi specificare un'autorizzazione durante la registrazione di un broadcast receiver.
    • Per i ricevitori dichiarati nel manifest, puoi impostare l'attributo android:exported su "false" nel manifest. Il destinatario non riceve trasmissioni da fonti esterne all'app.
  • Lo spazio dei nomi per le azioni di trasmissione è globale. Assicurati che i nomi delle azioni e le altre stringhe siano scritte in uno spazio dei nomi di tua proprietà. In caso contrario, potresti inavvertitamente entrare in conflitto con altre app.

  • Poiché il metodo onReceive(Context, Intent) di un ricevitore viene eseguito sul thread principale, deve essere eseguito e restituire rapidamente un valore. Se devi eseguire un lavoro di lunga durata, fai attenzione a generare thread o avviare servizi in background perché il sistema può terminare l'intero processo dopo la restituzione di onReceive(). Per saperne di più, consulta Effetto sullo stato del processo. Per eseguire operazioni a lunga esecuzione, ti consigliamo di:

    • Chiamando goAsync() nel metodo onReceive() del destinatario e passando BroadcastReceiver.PendingResult a un thread in background. In questo modo, la trasmissione rimane attiva dopo il ritorno da onReceive(). Tuttavia, anche con questo approccio, il sistema si aspetta che tu termini la trasmissione molto rapidamente (in meno di 10 secondi). Ti consente di spostare il lavoro in un altro thread per evitare problemi nel thread principale.
    • Pianificazione di un job con JobScheduler. Per saperne di più, vedi Pianificazione intelligente dei job.
  • Non avviare attività dai ricevitori di trasmissione perché l'esperienza utente è sgradevole, soprattutto se è presente più di un ricevitore. Valuta invece la possibilità di mostrare una notifica.