Os apps Android podem enviar ou receber mensagens de transmissão do sistema Android e de outros apps Android, de maneira semelhante ao padrão de design publicação/assinatura. Essas transmissões são enviadas quando ocorre um evento de interesse. Por exemplo, o sistema Android envia transmissões quando ocorrem vários eventos, como quando o sistema é inicializado ou o dispositivo começa a carregar. Os apps também podem enviar transmissões personalizadas, por exemplo, para notificar outros apps sobre algo que possam ser do interesse deles (por exemplo, alguns dados novos foram transferidos por download).
O sistema otimiza a entrega de transmissões para manter a integridade ideal. Portanto, os tempos de entrega das transmissões não são garantidos. Os apps que precisam de comunicação entre processos de baixa latência precisam considerar serviços vinculados.
Os apps podem se registrar para receber transmissões específicas. Quando uma transmissão é enviada, o sistema a roteia automaticamente para apps que se inscreveram para 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, tenha cuidado para não abusar da 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, como quando ele entra e sai do modo avião. As transmissões do sistema são enviadas para todos os apps inscritos para receber o evento.
A própria mensagem de transmissão é unida em um objeto
Intent
com uma string de ação que identifica o evento que ocorreu (por exemplo,
android.intent.action.AIRPLANE_MODE
). A intent também pode incluir
outras informações agrupadas no campo extra. Por exemplo, a intent
do modo avião inclui um booleano extra que indica se o modo
está ativado ou não.
Para saber mais sobre como ler intents e extrair a string de ação de uma intent, consulte Intents e filtros de intents.
Para conferir uma lista completa das ações de transmissão do sistema, consulte o
arquivo BROADCAST_ACTIONS.TXT
no SDK do Android. Cada ação de transmissão tem um
campo de constante associado a ela. Por exemplo, o valor da constante
ACTION_AIRPLANE_MODE_CHANGED
é
android.intent.action.AIRPLANE_MODE
. A 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 o comportamento das transmissões do sistema. Lembre-se das seguintes mudanças para oferecer compatibilidade com todas as versões do Android.
Android 14
Enquanto os apps estão em um estado
em cache, a entrega de transmissão é
otimizada para a integridade do sistema. Por exemplo, transmissões menos importantes do sistema, como
ACTION_SCREEN_ON
, são
adiadas enquanto o app está em cache. Quando o app passa do estado
em cache para um ciclo de vida
de processo ativo, o sistema entrega
todas as transmissões adiadas.
As transmissões importantes declaradas no manifesto removem temporariamente os apps do estado em cache para entrega.
Android 9
No Android 9 (nível 28 da API) e versões mais recentes, a transmissão
NETWORK_STATE_CHANGED_ACTION
não recebe informações sobre a localização do usuário ou dados de identificação
pessoal.
Além disso, se o app estiver instalado em um dispositivo com o Android 9 ou versões mais recentes,
as transmissões do sistema pelo Wi-Fi não vão conter SSIDs, BSSIDs, informações
de conexão nem resultados de verificação. Para acessar essas informações, chame
getConnectionInfo()
.
Android 8.0
No Android 8.0 (nível 26 da API) e versões mais recentes, o sistema impõe outras restrições aos receptores declarados pelo manifesto.
Se o app for destinado ao Android 8.0 ou versões mais recentes, não será possível usar o manifesto para declarar um receptor para a maioria das transmissões implícitas, ou seja, transmissões que não são direcionadas ao app especificamente. Você ainda pode usar um receptor registrado pelo contexto quando o usuário estiver usando o app ativamente.
Android 7.0
O Android 7.0 (nível 24 da API) e versões mais recentes não enviam as seguintes transmissões do sistema:
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 vai iniciar seu app (se ele ainda não estiver em execução) quando a transmissão for enviada.
Para declarar um broadcast receiver no manifesto, siga as seguintes etapas:
Especifique o elemento
<receiver>
no manifesto do 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.
Coloque
BroadcastReceiver
em uma subclasse e implementeonReceive(Context, Intent)
. O broadcast receiver no exemplo abaixo registra e mostra 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 arquivo build.gradle no nível 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 no app, o que significa que o sistema pode iniciar o app e enviar a transmissão se ele não estiver em execução.
O sistema cria um novo objeto de componente BroadcastReceiver
para processar cada transmissão recebida. Esse objeto é válido apenas
durante a chamada para onReceive(Context, Intent)
. Depois que o código
retornar desse método, o sistema vai considerar que o componente não está mais
ativo.
Receptores registrados pelo contexto
Os receptores registrados pelo contexto recebem transmissões, desde que o contexto
de registro seja válido. Por exemplo, se você se registrar em um
contexto
Activity
,
vai receber 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 app
esteja em execução.
Para registrar um receptor com um contexto, siga as seguintes etapas:
No arquivo de build do módulo do app, inclua a versão 1.9.0 ou mais recente 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") }
Crie uma instância de
BroadcastReceiver
:Kotlin
val br: BroadcastReceiver = MyBroadcastReceiver()
Java
BroadcastReceiver br = new MyBroadcastReceiver();
Crie uma instância de
IntentFilter
:Kotlin
val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
Java
IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
Escolha se o broadcast receiver será exportado e ficará visível para outros apps no dispositivo. Se o receptor estiver ouvindo transmissões enviadas pelo sistema ou por outros apps, mesmo que sejam seus, use a flag
RECEIVER_EXPORTED
. Se, em vez disso, o receptor estiver ouvindo apenas para transmissões enviadas pelo app, use a 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; }
Registre o receptor chamando
registerReceiver()
:Kotlin
ContextCompat.registerReceiver(context, br, filter, receiverFlags)
Java
ContextCompat.registerReceiver(context, br, filter, receiverFlags);
Para parar de receber transmissões, chame
unregisterReceiver(android.content.BroadcastReceiver)
. Cancele o registro do receptor quando não precisar mais dele ou o contexto não for mais válido.Atente-se ao local em que você registra e cancela o registro do receptor. Por exemplo, se você registrar um receptor em
onCreate(Bundle)
usando o contexto da atividade, cancele o registro dele emonDestroy()
para evitar vazamento do receptor para fora do contexto da atividade. Se você registrar um receptor emonResume()
, cancele o registro emonPause()
para evitar o registro várias vezes. Se você não quiser receber transmissões quando pausado, o que poderá reduzir a sobrecarga desnecessária do sistema. Não cancele o registro emonSaveInstanceState(Bundle)
, porque isso não será chamado se o usuário voltar para a pilha do histórico.
Efeitos no estado do processo
Se a BroadcastReceiver
está operando ou não, isso afeta o processo contido, o que pode alterar
a probabilidade de destruição do sistema. Um processo em primeiro plano executa o método onReceive()
de um receptor. O
sistema executa o processo, exceto sob pressão extrema de memória.
O BroadcastReceiver é desativado após onReceive()
. O processo do host
do receptor é tão importante quanto os componentes do app. Se esse processo hospedar apenas
um receptor declarado pelo manifesto, que é uma ocorrência frequente para apps com que o usuário nunca
interagiu recentemente, o sistema poderá eliminá-lo após onReceive()
para disponibilizar
recursos para outros processos mais essenciais.
Portanto, os broadcast receivers não devem iniciar linhas de execução em segundo plano de longa duração.
O sistema pode interromper o processo a qualquer momento após onReceive()
para liberar
memória, encerrando a linha de execução criada. Para manter o processo ativo, programe um
JobService
do receptor usando o JobScheduler
para que o sistema saiba que o processo ainda está funcionando.
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 método
sendOrderedBroadcast(Intent, String)
envia transmissões para um receptor por vez. À medida que cada receptor é executado, ele pode propagar um resultado para o próximo receptor ou pode cancelar completamente a transmissão para que ela não seja transmitida para outros receptores. Os receptores de pedidos executados podem ser controlados com o atributo android:priority do filtro de intent correspondente. Os receptores com a mesma prioridade serão executados em uma ordem arbitrária. - O método
sendBroadcast(Intent)
envia transmissões para todos os receptores em uma ordem indefinida. Isso é chamado de transmissão normal. 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 abaixo demonstra como enviar uma transmissão criando uma
intent e chamando 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 precisa fornecer a sintaxe do nome do pacote Java do app e
identificar de maneira exclusiva o evento de transmissão. É possível anexar outras informações
à intent usando putExtra(String, Bundle)
.
Também é possível limitar uma transmissão a um conjunto de apps da mesma organização
chamando setPackage(String)
na intent.
Como restringir transmissões com permissões
Com elas, é possível restringir transmissões ao conjunto de apps que têm determinadas permissões. Você pode impor restrições ao remetente ou ao receptor de uma transmissão.
Como enviar com permissões
Ao chamar sendBroadcast(Intent, String)
ou
sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
, você pode especificar um
parâmetro de permissão. Somente os receptores que solicitaram essa permissão com
a tag
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, conforme mostrado abaixo:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
É possível especificar uma permissão do sistema já 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 as Permissões
do sistema.
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 na tag
<receiver>
no
manifesto), somente as emissoras que solicitaram a permissão com a tag
<uses-permission>
no manifesto (e que receberam a permissão se ela for
perigosa) poderão enviar uma intent ao receiver.
Por exemplo, suponha que o app de recebimento tenha um receptor declarado pelo manifesto, conforme mostrado 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 );
Para enviar transmissões a 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
Confira algumas considerações de segurança e práticas recomendadas para enviar e receber transmissões:
Se muitos apps se registrarem para receber a mesma transmissão no manifesto, o sistema poderá iniciar vários apps, causando um impacto significativo no desempenho do dispositivo e na experiência do usuário. Para evitar isso, prefira usar o registro de contexto em vez da declaração de manifesto. Às vezes, o próprio sistema Android impõe o uso de receptores registrados por contexto. Por exemplo, a transmissão
CONNECTIVITY_ACTION
é entregue apenas a receptores registrados pelo contexto.Não transmita informações confidenciais usando um intent implícito. As informações podem ser lidas por qualquer app 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, é possível especificar um
pacote com
setPackage(String)
ao enviar uma transmissão. O sistema restringe a transmissão ao conjunto de apps que correspondem ao pacote.
Quando você registra um receptor, qualquer app pode enviar transmissões potencialmente maliciosas a ele. Há várias maneiras de limitar as transmissões recebidas pelo app:
- Você pode especificar uma permissão registrando um broadcast receiver.
- Para receptores declarados pelo manifesto, você pode definir o atributo android:exported como "false" no manifesto. O receptor 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 gravados em um namespace seu. Caso contrário, você pode entrar em conflito inadvertida com outros apps.
Como o método
onReceive(Context, Intent)
de um receptor é executado na linha de execução principal, ele precisa ser executado e retornar rapidamente. Se você precisar realizar um trabalho de longa duração, tenha cuidado ao gerar linhas de execução ou iniciar serviços em segundo plano, porque o sistema pode encerrar todo o processo depois queonReceive()
retornar. Para mais informações, consulte Efeito no estado do processo. Para executar trabalhos de longa duração, recomendamos:- Chamar
goAsync()
no métodoonReceive()
do receptor e transmitirBroadcastReceiver.PendingResult
para uma linha de execução em segundo plano. Isso mantém a transmissão ativa após retornar deonReceive()
. No entanto, mesmo com essa abordagem, o sistema espera que você termine a transmissão muito rapidamente (menos de 10 segundos). Isso permite que você mova o trabalho para outra linha de execução para evitar uma falha na linha principal. - programar um trabalho com
JobScheduler
. Para mais informações, consulte Programação inteligente de jobs.
- Chamar
Não inicie atividades em broadcast receivers, porque a experiência do usuário é desagradável, especialmente se houver mais de um receptor. Em vez disso, exiba uma notificação.