Visão geral das transmissões

Os apps Android podem enviar ou receber mensagens de transmissão do sistema Android e outros apps Android, assim como os publicar-inscrever-se padrão de design. Essas transmissões são enviadas quando ocorre um evento de interesse. Por exemplo, o sistema Android envia transmissões quando vários eventos do sistema quando o sistema é inicializado ou quando o dispositivo começa a carregar. Aplicativos também podem enviar transmissões personalizadas, por exemplo, para notificar outros apps sobre algo em que possam estar interessados (por exemplo, alguns dados novos têm após o download).

O sistema otimiza a entrega de transmissões para manter integridade ideal do sistema. Portanto, os tempos de entrega das transmissões não são garantida. Os aplicativos que precisam de comunicação entre processos de baixa latência devem Considere usar serviços vinculados.

Os apps podem se registrar para receber transmissões específicas. Quando uma transmissão é enviada, o sistema encaminha automaticamente as transmissões para os apps inscritos receber esse tipo específico de transmissão.

De modo geral, as transmissões podem ser usadas como um sistema de mensagens entre apps e fora do fluxo normal do usuário. No entanto, tome cuidado para não abusar a oportunidade de responder a transmissões e executar jobs em segundo plano que podem contribuir para um desempenho lento do sistema.

Sobre transmissões do sistema

O sistema envia transmissões automaticamente quando ocorrem vários eventos, por exemplo, quando o sistema entra e sai do modo avião. Sistema transmissões são enviadas a todos os apps inscritos para receber as evento.

A mensagem de transmissão em si é agrupada em um Intent. objeto cuja string de ação identifica o evento que ocorreu (por exemplo, android.intent.action.AIRPLANE_MODE). A intent também pode incluir informações adicionais agrupadas em seu campo extra. Por exemplo, o avião a intent de modo inclui um booleano extra que indica se o modo avião O modo está ativado.

Para mais informações sobre como ler intents e receber a string de ação de uma intent, consulte Intents e intents Filtros.

Para obter uma lista completa das ações de transmissão do sistema, consulte o BROADCAST_ACTIONS.TXT no SDK do Android. Cada ação de transmissão tem um campo constante associado a ele. Por exemplo, o valor da constante ACTION_AIRPLANE_MODE_CHANGED é android.intent.action.AIRPLANE_MODE. Documentação de cada ação de transmissão está disponível no campo de constante associado.

Mudanças em transmissões do sistema

À medida que a plataforma Android evolui, ela muda periodicamente a forma como o sistema transmite se comportar. Lembre-se das seguintes mudanças para oferecer suporte a todas as versões do Android.

Android 14

Enquanto os apps estiverem na pasta armazenada em cache, estado, a entrega de transmissão será otimizada para a integridade do sistema. Por exemplo, transmissões menos importantes do sistema, como como ACTION_SCREEN_ON estão adiado enquanto o app está em cache. Quando o app sai da configuração em um processo ativo ciclo de vida, o sistema entrega as transmissões adiadas.

Transmissões importantes que são declaradas no do app, remova temporariamente apps do cache o estado para a entrega.

Android 9

A partir do Android 9 (nível 28 da API), a NETWORK_STATE_CHANGED_ACTION transmissão não receba informações sobre a localização ou informações e identificáveis.

Além disso, se o app estiver instalado em um dispositivo com o Android 9 ou mais recente, as transmissões do sistema por Wi-Fi não contêm SSIDs, BSSIDs, conexão informações ou resultados de verificação. Para obter essas informações, chame getConnectionInfo() como alternativa.

Android 8.0

A partir do Android 8.0 (API de nível 26), o sistema impõe novos restrições para receptores declarados pelo manifesto.

Se o app for direcionado ao Android 8.0 ou a uma versão mais recente, não será possível usar o manifesto para declarar um receptor para a maioria das transmissões implícitas (transmissões que não são direcionadas seu app especificamente). Você ainda pode usar um receptor registrado pelo contexto quando o o usuário está usando seu app ativamente.

Android 7.0

O Android 7.0 (nível 24 da API) e versões mais recentes não enviam o seguinte sistema transmissões:

Além disso, os apps destinados ao Android 7.0 e versões mais recentes precisam registrar a transmissão CONNECTIVITY_ACTION. usando registerReceiver(BroadcastReceiver, IntentFilter). A declaração de um receptor no manifesto não funcionará.

Como receber transmissões

Os apps podem receber transmissões de duas maneiras: por receptores declarados pelo manifesto e receptores registrados pelo contexto.

Receptores declarados pelo manifesto

Se você declarar um broadcast receiver no manifesto, o sistema inicia o (se o app ainda não estiver em execução) quando a transmissão for enviada.

Para declarar um broadcast receiver no manifesto, siga as seguintes etapas:

  1. Especifique a classe <receiver>. no manifesto do seu 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>
    

    Os filtros de intent especificam as ações de transmissão em que seu receptor está inscrito.

  2. Coloque BroadcastReceiver em uma subclasse e implemente onReceive(Context, Intent). A o broadcast receiver nos registros de exemplo a seguir e exibe o conteúdo da transmissão:

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

    Para ativar a vinculação de visualizações, configure a viewBinding no nível do módulo. build.gradle do módulo.

O gerenciador de pacotes do sistema registra o receptor quando o app é instalado. O receptor se torna um ponto de entrada separado para o app, o que significa que que o sistema possa iniciar o aplicativo e entregar a transmissão se o aplicativo não for em execução no momento.

O sistema cria um novo componente BroadcastReceiver. para lidar com cada transmissão recebida. Este objeto é válido apenas durante a chamada para onReceive(Context, Intent). Assim que seu código retornar desse método, o sistema considerará que o componente não ativos.

Receptores registrados pelo contexto

Receptores registrados em contexto recebem transmissões, contanto que o registro contexto é válido. Por exemplo, se você se registrar em um Activity contexto, você recebe transmissões, desde que a atividade não seja destruída. Se você se registrar com o contexto do aplicativo, receberá transmissões, desde que o aplicativo está em execução.

Para registrar um receptor com um contexto, siga as seguintes etapas:

  1. No arquivo de build do módulo do app, inclua a versão 1.9.0 ou mais recente da da biblioteca 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. Crie uma instância de BroadcastReceiver:

    Kotlin

    val br: BroadcastReceiver = MyBroadcastReceiver()
    

    Java

    BroadcastReceiver br = new MyBroadcastReceiver();
    
  3. Crie uma instância de IntentFilter:

    Kotlin

    val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
    

    Java

    IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
    
  4. Escolha se o broadcast receiver deve ser exportado e ficar visível para outros apps no dispositivo. Se o receptor estiver ouvindo transmissões enviadas do sistema ou de outros aplicativos, até mesmo de seus aplicativos, use a sinalização RECEIVER_EXPORTED. Se, em vez disso, o receptor estiver ouvindo apenas transmissões enviadas pelo seu app, use a sinalização 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. Registre o receptor chamando registerReceiver():

    Kotlin

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

    Java

    ContextCompat.registerReceiver(context, br, filter, receiverFlags);
    
  6. Para parar de receber transmissões, chame unregisterReceiver(android.content.BroadcastReceiver). Cancele o registro do destinatário quando não precisar mais dele ou do não é mais válido.

    Saiba onde registrar e cancelar o registro do destinatário. Por Por exemplo, se você registrar um receptor em onCreate(Bundle) usando o contexto da atividade, deve cancelar o registro em onDestroy() para evitam o vazamento do receptor do contexto da atividade. Se você se registrar um receptor em onResume(), deverá cancele a inscrição em onPause() para evitar registrá-la várias vezes (se não quiser receber transmissões quando pausado, e isso pode reduzir a sobrecarga desnecessária do sistema). Não cancelar o registro em onSaveInstanceState(Bundle), porque ele não é chamado se o usuário voltar para a pilha de histórico.

Efeitos no estado do processo

Não importa se o BroadcastReceiver estiver em operação ou não afetar seu processo, o que pode alterar a probabilidade de encerramento do sistema. Um processo em primeiro plano executa o método onReceive() de um receptor. A executa o processo, exceto sob pressão extrema de memória.

O BroadcastReceiver é desativado após onReceive(). O host do destinatário processo é tão importante quanto os componentes do aplicativo. Se esse processo hospedar apenas um receptor declarado por manifesto (uma ocorrência frequente em apps em que o usuário nunca ou não tenha interagido recentemente), o sistema poderá eliminá-lo após onReceive() para tornar recursos disponíveis para outros processos mais críticos.

Assim, os broadcast receivers não devem iniciar linhas de execução de longa duração em segundo plano. O sistema pode interromper o processo a qualquer momento após onReceive() para recuperar memória, encerrando a thread criada. Para manter o processo ativo, agende uma JobService do receptor usando JobScheduler. para que o sistema saiba que o processo ainda está funcionando. A Visão geral do trabalho em segundo plano fornece mais detalhes.

Como enviar transmissões

O Android oferece três maneiras para os apps enviarem transmissões:

  • O sendOrderedBroadcast(Intent, String) envia transmissões para um receptor por vez. À medida que cada receptor é executado, por sua vez, pode propagar um resultado para o próximo receptor ou pode cancela completamente a transmissão para que ela não seja transmitida a outros receptores. Os receptores de pedidos executados podem ser controlados com o Atributo android:priority do filtro de intent correspondente com o valor com a mesma prioridade serão executados em ordem arbitrária.
  • O método sendBroadcast(Intent) envia transmite para todos os receptores em uma ordem indefinida. Isso é chamado de Transmissão. Isso é mais eficiente, mas significa que os receptores não podem ler resultados de outros receptores, propagar dados recebidos da transmissão ou cancelar a transmissão.

O snippet de código a seguir demonstra como enviar uma transmissão criando uma Intent e chamar 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);

A mensagem de transmissão é agrupada em um objeto Intent. A string de ação da intent deve fornecer a sintaxe do nome do pacote Java do aplicativo e identificam exclusivamente o evento de transmissão. Você pode anexar informações adicionais à intent com putExtra(String, Bundle). Também é possível limitar uma transmissão a um conjunto de apps na mesma organização chamando setPackage(String) na intent.

Como restringir transmissões com permissões

Com as permissões, você pode restringir as transmissões ao conjunto de apps que contêm determinadas permissões. É possível aplicar restrições ao remetente ou receptor de uma transmissão.

Como enviar com permissões

Quando você ligar para sendBroadcast(Intent, String) ou sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle), é possível especificar . Somente os receptores que solicitaram essa permissão com a tag no manifesto e, consequentemente, receberam o permissão se for perigoso) receber a transmissão. Por exemplo, o o código a seguir envia uma transmissão:

Kotlin

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

Java

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

Para receber a transmissão, o app de destino precisa solicitar a permissão como mostrados abaixo:

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

É possível especificar uma permissão de sistema existente, como BLUETOOTH_CONNECT ou definir uma permissão personalizada com o Elemento <permission>. Para informações sobre permissões e segurança em geral, consulte a página do Permissões.

Como receber com permissões

Se você especificar um parâmetro de permissão ao registrar um broadcast receiver (com registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) ou em tag <receiver> na sua manifesto), somente as emissoras que solicitaram a permissão com o Tag <uses-permission> em seu manifesto (e, subsequentemente, receber a permissão se for perigoso) pode enviar uma intent ao destinatário.

Por exemplo, suponha que o app de recebimento tenha um receptor declarado pelo manifesto como mostrados abaixo:

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

Ou o app de recebimento tenha um receptor registrado pelo contexto, conforme mostrado abaixo:

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

Então, para poder enviar transmissões para esses receptores, o app de envio precisa solicitar a permissão conforme mostrado abaixo:

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

Considerações de segurança e práticas recomendadas

Aqui estão algumas considerações de segurança e práticas recomendadas para enviar e recebendo transmissões:

  • Se vários aplicativos estiverem registrados para receber a mesma transmissão em seu ele pode fazer com que o sistema inicie muitos aplicativos, causando uma impacto significativo no desempenho do dispositivo e na experiência do usuário. Para evitar isso, prefira usar o registro de contexto na declaração do manifesto. Às vezes, o próprio sistema Android aplica o uso de dados receptores. Por exemplo, a transmissão CONNECTIVITY_ACTION é entregue apenas para receptores registrados pelo contexto.

  • Não transmita informações confidenciais usando um intent implícito. A informações podem ser lidas por qualquer aplicativo que se registre para receber a transmissão. Existem três maneiras de controlar quem pode receber suas transmissões:

    • Você pode especificar uma permissão enviando uma transmissão.
    • No Android 4.0 e versões mais recentes, package com setPackage(String) ao enviar uma transmissão. O sistema restringe a transmissão ao conjunto de aplicativos que corresponder ao pacote.
  • Quando você registra um receptor, qualquer app pode enviar transmite para o receptor do seu app. Há várias maneiras de limitar o transmissões que o app recebe:

    • Você pode especificar uma permissão registrando um broadcast receiver.
    • Para receptores declarados pelo manifesto, é possível definir o android:exported (link em inglês) atributo como "false" no manifesto. O destinatário não recebe transmissões de fontes externas ao app.
  • O namespace das ações de transmissão é global. Certifique-se de que os nomes de ação e outras strings sejam escritas em um namespace de sua propriedade. Caso contrário, você pode entrar em conflito inadvertidamente com outros aplicativos.

  • Como o método onReceive(Context, Intent) de um receptor é executado linha de execução principal, ele precisa ser executado e retornar rapidamente. Se você precisar executar trabalhos de longa duração, tome cuidado ao gerar linhas de execução ou serviços em segundo plano porque o sistema pode encerrar todo o processo após onReceive() retorna. Para mais informações, consulte Efeito no processo state Para realizar um trabalho de longa duração, recomendamos:

    • Ligando para goAsync() no seu método onReceive() do receptor e transmitindo o BroadcastReceiver.PendingResult para uma linha de execução em segundo plano. Isso mantém a transmissão ativa após retornar de onReceive(). No entanto, mesmo com essa abordagem, o sistema espera que você termine com a transmissão muito rapidamente (menos de 10 segundos). Ele permite que você se mova trabalham em outra linha de execução para evitar falhas na linha de execução principal.
    • programar um trabalho com JobScheduler. Para mais informações, consulte Serviço inteligente de Agendamento.
  • Não iniciar atividades de broadcast receivers porque a experiência do usuário é desagradável. especialmente se houver mais de um receptor. Em vez disso, considere exibindo uma notificação.