Présentation des diffusions

Les applications Android peuvent envoyer ou recevoir des annonces depuis le système Android et d'autres applications Android, semblables à publish-subscribe modèle de conception. Ces annonces sont envoyées lorsqu'un événement intéressant se produit. Par exemple, le système Android envoie des annonces lorsque divers événements système (par exemple, lorsque le système démarre ou que l'appareil commence à se recharger). Applications peut également envoyer des annonces personnalisées, par exemple pour avertir d'autres applications quelque chose qui pourrait les intéresser (par exemple, certaines nouvelles données téléchargé).

Le système optimise la diffusion des diffusions afin de maintenir l'état optimal du système. Par conséquent, les délais de livraison des diffusions ne sont pas sont garantis. Les applications nécessitant une communication inter-processus à faible latence doivent pensez aux services liés.

Les applications peuvent s'inscrire pour recevoir des annonces spécifiques. Lorsqu'une diffusion est envoyée, le système achemine automatiquement les annonces vers les applications qui se sont abonnées recevoir ce type particulier de diffusion.

De manière générale, les annonces peuvent être utilisées comme un système de messagerie pour toutes les applications. et en dehors du flux utilisateur normal. Toutefois, vous devez veiller à ne pas utiliser possibilité de répondre aux annonces et d'exécuter des jobs en arrière-plan peut contribuer à la lenteur des performances du système.

À propos des diffusions système

Le système envoie automatiquement des annonces lorsque divers événements système se produisent, comme lorsque le système passe en mode Avion et le quitte. Système les annonces sont envoyées à toutes les applications auxquelles vous êtes abonné pour recevoir les .

Le message de diffusion lui-même est encapsulé dans un Intent. objet dont la chaîne d'action identifie l'événement qui s'est produit (par exemple, android.intent.action.AIRPLANE_MODE). L'intention peut également inclure des informations supplémentaires rgroupées dans son champ supplémentaire. Par exemple, l'avion inclut un extra booléen qui indique si le mode Avion est défini ou non Le mode est activé.

Pour savoir comment lire les intents et obtenir la chaîne d'action à partir de un intent, consultez la section Intents Filtres.

Pour obtenir la liste complète des actions de diffusion du système, consultez la BROADCAST_ACTIONS.TXT dans le SDK Android. Chaque action de diffusion possède un constante qui lui est associée. Par exemple, la valeur de la constante ACTION_AIRPLANE_MODE_CHANGED correspond à android.intent.action.AIRPLANE_MODE Documentation sur chaque action de diffusion est disponible dans le champ de constante associé.

Modifications apportées aux diffusions système

À mesure que la plate-forme Android évolue, elle modifie régulièrement la façon dont le système diffuse et le comportement de l'utilisateur. Tenez compte des modifications suivantes pour assurer la compatibilité avec toutes les versions d'Android.

Android 14

Lorsque les applications sont en cache , la diffusion de diffusion est optimisé pour l'état du système. Par exemple, les annonces système moins importantes que ACTION_SCREEN_ON sont reporté tant que l'application est en cache. Une fois que l'application passe du cache l'état en un processus actif cycle de vie, le système livre les diffusions différées.

Annonces importantes déclarées dans le fichier manifeste supprimer temporairement des applications du cache pour la diffusion.

Android 9

À partir d'Android 9 (niveau d'API 28), NETWORK_STATE_CHANGED_ACTION ne reçoit aucune information sur la position de l'utilisateur ou sur des données identifiables.

De plus, si votre application est installée sur un appareil équipé d'Android 9 ou version ultérieure, les diffusions du système à partir du Wi-Fi ne contiennent pas de SSID, BSSID, des informations ou des résultats d'analyse. Pour obtenir ces informations, appelez getConnectionInfo() à la place.

Android 8.0

À partir d'Android 8.0 (niveau d'API 26), le système impose des des restrictions sur les récepteurs déclarés par le fichier manifeste.

Si votre application cible Android 8.0 ou une version ultérieure, vous ne pouvez pas utiliser le fichier manifeste pour déclarer un récepteur pour la plupart des diffusions implicites (annonces qui ne ciblent pas spécifiquement pour votre application). Vous pouvez toujours utiliser un destinataire enregistré en contexte lorsque le utilise activement votre application.

Android 7.0

Android 7.0 (niveau d'API 24) ou version ultérieure n'envoie pas le système suivant diffusions:

De plus, les applications ciblant Android 7.0 ou version ultérieure doivent enregistrer la diffusion CONNECTIVITY_ACTION. avec registerReceiver(BroadcastReceiver, IntentFilter). La déclaration d'un destinataire dans le fichier manifeste ne fonctionne pas.

Recevoir des annonces

Les applications peuvent recevoir des annonces de deux manières: via des récepteurs déclarés dans le fichier manifeste. et les récepteurs enregistrés en contexte.

Destinataires déclarés dans le fichier manifeste

Si vous déclarez un broadcast receiver dans votre fichier manifeste, le système lance votre application (si elle n'est pas déjà en cours d'exécution) lors de l'envoi de la diffusion.

Pour déclarer un broadcast receiver dans le fichier manifeste, procédez comme suit:

  1. Spécifiez la <receiver> dans le fichier manifeste de votre application.

    <!-- 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>
    

    Les filtres d'intent spécifient les actions de diffusion auxquelles votre récepteur s'abonne.

  2. Sous-classe BroadcastReceiver et implémentez onReceive(Context, Intent). La broadcast receiver dans les exemples de journaux suivants et affiche le contenu de la diffusion:

    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();
            }
        }
    

    Pour activer la liaison de vue, configurer viewBinding au niveau du module build.gradle.

Le gestionnaire de packages système enregistre le récepteur lorsque l'application est installée. Le récepteur devient alors un point d'entrée distinct dans votre application, ce qui signifie que le système puisse lancer l'application et diffuser la diffusion si l'application n'est pas en cours d'exécution.

Le système crée un composant BroadcastReceiver. pour gérer chaque annonce qu'il reçoit. Cet objet n'est valide que pendant la durée de l'appel à onReceive(Context, Intent). Une fois que votre code renvoyées par cette méthode, le système considère que le composant n'est plus actif.

Récepteurs enregistrés en contexte

Les récepteurs enregistrés en contexte reçoivent des annonces à condition que leur enregistrement le contexte est valide. Par exemple, si vous vous inscrivez au sein d'un Activity vous recevez des annonces tant que l'activité n'est pas détruite. Si vous s'inscrire dans le contexte de l'application, vous recevez des annonces à condition que l'application est en cours d'exécution.

Pour enregistrer un récepteur avec un contexte, procédez comme suit:

  1. Dans le fichier de compilation au niveau du module de votre application, incluez la version 1.9.0 ou ultérieure de la bibliothèque AndroidX Core:

    Groovy

    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-alpha01"
    }
    

    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-alpha01")
    }
    
  2. Créer une instance de BroadcastReceiver:

    Kotlin

    val br: BroadcastReceiver = MyBroadcastReceiver()
    

    Java

    BroadcastReceiver br = new MyBroadcastReceiver();
    
  3. Créer une instance de IntentFilter:

    Kotlin

    val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
    

    Java

    IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
    
  4. Indiquez si le broadcast receiver doit être exporté et visible par d'autres applications sur l'appareil. Si ce destinataire écoute les annonces envoyées du système ou d'autres applications, ou même d'autres applications dont vous êtes le propriétaire, utilisent le RECEIVER_EXPORTED. Si, au contraire, ce récepteur n'écoute que les annonces envoyées par votre application, utilisez l'indicateur 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. Enregistrez le récepteur en appelant registerReceiver():

    Kotlin

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

    Java

    ContextCompat.registerReceiver(context, br, filter, receiverFlags);
    
  6. Pour ne plus recevoir d'annonces, appelez unregisterReceiver(android.content.BroadcastReceiver). Pensez à annuler l'enregistrement du récepteur lorsque vous n'en avez plus besoin le contexte n'est plus valide.

    Faites attention à l'emplacement où vous enregistrez ou annulez l'enregistrement du récepteur, Par exemple, si vous enregistrez un récepteur dans onCreate(Bundle) à l'aide du contexte de l'activité, vous doit annuler son enregistrement dans onDestroy() pour empêcher la fuite du récepteur hors du contexte de l'activité. Si vous vous inscrivez un récepteur dans onResume(), vous devez annulez-le dans onPause() pour empêcher en l'enregistrant plusieurs fois (si vous ne voulez pas recevoir d'annonces lorsqu'elles sont mises en pause, ce qui permet de réduire les frais généraux inutiles sur le système). À ne pas faire se désinscrire de onSaveInstanceState(Bundle) car elle n'est pas appelée si l'utilisateur revient dans la pile de l'historique.

Effets sur l'état du processus

Que votre BroadcastReceiver fonctionne ou n'affecte pas le processus qu'il contient, ce qui peut altérer son la probabilité de suppression du système. Un processus de premier plan exécute la méthode onReceive() d'un récepteur. La système exécute le processus, sauf en cas de pression extrême de la mémoire.

BroadcastReceiver est désactivé après onReceive(). Hôte du destinataire n'est importante que pour ses composants d'application. Si ce processus n'héberge que un destinataire déclaré dans le fichier manifeste (ce qui arrive fréquemment pour les applications que l'utilisateur n'a jamais ou avec lesquelles vous n'avez pas interagi récemment), le système peut la fermer après onReceive() pour ressources disponibles pour d’autres processus plus critiques.

Ainsi, les broadcast receivers ne doivent pas lancer de threads de longue durée en arrière-plan. Le système peut arrêter le processus à tout moment après onReceive() pour récupérer mémoire, mettant fin au thread créé. Pour que le processus reste actif, planifiez une JobService à partir du récepteur à l'aide de JobScheduler afin que le système sache que le processus fonctionne toujours. La page Présentation des tâches en arrière-plan fournit plus de détails.

Envoyer des annonces

Android propose trois façons pour les applications d'envoyer une diffusion:

  • sendOrderedBroadcast(Intent, String) envoie des annonces à un destinataire à la fois. Lorsque chaque récepteur exécute à son tour, il peut propager un résultat au destinataire suivant ou annuler complètement la diffusion afin qu'elle ne soit pas transmise à d'autres récepteurs. L'ordre dans lequel les récepteurs s'exécutent peut être contrôlé Attribut android:Priority de l'intent-filter correspondant récepteurs avec même priorité seront exécutées dans un ordre arbitraire.
  • La méthode sendBroadcast(Intent) envoie diffuse des annonces à tous les récepteurs dans un ordre indéterminé. C'est ce que l'on appelle Diffuser. C'est plus efficace, mais cela signifie que les récepteurs ne peuvent pas lire des résultats provenant d'autres récepteurs, de propager les données reçues de la diffusion ou annuler la diffusion.

L'extrait de code suivant montre comment envoyer une diffusion en créant une Intention et appel de 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);

Le message de diffusion est encapsulé dans un objet Intent. La chaîne d'action de l'intent doit fournir la syntaxe du nom de package Java de l'application et identifier de manière unique l'événement de diffusion. Vous pouvez joindre des informations à l'intent avec putExtra(String, Bundle). Vous pouvez également limiter une diffusion à un ensemble d'applications de la même organisation en en appelant setPackage(String) sur l'intent.

Limiter les diffusions avec des autorisations

Les autorisations vous permettent de limiter les diffusions à l'ensemble des applications qui contiennent certaines autorisations. Vous pouvez appliquer des restrictions à l'expéditeur ou le destinataire d'une diffusion.

Envoyer avec des autorisations

Lorsque vous appelez le sendBroadcast(Intent, String) ou sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle), vous pouvez spécifier d'autorisation. Seuls les destinataires qui ont demandé cette autorisation avec la balise dans leur fichier manifeste (et ont ensuite reçu l'autorisation l'autorisation s'il est dangereux) peut recevoir la diffusion. Par exemple, Le code suivant envoie une diffusion:

Kotlin

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

Java

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

Pour recevoir la diffusion, l'application réceptrice doit demander l'autorisation en tant que comme indiqué ci-dessous:

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

Vous pouvez spécifier une autorisation système existante, comme BLUETOOTH_CONNECT ou définissez une autorisation personnalisée <permission>. Pour des informations sur les autorisations et la sécurité en général, consultez la page Autorisations.

.

Réception avec autorisations

Si vous spécifiez un paramètre d'autorisation lors de l'enregistrement d'un broadcast receiver (avec registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) ou dans Balise <receiver> dans votre manifeste), seuls les diffuseurs ayant demandé l'autorisation Balise <uses-permission> dans leur fichier manifeste (et qui ont ensuite reçu l'autorisation dangereux) peut envoyer un intent au récepteur.

Par exemple, supposons que votre application réceptrice dispose d'un destinataire déclaré dans le fichier manifeste, comme indiqué ci-dessous:

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

Ou votre application réceptrice dispose d'un récepteur enregistré en contexte, comme indiqué ci-dessous:

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

Ensuite, pour pouvoir envoyer des annonces à ces récepteurs, l'application émettrice doit demandez l'autorisation comme indiqué ci-dessous:

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

Remarques sur la sécurité et bonnes pratiques

Voici quelques considérations de sécurité et les meilleures pratiques pour l'envoi et recevoir des diffusions:

  • Si de nombreuses applications se sont inscrites pour recevoir la même annonce le fichier manifeste, cela peut amener le système à lancer un grand nombre d'applications, ce qui provoque une un impact important sur les performances des appareils et sur l'expérience utilisateur. Pour éviter utilisez plutôt l'enregistrement du contexte plutôt que la déclaration du fichier manifeste. Parfois, le système Android impose lui-même l'utilisation de données de contexte enregistrées récepteurs. Par exemple, l'annonce CONNECTIVITY_ACTION est diffusée. uniquement pour les récepteurs enregistrés en contexte.

  • Ne diffusez pas d'informations sensibles à l'aide d'un intent implicite. La les informations peuvent être lues par toute application qui s'inscrit pour recevoir la diffusion. Il existe trois façons de contrôler qui peut recevoir vos annonces:

    • Vous pouvez spécifier une autorisation lorsque vous envoyez une diffusion.
    • Dans Android 4.0 et versions ultérieures, vous pouvez spécifier un package avec setPackage(String) lors de l'envoi d'un annonce. Le système limite la diffusion à l'ensemble des applications correspondent au package.
  • Lorsque vous enregistrez un récepteur, toute application peut envoyer diffuse des annonces au récepteur de votre application. Il existe plusieurs façons de limiter que votre application reçoit:

    • Vous pouvez spécifier une autorisation lors de l'enregistrement d'un broadcast receiver.
    • Pour les destinataires déclarés dans le fichier manifeste, vous pouvez définir android:exported Attribut sur "false" dans le fichier manifeste. Le récepteur ne reçoit pas les annonces à partir de sources externes à l'application.
  • L'espace de noms des actions de diffusion est global. Assurez-vous que les noms des actions et d'autres chaînes sont écrites dans un espace de noms qui vous appartient. Sinon, vous pouvez en conflit avec d'autres applications.

  • Comme la méthode onReceive(Context, Intent) d'un destinataire s'exécute sur le thread principal, il devrait s'exécuter et revenir rapidement. Si vous avez besoin de des tâches de longue durée, évitez de générer des threads ou de démarrer les services d’arrière-plan car le système peut tuer l’ensemble du processus après Retours de onReceive(). Pour plus d'informations, consultez la section Effet sur le processus Pour effectuer un travail de longue durée, recommandent:

    • Vous appelez goAsync() dans votre la méthode onReceive() du récepteur et transmettre le BroadcastReceiver.PendingResult à un thread d'arrière-plan. La diffusion reste ainsi active après son retour depuis onReceive(). Cependant, même avec cette approche, le système s'attend à ce que vous terminiez la diffusion très rapidement (moins de 10 secondes). Cela vous permet de déplacer travailler sur un autre thread pour éviter de perturber le thread principal.
    • Planifier une tâche avec JobScheduler Pour plus pour plus d'informations, consultez la page Planification.
  • Ne pas démarrer les activités des broadcast receivers, car l'expérience utilisateur est bouleversant. surtout s'il y a plusieurs destinataires. Envisagez plutôt affichant une notification.