Uma Intent é um objeto de mensagem que pode ser usado para solicitar uma ação
de outro componente do app.
Embora as intents facilitem a comunicação entre componentes de várias maneiras, há três
casos de uso fundamentais:
- Como iniciar uma atividade
Uma
Activityrepresenta uma única tela em um app. É possível iniciar uma nova instância de umaActivitytransmitindo umaIntentparastartActivity(). AIntentdescreve a atividade a ser iniciada e carrega os dados necessários.Se você quiser receber um resultado da atividade quando ela for concluída, chame
startActivityForResult(). A atividade recebe o resultado como um objetoIntentseparado no callbackonActivityResult()da atividade. Para mais informações, consulte o guia Atividades. - Como iniciar um serviço
Um
Serviceé um componente que executa operações em segundo plano sem uma interface do usuário. No Android 5.0 (nível 21 da API) e versões mais recentes, é possível iniciar um serviço comJobScheduler. Para mais informações sobreJobScheduler, consulte oAPI-reference documentation.Para versões anteriores ao Android 5.0 (nível 21 da API), é possível iniciar um serviço usando métodos da classe
Service. É possível iniciar um serviço para realizar uma operação única (como fazer o download de um arquivo) transmitindo umIntentparastartService(). OIntentdescreve o serviço a ser iniciado e carrega todos os dados necessários.Se o serviço for projetado com uma interface cliente-servidor, será possível se vincular ao serviço de outro componente transmitindo um
IntentparabindService(). Para mais informações, consulte o guia Serviços. - Como enviar uma transmissão
Uma transmissão é uma mensagem que qualquer app pode receber. O sistema envia várias transmissões para eventos do sistema, como quando o sistema é inicializado ou o dispositivo começa a carregar. É possível enviar uma transmissão para outros apps transmitindo um
IntentparasendBroadcast()ousendOrderedBroadcast().
O restante desta página explica como as intents funcionam e como usá-las. Para informações relacionadas, consulte Como interagir com outros apps e Como compartilhar conteúdo.
Tipos de intent
Há dois tipos de intents:
- As intents explícitas especificam qual componente de qual aplicativo vai atender à intent, especificando um
ComponentNamecompleto. Normalmente, você usa uma intent explícita para iniciar um componente no seu próprio app, porque sabe o nome da classe da atividade ou do serviço que quer iniciar. Por exemplo, você pode iniciar uma nova atividade no app em resposta a uma ação do usuário ou iniciar um serviço para fazer o download de um arquivo em segundo plano. - As intents implícitas não nomeiam um componente específico, mas declaram uma ação geral a ser realizada, o que permite que um componente de outro app a processe. Por exemplo, se você quiser mostrar ao usuário um local em um mapa, use uma intent implícita para solicitar que outro app capaz mostre um local especificado em um mapa.
A Figura 1 mostra como uma intent é usada ao iniciar uma atividade. Quando o objeto
Intent nomeia explicitamente um componente de atividade específico, o sistema
inicia esse componente imediatamente.
Figura 1. Como uma intent implícita é
enviada pelo sistema para iniciar outra atividade: [1] A Atividade A cria uma
Intent com uma descrição de ação e a transmite para startActivity(). [2] O sistema Android pesquisa em todos os
apps um filtro de intent que corresponda à intent. Quando uma correspondência é encontrada, [3] o sistema
inicia a atividade correspondente (Atividade B) invocando o método onCreate() e transmitindo o Intent.
Quando você usa uma intent implícita, o sistema Android encontra o componente adequado para iniciar
comparando o conteúdo da intent com os filtros de intent declarados no arquivo de manifesto de outros apps no
dispositivo. Se a intent corresponder a um filtro de intent, o sistema vai iniciar esse componente e enviar o objeto Intent para ele. Se vários filtros de intent forem compatíveis, o sistema
vai mostrar uma caixa de diálogo para que o usuário escolha qual app usar.
Um filtro de intent é uma expressão no arquivo de manifesto de um app que especifica o tipo de intent que o componente gostaria de receber. Por exemplo, ao declarar um filtro de intent para uma atividade, você permite que outros apps iniciem diretamente sua atividade com um determinado tipo de intent. Da mesma forma, se você não declarar nenhum filtro de intent para uma atividade, ela só poderá ser iniciada com uma intent explícita.
Cuidado:para garantir que o app esteja seguro, sempre
use uma intent explícita
ao iniciar um Service e não
declare filtros de intent para os serviços. O uso de uma intent implícita para iniciar um serviço representa um
risco de segurança, porque não é possível determinar qual serviço responderá à intent,
e o usuário não poderá ver qual serviço será iniciado. No Android 5.0 (nível 21 da API) e versões mais recentes, o sistema
gera uma exceção quando você chama bindService()
com uma intent implícita.
Como criar uma intent
Um objeto Intent carrega informações que o sistema Android usa
para determinar qual componente iniciar (como o nome ou a categoria exata do componente
que deve receber a intent), além de informações que o componente receptor usa para
executar a ação corretamente (como a ação a ser realizada e os dados a serem usados).
As principais informações contidas em um Intent são as seguintes:
- Nome do componente
- O nome do componente a ser iniciado.
Isso é opcional, mas é a informação essencial que torna uma intent explícita, o que significa que ela precisa ser entregue apenas ao componente do app definido pelo nome do componente. Sem um nome de componente, a intent é implícita, e o sistema decide qual componente deve receber a intent com base nas outras informações dela, como a ação, os dados e a categoria, descritos abaixo. Se você precisar iniciar um componente específico no app, especifique o nome dele.
Observação:ao iniciar um
Service, sempre especifique o nome do componente. Caso contrário, não é possível determinar qual serviço vai responder à intent, e o usuário não pode conferir qual serviço será iniciado.Esse campo do
Intenté um objetoComponentName, que pode ser especificado usando um nome de classe totalmente qualificado do componente de destino, incluindo o nome do pacote do app, por exemplo,com.example.ExampleActivity. É possível definir o nome do componente comsetComponent(),setClass(),setClassName()ou com o construtorIntent. - Ação
- String que especifica a ação genérica a ser executada (como view ou pick).
No caso de uma intent de transmissão, essa é a ação que ocorreu e está sendo informada. A ação determina em grande parte como o restante da intent é estruturado, principalmente as informações contidas nos dados e extras.
É possível especificar suas próprias ações para uso por intents no seu app (ou para uso por outros apps para invocar componentes no seu app), mas geralmente você especifica constantes de ação definidas pela classe
Intentou outras classes de framework. Confira algumas ações comuns para iniciar uma atividade:ACTION_VIEW- Use essa ação em uma intent com
startActivity()quando tiver algumas informações que uma atividade pode mostrar ao usuário, como uma foto para visualizar em um app de galeria ou um endereço para visualizar em um app de mapas. ACTION_SEND- Também conhecida como intent de compartilhamento, ela deve ser usada em uma intent com
startActivity()quando você tem dados que o usuário pode compartilhar por outro app, como um app de e-mails ou de compartilhamento em redes sociais.
Consulte a referência da classe
Intentpara ver mais constantes que definem ações genéricas. Outras ações são definidas em outras partes do framework do Android, como emSettingspara ações que abrem telas específicas no app Configurações do sistema.É possível especificar a ação de uma intent com
setAction()ou com um construtorIntent.Se você definir suas próprias ações, inclua o nome do pacote do app como um prefixo, conforme mostrado no exemplo a seguir:
Kotlin
const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"
Java
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
- Dados
- O URI (um objeto
Uri) que faz referência aos dados que serão processados e/ou ao tipo MIME desses dados. O tipo de dados fornecido geralmente é determinado pela ação da intent. Por exemplo, se a ação forACTION_EDIT, os dados precisam conter o URI do documento a ser editado.Ao criar uma intent, geralmente é importante especificar o tipo de dados (o tipo MIME) além do URI. Por exemplo, uma atividade que pode mostrar imagens provavelmente não poderá reproduzir um arquivo de áudio, mesmo que os formatos de URI sejam semelhantes. Especificar o tipo MIME dos dados ajuda o sistema Android a encontrar o melhor componente para receber a intent. No entanto, o tipo MIME às vezes pode ser inferido do URI, principalmente quando os dados são um URI
content:. Um URIcontent:indica que os dados estão localizados no dispositivo e são controlados por umContentProvider, o que torna o tipo MIME dos dados visível para o sistema.Para definir apenas o URI de dados, chame
setData(). Para definir apenas o tipo MIME, chamesetType(). Se necessário, é possível definir ambos explicitamente comsetDataAndType().Atenção:se você quiser definir o URI e o tipo MIME, não chame
setData()esetType(), porque cada um deles anula o valor do outro. Sempre usesetDataAndType()para definir o URI e o tipo MIME. - Categoria
- Uma string que contém informações adicionais sobre o tipo de componente
que deve processar a intent. Qualquer número de descrições de categoria pode ser
colocado em uma intent, mas a maioria das intents não exige uma categoria.
Confira algumas categorias comuns:
CATEGORY_BROWSABLE- A atividade de destino permite que um navegador da Web a inicie para mostrar dados referenciados por um link, como uma imagem ou uma mensagem de e-mail.
CATEGORY_LAUNCHER- A atividade é a inicial de uma tarefa e está listada no inicializador do aplicativo do sistema.
Consulte a descrição da classe
Intentpara ver a lista completa de categorias.É possível especificar uma categoria com
addCategory().
Essas propriedades listadas acima (nome do componente, ação, dados e categoria) representam as características de definição de uma intent. Ao ler essas propriedades, o sistema Android pode resolver qual componente do app deve ser iniciado. No entanto, uma intent pode conter informações adicionais que não afetam como ela é resolvida para um componente do app. Uma intent também pode fornecer as seguintes informações:
- Extras
- Pares de chave-valor que carregam informações adicionais necessárias para realizar
a ação solicitada.
Assim como algumas ações usam tipos específicos de URIs de dados, algumas também usam extras específicos.
É possível adicionar mais dados com vários métodos
putExtra(), cada um aceitando dois parâmetros: o nome da chave e o valor. Também é possível criar um objetoBundlecom todos os dados extras e inserir oBundlenoIntentcomputExtras().Por exemplo, ao criar uma intent para enviar um e-mail com
ACTION_SEND, é possível especificar o destinatário to com a chaveEXTRA_EMAILe o subject com a chaveEXTRA_SUBJECT.A classe
Intentespecifica muitas constantesEXTRA_*para tipos de dados padronizados. Se você precisar declarar suas próprias chaves extras (para intents que seu app recebe), inclua o nome do pacote do app como um prefixo, conforme mostrado no exemplo a seguir:Kotlin
const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"
Java
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
Atenção: não use dados
ParcelableouSerializableao enviar uma intent que você espera que outro app receba. Se um app tentar acessar dados em um objetoBundle, mas não tiver acesso à classe parcelada ou serializada, o sistema vai gerar umaRuntimeException. - Sinalizações
- As flags são definidas na classe
Intentque funciona como metadados para a intent. As flags podem instruir o sistema Android sobre como iniciar uma atividade (por exemplo, a qual tarefa ela deve pertencer) e como tratá-la depois de iniciada (por exemplo, se ela pertence à lista de atividades recentes).Para mais informações, consulte o método
setFlags().
Exemplo de intent explícita
Uma intent explícita é usada para iniciar um componente de app específico, como
uma atividade ou um serviço específico no app. Para criar uma intent explícita, defina
o nome do componente para o objeto Intent. Todas
as outras propriedades de intent são opcionais.
Por exemplo, se você criou um serviço no app, chamado DownloadService,
projetado para fazer o download de um arquivo da Web, é possível iniciá-lo com o seguinte código:
Kotlin
// Executed in an Activity, so 'this' is theContext// The fileUrl is a string URL, such as "http://www.example.com/image.png" val downloadIntent = Intent(this, DownloadService::class.java).apply { data =Uri.parse(fileUrl) } startService(downloadIntent)
Java
// Executed in an Activity, so 'this' is theContext// The fileUrl is a string URL, such as "http://www.example.com/image.png" Intent downloadIntent = new Intent(this, DownloadService.class); downloadIntent.setData(Uri.parse(fileUrl)); startService(downloadIntent);
O construtor Intent(Context, Class)
fornece o Context do app e o
objeto Class do componente. Assim,
essa intent inicia explicitamente a classe DownloadService no app.
Para mais informações sobre como criar e iniciar um serviço, consulte o guia Serviços.
Exemplo de intent implícita
Uma intent implícita especifica uma ação que pode invocar qualquer app no dispositivo capaz de realizar a ação. Usar uma intent implícita é útil quando o app não pode realizar a ação, mas outros apps provavelmente podem, e você quer que o usuário escolha qual app usar.
Por exemplo, se você tiver conteúdo que quer que o usuário compartilhe com outras pessoas,
crie uma intent
com a ação ACTION_SEND
e adicione extras que especifiquem o conteúdo a ser compartilhado. Quando você chama
startActivity() com essa intent, o usuário pode
escolher um app para compartilhar o conteúdo.
Kotlin
// Create the text message with a string. val sendIntent = Intent().apply { action = Intent.ACTION_SEND putExtra(Intent.EXTRA_TEXT, textMessage) type = "text/plain" } // Try to invoke the intent. try { startActivity(sendIntent) } catch (e: ActivityNotFoundException) { // Define what your app should do if no activity can handle the intent. }
Java
// Create the text message with a string. Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType("text/plain"); // Try to invoke the intent. try { startActivity(sendIntent); } catch (ActivityNotFoundException e) { // Define what your app should do if no activity can handle the intent. }
Quando startActivity() é chamado, o sistema
examina todos os apps instalados para determinar quais podem processar esse tipo de intent (uma
intent com a ação ACTION_SEND e que carrega dados "text/plain"). Se houver apenas um app que possa processá-la, ele será aberto imediatamente e receberá a
intent. Se nenhum outro app puder processá-la, seu app poderá capturar a
ActivityNotFoundException
que ocorrer. Se várias atividades aceitarem a intent, o sistema
vai mostrar uma caixa de diálogo como a da Figura 2 para que o usuário escolha qual app usar.
Mais informações sobre como iniciar outros apps também são fornecidas no guia sobre como enviar o usuário para outro app.
Figura 2. Caixa de diálogo seletora.
Forçar um seletor de apps
Quando há mais de um app que responde à sua intent implícita, o usuário pode selecionar qual app usar e torná-lo a escolha padrão para a ação. A capacidade de selecionar um padrão é útil ao realizar uma ação para qual o usuário provavelmente quer usar o mesmo app todas as vezes, por exemplo, ao abrir uma página da web (os usuários geralmente preferem apenas um navegador da web).
No entanto, se vários apps puderem responder à intent e o usuário quiser usar um app diferente
a cada vez, mostre explicitamente uma caixa de diálogo de seletor. A caixa de diálogo de escolha pede que o
usuário selecione qual app usar para a ação (o usuário não pode selecionar um app padrão para
a ação). Por exemplo, quando o app realiza um "compartilhamento" com a ação ACTION_SEND, os usuários podem querer compartilhar usando um app diferente, dependendo
da situação atual. Por isso, use sempre a caixa de diálogo seletora, como mostrado na Figura 2.
Para mostrar o seletor, crie uma Intent usando createChooser() e transmita-a para startActivity(), conforme mostrado no exemplo a seguir.
Este exemplo mostra uma caixa de diálogo com uma lista de apps que respondem à intent transmitida ao método createChooser() e usa o texto fornecido como o
título da caixa de diálogo.
Kotlin
val sendIntent = Intent(Intent.ACTION_SEND) ... // Always use string resources for UI text. // This says something like "Share this photo with" val title: String = resources.getString(R.string.chooser_title) // Create intent to show the chooser dialog val chooser: Intent = Intent.createChooser(sendIntent, title) // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(packageManager) != null) { startActivity(chooser) }
Java
Intent sendIntent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. // This says something like "Share this photo with" String title = getResources().getString(R.string.chooser_title); // Create intent to show the chooser dialog Intent chooser = Intent.createChooser(sendIntent, title); // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
Detectar inicializações de intent não seguras
Seu app pode iniciar intents para navegar entre componentes dentro dele ou para realizar uma ação em nome de outro app. Para melhorar a segurança da plataforma, o Android 12 (nível 31 da API) e versões mais recentes oferecem um recurso de depuração que avisa se o app realizar uma inicialização não segura de uma intent. Por exemplo, seu app pode fazer uma inicialização não segura de uma intent aninhada, que é uma intent transmitida como um extra em outra intent.
Se o app realizar as duas ações a seguir, o sistema vai detectar uma inicialização de intent não segura e ocorrerá uma violação de StrictMode:
- O app separa as intents aninhadas das outras intents enviadas.
- O app imediatamente inicia um componente
do app usando essa intent aninhada,
como ao transmitir a intent para
startActivity(),startService()oubindService().
Para mais detalhes sobre como identificar essa situação e fazer mudanças no app, leia a postagem do blog sobre intents de aninhamento do Android (link em inglês) no Medium.
Verificar se há inicializações de intent não seguras
Para verificar se há inicializações de intents não seguras no app, chame
detectUnsafeIntentLaunch()
ao configurar o VmPolicy, conforme mostrado no snippet de código a seguir. Se o app detectar uma violação do StrictMode, interrompa a execução dele para proteger informações sensíveis.
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()) }
Java
protected void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()); }
Usar intents de forma mais responsável
Para minimizar a chance de uma inicialização de intent não segura e uma violação do StrictMode, siga estas práticas recomendadas.
Copie apenas os extras essenciais nas intents e execute todas as limpezas
e validações necessárias. O app pode copiar os extras de uma intent para
outra usada para iniciar um novo componente. Isso ocorre quando o
app chama
putExtras(Intent)
ou
putExtras(Bundle).
Se o app executar uma dessas operações, copie apenas os extras esperados
pelo componente de recebimento. Se a outra intent (que recebe a cópia)
iniciar um componente que não foi
exportado, limpe e
valide os extras antes de copiá-los para a intent que inicia
o componente.
Não exporte os componentes do app desnecessariamente. Por exemplo, se você
pretende iniciar um componente de app usando uma intent aninhada interna, defina o
atributo android:exported desse componente como false.
Use uma PendingIntent em vez de uma
intent aninhada. Dessa forma, quando outro app desempacotar o PendingIntent da
Intent que o contém, ele poderá iniciar o PendingIntent usando a
identidade do seu app. Essa configuração permite que o outro app inicie com segurança
qualquer componente, incluindo um componente não exportado, no seu app.
O diagrama na figura 2 mostra como o sistema transfere o controle do seu app (cliente) para outro app (serviço) e de volta para o seu app:
- O app cria uma intent que invoca uma atividade em outro app. Nessa
intent, você adiciona um objeto
PendingIntentcomo extra. Essa intent pendente invoca um componente no seu app, que não é exportado. - Ao receber a intent do seu app, o outro app extrai o objeto
PendingIntentaninhado. - O outro app invoca o método
send()no objetoPendingIntent. - Depois de devolver o controle ao app, o sistema invoca a intent pendente usando o contexto do app.
Figura 2. Diagrama de comunicação entre apps ao usar uma intent pendente aninhada.
Receber uma intent implícita
Para anunciar quais intents implícitas seu app pode receber, declare um ou mais filtros de intent para
cada um dos componentes do app com um elemento <intent-filter>
no arquivo de manifesto.
Cada filtro de intent especifica o tipo de intent que ele aceita com base na ação,
nos dados e na categoria da intent. O sistema só vai entregar uma intent implícita ao componente do app se ela
puder passar por um dos seus filtros de intent.
Observação:uma intent explícita é sempre entregue ao destino, independentemente dos filtros de intent declarados pelo componente.
Um componente do app precisa declarar filtros separados para cada tarefa exclusiva que ele pode realizar.
Por exemplo, uma atividade em um app de galeria de imagens pode ter dois filtros: um
para visualizar uma imagem e outro para editá-la. Quando a atividade é iniciada,
ela inspeciona o Intent e decide como se comportar com base nas informações
no Intent (por exemplo, se os controles do editor serão mostrados ou não).
Cada filtro de intent é definido por um elemento <intent-filter>
no arquivo de manifesto do app, aninhado no componente correspondente (como
um elemento <activity>).
Em cada componente do app que inclui um elemento <intent-filter>,
defina explicitamente um valor para
android:exported.
Esse atributo indica se o componente do app pode ser acessado por outros apps. Em algumas
situações, como atividades com filtros de intent que incluem a
categoria
LAUNCHER, é útil definir esse atributo como true. Caso contrário,
é mais seguro definir esse atributo como false.
Aviso:se uma atividade, um serviço ou um broadcast
receiver no app usar filtros de intent e não definir explicitamente o valor
para android:exported, o app não poderá ser instalado em um dispositivo com
o Android 12 ou versões mais recentes.
Dentro do <intent-filter>,
é possível especificar o tipo de intents a serem aceitas usando um ou mais
destes três elementos:
<action>- Declara a ação de intent aceita no atributo
name. O valor precisa ser o valor de string literal de uma ação, não a constante de classe. <data>- Declara o tipo de dados aceito, usando um ou mais atributos que especificam vários
aspectos do URI de dados (
scheme,host,port,path) e o tipo MIME. <category>- Declara a categoria de intent aceita no atributo
name. O valor precisa ser o valor literal da string de uma ação, não a constante da classe.Observação:para receber intents implícitas, inclua a categoria
CATEGORY_DEFAULTno filtro de intents. Os métodosstartActivity()estartActivityForResult()tratam todas as intents como se elas declarassem a categoriaCATEGORY_DEFAULT. Se você não declarar essa categoria no filtro de intent, nenhuma intent implícita será resolvida para sua atividade.
Por exemplo, esta é uma declaração de atividade com um filtro de intent para receber uma
intent ACTION_SEND quando o tipo de dados é texto:
<activity android:name="ShareActivity" android:exported="false"> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> </activity>
É possível criar um filtro que inclua mais de uma instância de
<action>,
<data> ou
<category>.
Se fizer isso, você precisa ter certeza de que o componente pode lidar com todas as
combinações desses elementos de filtro.
Quando você quer processar vários tipos de intents, mas apenas em combinações específicas de ação, dados e tipo de categoria, é necessário criar vários filtros de intent.
Uma intent implícita é testada em relação a um filtro comparando a intent com cada um dos três elementos. Para ser entregue ao componente, a intent precisa passar nos três testes. Se não houver correspondência com pelo menos um deles, o sistema Android não vai entregar a intent ao componente. No entanto, como um componente pode ter vários filtros de intent, uma intent que não passa por um dos filtros de um componente pode passar por outro. Mais informações sobre como o sistema resolve intents são fornecidas na seção abaixo sobre Resolução de intents.
Atenção : usar um filtro de intent não é uma maneira segura de impedir que outros apps iniciem
seus componentes. Embora os filtros de intent restrinjam um componente para responder apenas a
determinados tipos de intents implícitas, outro app pode iniciar o componente do seu app
usando uma intent explícita se o desenvolvedor determinar os nomes dos componentes.
Se for importante que somente seu próprio app possa iniciar um dos seus componentes,
não declare filtros de intent no manifesto. Em vez disso, defina o atributo
exported
como "false" para esse componente.
Da mesma forma, para evitar a execução acidental do Service de outro app, sempre use uma intent explícita para iniciar seu próprio serviço.
Observação:para todas as atividades, é necessário declarar os filtros de intent no arquivo de manifesto.
No entanto, os filtros para broadcast receivers podem ser registrados dinamicamente chamando
registerReceiver(). Em seguida, cancele o registro do receptor com unregisterReceiver(). Isso permite que o app
detecte transmissões específicas apenas durante um período especificado enquanto o app
está em execução.
Exemplos de filtros
Para demonstrar alguns dos comportamentos do filtro de intent, veja um exemplo do arquivo de manifesto de um app de compartilhamento social:
<activity android:name="MainActivity" android:exported="true"> <!-- This activity is the main entry, should appear in app launcher --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="ShareActivity" android:exported="false"> <!-- This activity handles "SEND" actions with text data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND_MULTIPLE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="application/vnd.google.panorama360+jpg"/> <data android:mimeType="image/*"/> <data android:mimeType="video/*"/> </intent-filter> </activity>
A primeira atividade, MainActivity, é o ponto de entrada principal do app, ou seja, a atividade que
é aberta quando o usuário inicia o app com o ícone na tela de início:
- A ação
ACTION_MAINindica que esse é o ponto de entrada principal e não espera dados de intent. - A categoria
CATEGORY_LAUNCHERindica que o ícone dessa atividade precisa ser colocado no Acesso rápido aos apps do sistema. Se o elemento<activity>não especificar um ícone comicon, o sistema vai usar o ícone do elemento<application>.
Os dois precisam ser pareados para que a atividade apareça no acesso rápido aos apps.
A segunda atividade, ShareActivity, tem como objetivo facilitar o compartilhamento de conteúdo de texto e mídia. Embora os usuários possam entrar nessa atividade navegando até ela em MainActivity,
eles também podem entrar em ShareActivity diretamente de outro app que emite uma intent
implícita que corresponde a um dos dois filtros de intent.
Observação:o tipo MIME
application/vnd.google.panorama360+jpg é um tipo de dados especial que especifica
fotos panorâmicas, que podem ser processadas com as APIs Google
Panorama.
Fazer a correspondência de intents com filtros de intents de outros apps
Se outro app for direcionado ao Android 13 (nível 33 da API) ou versões mais recentes, ele só poderá processar a
intent do seu app se ela corresponder às ações e categorias de um
elemento <intent-filter> nesse outro app. Se o sistema não encontrar uma
correspondência, ele vai gerar uma
ActivityNotFoundException.
O app de envio precisa processar
essa exceção.
Da mesma forma, se você atualizar o app para que ele seja destinado ao Android 13
ou versões mais recentes, todas as intents originadas de apps externos serão entregues a um
componente exportado do seu app somente se essa intent corresponder às ações e
categorias de um elemento <intent-filter> declarado pelo app. Esse comportamento
ocorre independente da versão do SDK de destino do app de envio.
Nos casos a seguir, a correspondência de intent não é aplicada:
- Intents entregues a componentes que não declaram filtros de intent.
- Intents originadas de um mesmo app.
- Intents do sistema, ou seja, as intents enviadas do
UID do sistema (uid=1000). Apps do sistema incluem
system_servere apps que definemandroid:sharedUserIdcomoandroid.uid.system. - Intents originadas de uma raiz.
Saiba mais sobre a correspondência de intent.
Como usar uma intent pendente
Um objeto PendingIntent é um wrapper em torno de um objeto Intent. A finalidade principal de um PendingIntent
é conceder permissão a um aplicativo externo
para usar o Intent contido como se ele fosse executado no próprio
processo do seu app.
Os principais casos de uso de uma intent pendente incluem:
- Declarar uma intent a ser executada quando o usuário realizar uma ação com sua notificação
(o
NotificationManagerdo sistema Android executa oIntent). - Declarar uma intent a ser executada quando o usuário realiza uma ação com o
widget do app
(o app da tela inicial executa o
Intent). - Declarar uma intent a ser executada em um horário futuro especificado (o
AlarmManagerdo sistema Android executa oIntent).
Assim como cada objeto Intent é projetado para ser processado por um tipo específico
de componente do app (um Activity, um Service ou
um BroadcastReceiver), um PendingIntent também precisa ser
criado com a mesma consideração. Ao usar uma intent pendente, seu app não
executa a intent com uma chamada como startActivity(). Em vez disso, declare o tipo de componente pretendido ao criar o
PendingIntent chamando o respectivo método de criação:
PendingIntent.getActivity()para umaIntentque inicia umaActivity.PendingIntent.getService()para umaIntentque inicia umaService.PendingIntent.getBroadcast()para umaIntentque inicia umaBroadcastReceiver.
A menos que seu app esteja recebendo intents pendentes de outros apps,
os métodos acima para criar uma PendingIntent provavelmente são os únicos
métodos PendingIntent de que você vai precisar.
Cada método usa o Context do app atual, a
Intent que você quer encapsular e uma ou mais flags que especificam
como a intent precisa ser usada (por exemplo, se ela pode ser usada mais de uma vez).
Para mais informações sobre o uso de intents pendentes, consulte a documentação de cada um dos respectivos casos de uso, como nos guias de API de Notificações e Widgets de apps.
Especificar a mutabilidade
Se o app for destinado ao Android 12 ou versões mais recentes, será necessário especificar a
mutabilidade de cada objeto PendingIntent criado pelo app. Para declarar que
um determinado objeto PendingIntent é mutável ou imutável, use a flag
PendingIntent.FLAG_MUTABLE
ou
PendingIntent.FLAG_IMMUTABLE, respectivamente.
Se o app tentar criar um objeto PendingIntent
sem definir uma flag de mutabilidade, o sistema vai gerar uma
IllegalArgumentException, e
a seguinte mensagem vai aparecer no Logcat:
PACKAGE_NAME: Targeting S+ (version 31 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.
Criar intents pendentes imutáveis sempre que possível
Na maioria dos casos, o app precisa criar objetos PendingIntent imutáveis, conforme
mostrado no snippet de código a seguir. Se um objeto PendingIntent for imutável,
outros apps não poderão modificar a intent para ajustar o resultado da invocação
dela.
Kotlin
val pendingIntent = PendingIntent.getActivity(applicationContext, REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE)
Java
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE);
No entanto, alguns casos de uso exigem objetos PendingIntent mutáveis:
- Suporte a ações de resposta direta em
notificações. A
resposta direta requer uma mudança nos dados do clipe no objeto PendingIntent
associado à resposta. Normalmente, você solicita essa mudança transmitindo
FILL_IN_CLIP_DATAcomo uma flag para o métodofillIn(). - Associar notificações ao framework do Android Auto usando instâncias de
CarAppExtender. - Colocar conversas em balões usando instâncias
de
PendingIntent. Um objetoPendingIntentmutável permite que o sistema aplique as flags corretas, comoFLAG_ACTIVITY_MULTIPLE_TASKeFLAG_ACTIVITY_NEW_DOCUMENT. - Solicitar informações de localização do dispositivo chamando
requestLocationUpdates()ou APIs semelhantes. O objetoPendingIntentmutável permite que o sistema adicione extras de intent que representam eventos de ciclo de vida de localização. Esses eventos incluem uma mudança no local e um provedor que se torna disponível. - Programar alarmes usando
AlarmManager. O objetoPendingIntentmutável permite que o sistema adicione o intent extraEXTRA_ALARM_COUNT. Esse extra representa o número de vezes que um alarme repetido foi acionado. Ao conter esse extra, a intent pode notificar um app com precisão se um alarme recorrente foi acionado várias vezes, como quando o dispositivo estava em modo de suspensão.
Se o app criar um objeto PendingIntent mutável, é altamente recomendável
usar uma intent explícita e preencher o
ComponentName. Dessa forma, todas as vezes que
outro app invocar PendingIntent e devolver o controle para o app, o
mesmo componente será iniciado.
Usar intents explícitas em intents pendentes
Para definir melhor como outros apps podem usar as intents pendentes do seu app, sempre as envolva em uma intent explícita. Para seguir essa prática recomendada, faça o seguinte:
- Verifique se os campos de ação, pacote e componente da intent de base estão definidos.
-
Use
FLAG_IMMUTABLE, adicionado no Android 6.0 (nível 23 da API), para criar intents pendentes. Essa flag impede que apps que recebem umaPendingIntentpreencham propriedades não preenchidas. Se ominSdkVersiondo app for22ou anterior, você poderá oferecer segurança e compatibilidade usando o seguinte código:if (Build.VERSION.SDK_INT >= 23) { // Create a PendingIntent using FLAG_IMMUTABLE. } else { // Existing code that creates a PendingIntent. }
Resolução de intents
Quando o sistema recebe uma intent implícita para iniciar uma atividade, ele procura a melhor atividade para a intent, comparando-a com filtros de intent com base em três aspectos:
- Ação.
- Dados (URI e tipo de dados).
- Categoria.
As seções a seguir descrevem como as intents são associadas aos componentes adequados de acordo com a declaração do filtro de intent no arquivo de manifesto de um app.
Teste de ação
Para especificar ações de intent aceitas, um filtro de intent pode declarar zero ou mais
elementos <action>, como mostrado no exemplo a seguir:
<intent-filter> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.VIEW" /> ... </intent-filter>
Para passar por esse filtro, a ação especificada no Intent
precisa corresponder a uma das ações listadas no filtro.
Se o filtro não listar nenhuma ação, não haverá nada para uma
intent corresponder. Portanto, todas as intents vão falhar no teste. No entanto, se um Intent
não especificar uma ação, ele vai passar no teste, desde que o filtro
contenha pelo menos uma ação.
Teste de categoria
Para especificar as categorias de intent aceitas, um filtro de intent pode declarar zero ou mais elementos <category>, como mostrado no exemplo a seguir:
<intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> ... </intent-filter>
Para que uma intent seja aprovada no teste de categoria, todas as categorias no Intent
precisam corresponder a uma categoria no filtro. O inverso não é necessário: o filtro de intent pode
declarar mais categorias do que as especificadas no Intent, e o
Intent ainda será aprovado. Portanto, uma intent sem categorias
sempre passa nesse teste, independentemente das categorias declaradas no filtro.
Observação:o Android aplica automaticamente a categoria CATEGORY_DEFAULT
a todas as intents implícitas transmitidas para startActivity() e startActivityForResult().
Se você quiser que sua atividade receba intents implícitas, ela precisa
incluir uma categoria para "android.intent.category.DEFAULT" nos filtros de intent, como
mostrado no exemplo anterior de <intent-filter>.
Teste de dados
Para especificar dados de intent aceitos, um filtro de intent pode declarar zero ou mais
elementos <data>, como mostrado no exemplo a seguir:
<intent-filter> <data android:mimeType="video/mpeg" android:scheme="http" ... /> <data android:mimeType="audio/mpeg" android:scheme="http" ... /> ... </intent-filter>
Cada elemento <data>
pode especificar uma estrutura de URI e um tipo de dados (tipo de mídia MIME).
Cada parte do URI é um atributo separado: scheme, host, port e path:
<scheme>://<host>:<port>/<path>
O exemplo a seguir mostra os valores possíveis para esses atributos:
content://com.example.project:200/folder/subfolder/etc
Nesse URI, o esquema é content, o host é com.example.project,
a porta é 200 e o caminho é folder/subfolder/etc.
Cada um desses atributos é opcional em um elemento <data>,
mas há dependências lineares:
- Se um esquema não for especificado, o host será ignorado.
- Se um host não for especificado, a porta será ignorada.
- Se o esquema e o host não forem especificados, o caminho será ignorado.
Quando o URI em uma intent é comparado a uma especificação de URI em um filtro, ele é comparado apenas às partes do URI incluídas no filtro. Exemplo:
- Se um filtro especificar apenas um esquema, todos os URIs com esse esquema vão corresponder ao filtro.
- Se um filtro especificar um esquema e uma autoridade, mas nenhum caminho, todos os URIs com o mesmo esquema e autoridade vão passar pelo filtro, independentemente dos caminhos.
- Se um filtro especificar um esquema, uma autoridade e um caminho, somente URIs com o mesmo esquema, autoridade e caminho passarão pelo filtro.
Observação:uma especificação de caminho pode conter um asterisco curinga (*) para exigir apenas uma correspondência parcial do nome do caminho.
O teste de dados compara o URI e o tipo MIME na intent com um URI e um tipo MIME especificados no filtro. As regras são as seguintes:
- Uma intent que não contém um URI nem um tipo MIME só passa no teste se o filtro não especificar URIs ou tipos MIME.
- Uma intent que contém um URI, mas nenhum tipo MIME (nem explícito nem inferível do URI), passa no teste apenas se o URI corresponder ao formato de URI do filtro e se o filtro também não especificar um tipo MIME.
- Uma intent que contém um tipo MIME, mas não um URI, passa no teste somente se o filtro listar o mesmo tipo MIME e não especificar um formato de URI.
- Uma intent que contém um URI e um tipo MIME (explícito ou inferível do
URI) transmite a parte do tipo MIME do teste somente se esse
tipo corresponder a um tipo listado no filtro. Ele passa na parte do URI do teste
se o URI dele corresponder a um URI no filtro ou se tiver um URI
content:oufile:e o filtro não especificar um URI. Em outras palavras, presume-se que um componente seja compatível com dadoscontent:efile:se o filtro listar apenas um tipo MIME.
Observação:se uma intent especificar um URI ou tipo MIME, o teste de dados vai falhar se não houver elementos <data> no <intent-filter>.
Essa última regra, a (d), reflete a expectativa
de que os componentes possam receber dados locais de um arquivo ou provedor de conteúdo.
Portanto, os filtros deles podem listar apenas um tipo de dados e não precisam nomear explicitamente
os esquemas content: e file:.
O exemplo a seguir mostra um caso típico em que um elemento <data>
informa ao Android que o componente pode receber dados de imagem de um provedor de conteúdo
e mostrá-los:
<intent-filter> <data android:mimeType="image/*" /> ... </intent-filter>
Os filtros que especificam um tipo de dados, mas não um URI, são talvez os mais comuns, porque a maioria dos dados disponíveis é dispensada por provedores de conteúdo.
Outra configuração comum é um filtro com um esquema e um tipo de dados. Por
exemplo, um elemento <data>
como o seguinte informa ao Android que
o componente pode recuperar dados de vídeo da rede para realizar a ação:
<intent-filter> <data android:scheme="http" android:mimeType="video/*" /> ... </intent-filter>
Correspondência com intents
As intents são comparadas com filtros de intents não apenas para descobrir um componente de destino
a ser ativado, mas também para descobrir algo sobre o conjunto de
componentes no dispositivo. Por exemplo, o app Home preenche o acesso rápido aos apps
encontrando todas as atividades com filtros de intent que especificam a
ação ACTION_MAIN e a
categoria CATEGORY_LAUNCHER.
Uma correspondência só é bem-sucedida se as ações e categorias na intent corresponderem
ao filtro, conforme descrito na documentação da classe
IntentFilter.
Seu aplicativo pode usar a correspondência de intent de maneira semelhante ao app Home.
O PackageManager tem um conjunto de métodos query...()
que retornam todos os componentes que podem aceitar uma intent específica e
uma série semelhante de métodos resolve...() que determinam o melhor
componente para responder a uma intent. Por exemplo,
queryIntentActivities() retorna uma lista de todas as atividades que podem executar
a intent transmitida como um argumento, e queryIntentServices() retorna uma lista semelhante de serviços.
Nenhum dos métodos ativa os componentes. Eles apenas listam os que
podem responder. Há um método semelhante,
queryBroadcastReceivers(), para broadcast receivers.