Um Intent
é um objeto de mensagem que pode ser usado para solicitar uma ação
de outro componente do app.
Embora os intents facilitem a comunicação entre os componentes de diversas formas, há três
casos de uso fundamentais:
- Como iniciar uma atividade
Uma
Activity
representa uma única tela em um app. É possível iniciar uma nova instância de umaActivity
transmitindo umaIntent
parastartActivity()
. OIntent
descreve a atividade a iniciar e carrega todos os dados necessários.Se você quiser receber um resultado da atividade quando ela terminar, chame
startActivityForResult()
. Sua atividade recebe o resultado como um objetoIntent
separado no callbackonActivityResult()
da atividade. Para mais informações, consulte o guia Atividades. - Como iniciar um serviço
Um
Service
é um componente que realiza operações em segundo plano sem uma interface do usuário. Com o 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 aAPI-reference documentation
.Para versões anteriores ao Android 5.0 (nível 21 da API), é possível iniciar um serviço usando os 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 umIntent
parastartService()
. OIntent
descreve o serviço a iniciar e carrega todos os dados necessários.Se o serviço for projetado com uma interface cliente-servidor, é possível vincular ao serviço em outro componente passando um
Intent
parabindService()
. Para mais informações, consulte o guia Serviços. - Como transmitir um programa
Transmissão é uma mensagem que qualquer aplicativo pode receber. O sistema fornece diversas transmissões para eventos do sistema, como quando o sistema inicializa ou o dispositivo inicia o carregamento. Você pode transmitir uma transmissão para outros apps transmitindo um
Intent
parasendBroadcast()
ousendOrderedBroadcast()
.
O restante desta página explica como os intents funcionam e como usá-los. Para informações relacionadas, consulte Como interagir com outros apps e Compartilhar conteúdo.
Tipos de intents
Há dois tipos de intents:
- As intents explícitas especificam qual componente de qual app vai atender à intent, especificando um
ComponentName
completo. Normalmente, usa-se um intent explícito para iniciar um componente no próprio app porque se sabe o nome de classe da atividade ou serviço que se 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. - Os intents implícitos 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 um intent implícito para solicitar que outro app capaz mostre um local especificado em um mapa.
A figura 1 mostra como um intent é usado ao iniciar uma atividade. Quando o
objeto Intent
nomeia um componente específico da atividade de forma explícita, o sistema
imediatamente inicia esse componente.
Ao usar um intent implícito, o sistema Android encontra o componente adequado para iniciar
comparando o conteúdo do intent aos filtros de intent declarados no arquivo de manifesto de outros apps no
dispositivo. Se a intent corresponder a um filtro de intents, o sistema vai iniciar esse componente e entregar
o objeto Intent
. Se diversos filtros de intents corresponderem, o sistema
exibirá uma caixa de diálogo para que o usuário selecione o aplicativo que deseja usar.
O filtro de intents é uma expressão em um arquivo de manifesto do app que especifica o tipo de intents que o componente gostaria de receber. Por exemplo, ao declarar um filtro de intent para uma atividade, outros apps podem iniciar 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 a segurança do app, 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 se você chamar bindService()
com uma intent implícita.
Criação de um intent
Um objeto Intent
carrega informações que o sistema Android usa
para determinar qual componente iniciar (como o nome exato do componente ou a categoria
do componente que deve receber a intent), além de informações que o componente receptor usa
para realizar a ação corretamente (como a ação a ser realizada e os dados a serem usados).
As informações principais contidas em um Intent
são as seguintes:
- Nome do componente
- O nome do componente a iniciar.
É opcional, mas é a informação fundamental que torna um intent explícito, o que significa que o intent precisa ser entregue apenas ao componente do app definido pelo nome do componente. Sem nome de componente, a intent é implícita, e o sistema decide qual componente deve receber a intent com base nas informações de outra intent (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 será possível determinar qual serviço vai responder à intent, e o usuário não poderá ver qual serviço é 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 realizar (como visualizar ou selecionar).
No caso de um intent de transmissão, essa é a ação que entrou em vigor e que está sendo relatada. A ação determina amplamente como o resto da intent é estruturado, principalmente as informações contidas nos dados e em extras.
É possível especificar as ações para uso por intents dentro do aplicativo (ou para uso por outros apps para invocar componentes no seu app), mas normalmente são usadas constantes de ação definidas pela classe
Intent
ou por outras classes de framework. Confira algumas ações comuns para iniciar uma atividade:ACTION_VIEW
- Use essa ação em um intent com
startActivity()
quando houver informações que uma atividade possa mostrar ao usuário, como uma foto para exibição em um aplicativo de galeria ou um endereço para exibição em um aplicativo de mapa. ACTION_SEND
- Também conhecida como a intent de compartilhamento, ela deve ser usada em uma intent com
startActivity()
quando houver alguns dados que o usuário possa compartilhar por meio de outro aplicativo, como um app de e-mail ou de compartilhamento social.
Consulte a referência da classe
Intent
para saber mais constantes que definem ações genéricas. Outras ações são definidas em outros locais no framework do Android, como emSettings
para ações que abrem telas específicas no app Configurações do sistema.É possível especificar a ação para um intent com
setAction()
ou com um construtorIntent
.Se você definir as próprias ações, inclua o nome do pacote do seu app como prefixo, conforme mostrado no exemplo abaixo:
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 referencia os dados a serem aproveitados e/ou o tipo MIME desses dados. O tipo dos dados fornecidos geralmente é determinado pela ação da intent. Por exemplo, se a ação forACTION_EDIT
, os dados precisarão conter o URI do documento a ser editado.Ao criar um intent, é importante especificar o tipo de dados (seu tipo MIME) em adição ao URI. Por exemplo, uma atividade capaz de exibir imagens provavelmente não será capaz de reproduzir um arquivo de áudio, mesmo que os formatos do URI sejam similares. 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 a partir 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
, 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 um anula o valor do outro. Sempre usesetDataAndType()
para definir o URI e o tipo MIME. - Categorias
- 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
inserido em um intent, mas a maioria dos intents não requer nenhuma categoria.
Confira algumas categorias comuns:
CATEGORY_BROWSABLE
- A atividade-alvo permite ser iniciada por um navegador da Web para exibir dados referenciados por um link, como uma imagem ou uma mensagem de e-mail.
CATEGORY_LAUNCHER
- A atividade é a atividade inicial de uma tarefa e é listada no inicializador de aplicativos do sistema.
Consulte a descrição da classe
Intent
para conferir a lista completa de categorias.É possível especificar uma categoria com
addCategory()
.
As propriedades listadas acima (nome do componente, ação, dados e categoria) representam as características de definição de um intent. Ao ler essas propriedades, o sistema Android é capaz de definir o componente de app que ele deve iniciar. No entanto, um intent pode carregar informações adicionais que não afetam o modo com que é tratado para um componente do app. Os intents também podem fornecer o seguinte:
- Extras
- Pares de chave-valor que carregam informações adicionais necessárias para realizar
a ação solicitada.
Assim como algumas ações usam determinados tipos de URIs de dados, outras também usam determinados extras.
É possível adicionar dados extras 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 objetoBundle
com todos os dados extras e inserir oBundle
noIntent
computExtras()
.Por exemplo, ao criar uma intent para enviar um e-mail com
ACTION_SEND
, é possível especificar o destinatário para com a chaveEXTRA_EMAIL
e especificar o assunto com a chaveEXTRA_SUBJECT
.A classe
Intent
especifica muitas constantesEXTRA_*
para tipos de dados padronizados. Se for necessário declarar chaves extras (para intents que seu app recebe), inclua o nome do pacote do app como prefixo, conforme mostrado no exemplo abaixo:Kotlin
const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"
Java
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
Cuidado: não use dados
Parcelable
ouSerializable
ao 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 umRuntimeException
. - Flags Os flags
- são definidos na classe
Intent
e funcionam como metadados para a intent. Os sinalizadores podem instruir o sistema Android a inicializar uma atividade (por exemplo, a qual tarefa a atividade deve pertencer) e como tratá-la após a inicialização (por exemplo, se ela pertence a uma lista de atividades recentes).Para mais informações, consulte o método
setFlags()
.
Exemplo de intent explícito
A intent explícita é usada para inicializar um componente específico de um app, como
uma atividade ou serviço em particular no seu app. Para criar uma intent explícita, defina
o nome do componente para o objeto Intent
. Todas
as outras propriedades da intent são opcionais.
Por exemplo, se você criar um serviço no app, chamado DownloadService
,
projetado para fazer o download de um arquivo da Web, poderá 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
componente um objeto Class
. Assim,
essa intent inicia explicitamente a classe DownloadService
no app.
Para mais informações sobre a criação e inicialização de um serviço, consulte o guia Serviços.
Exemplo de intent implícito
O intent implícito especifica uma ação que pode chamar qualquer app no dispositivo capaz de realizar a ação. O intent implícito é útil quando o app não pode realizar a ação, mas outros aplicativos provavelmente podem, e o usuário seleciona que aplicativo usar.
Por exemplo, se você tem 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 compartilhar. 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()
é chamada, o sistema
examina todos os apps instalados para determinar quais deles podem processar esse tipo de intent (um
intent com a ação ACTION_SEND
e que carrega dados de "texto/simples"). Se houver somente um aplicativo que possa tratá-lo, o aplicativo se abrirá imediatamente e receberá a
intent. Se nenhum outro app puder processá-lo, seu app poderá capturar a
ActivityNotFoundException
que ocorre. Se diversas atividades aceitarem o intent, o sistema
vai mostrar uma caixa de diálogo, como a mostrada na 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 enviar o usuário para outro app.
Como forçar um seletor de aplicativo
Quando há mais de um app que responde ao intent implícito, o usuário pode selecionar o aplicativo que quer usar e tornar esse aplicativo a escolha padrão para a ação. Isso é útil ao executar uma ação em que o usuário provavelmente quer usar o mesmo aplicativo todas as vezes, como quando abre uma página da Web (os usuários geralmente preferem apenas um navegador).
No entanto, se diversos aplicativos puderem responder ao intent e o usuário tiver que ficar livre para usar um aplicativo
diferente a cada vez, é preciso exibir uma caixa de diálogo seletora explicitamente. A caixa de diálogo seletora pede que o
usuário selecione o app que será usado para a ação. Não é possível selecionar um app padrão para
a ação. Por exemplo, quando o app realiza "compartilhar" com a ação ACTION_SEND
, os usuários podem querer compartilhar usando um app diferente, dependendo
da situação atual. Portanto, sempre use a caixa de diálogo seletora, como mostrado na Figura 2.
Para mostrar o seletor, crie uma Intent
usando createChooser()
e transmita-o para startActivity()
, conforme mostrado no exemplo a seguir.
Esse 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
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 intents não seguras
O app pode iniciar intents para navegar entre componentes dentro do app 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 realiza uma inicialização não segura de uma intent. Por exemplo, o app pode executar uma inicialização não segura de uma intent aninhada, que é 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 Android Nesting Intents no Medium.
Verificar lançamentos de intents 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. Caso
o app detecte uma violação de StrictMode, é recomendado interromper a execução
para proteger informações possivelmente confidenciais.
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 um lançamento de intent não seguro 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 sem necessidade. Por exemplo, se você
pretender iniciar um componente do app usando uma intent interna aninhada, defina o
atributo android:exported
desse componente como false
.
Use uma PendingIntent
em vez de uma
intent aninhada. Dessa forma, quando outro app desempacotar a PendingIntent
da
Intent
que o contém, ele poderá iniciar a 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 transmite o controle do seu app (cliente) para outro app (serviço) e vice-versa:
- O app cria uma intent que invoca uma atividade em outro app. Dentro
dessa intent, você adiciona um objeto
PendingIntent
como um extra. Essa intent pendente invocou um componente no seu app, que não foi exportado. - Ao receber a intent do app, o outro app extrai o objeto
PendingIntent
aninhado. - O outro app invoca o método
send()
no objetoPendingIntent
. - Depois de transmitir o controle de volta ao app, o sistema invoca a intent pendente usando o contexto do app.
Figura 2. Diagrama da comunicação entre apps ao usar uma intent pendente anexada.
Como receber um intent implícito
Para anunciar quais intents implícitas o app pode receber, declare um ou mais filtros de intents para
cada um dos componentes do app com um elemento <intent-filter>
no arquivo de manifesto.
Cada filtro de intent especifica o tipo de intents aceito com base na ação,
nos dados e na categoria do intent. O sistema vai enviar um intent implícito ao componente do seu app somente se ele
puder passar por um dos filtros de intents.
Observação:uma intent explícita é sempre entregue ao destino, independentemente dos filtros de intent que o componente declare.
Os componentes de um app precisam declarar filtros separados para cada job exclusivo que podem fazer.
Por exemplo, uma atividade em um app de galeria de imagens pode ter dois filtros: um para
visualizar uma imagem e outro para editar uma imagem. Quando a atividade é iniciada,
ela inspeciona o Intent
e decide como se comportar com base nas informações
no Intent
(como para mostrar ou não os controles do editor).
Cada filtro de intents é definido por um elemento <intent-filter>
no arquivo de manifesto do app, aninhado no componente correspondente do app (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 é acessível a outros apps. Em algumas
situações, como atividades cujos filtros de intent incluem a
categoria LAUNCHER
, é útil definir esse atributo como true
. Caso contrário,
é mais seguro definir esse atributo como false
.
Aviso:caso uma atividade, um serviço ou um broadcast
receiver no app use filtros de intent e não defina explicitamente o valor
para android:exported
, não será possível instalar o app em um dispositivo
com o Android 12 ou mais recente.
Dentro de <intent-filter>
,
é possível especificar o tipo de intents aceitos 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 literal da string de uma ação, e não a constante da classe. <data>
- Declara o tipo de dados aceitos usando um ou mais atributos que especificam diversos
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, e não a constante da classe.Observação:para receber intents implícitas, inclua a categoria
CATEGORY_DEFAULT
no 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, abaixo há uma declaração de atividade com um filtro de intents 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>
Você pode criar um filtro que inclua mais de uma instância de
<action>
,
<data>
ou
<category>
.
Se fizer isso, será necessário verificar se o componente pode processar todas as
combinações dos elementos de filtro.
Para processar diversos tipos de intents, mas somente em combinações específicas de ação, dados e tipo de categoria, será necessário criar diversos filtros de intents.
Os intents implícitos são testados em relação a um filtro por meio da comparação do intent com cada um dos três elementos. Para ser entregue ao componente, o intent deve passar por todos os três testes. Se ele falhar em algum deles, o sistema Android não vai entregar a intent ao componente. No entanto, como um componente pode ter diversos filtros de intents, um intent que não passe por um dos filtros de um componente pode passar por outro filtro. Confira mais informações sobre como o sistema resolve intents na seção abaixo sobre Resolução de intents.
Cuidado : o uso de um filtro de intent não é um modo seguro de evitar que outros apps iniciem
componentes. Embora os filtros de intent restrinjam um componente a responder somente a
determinados tipos de intents implícitos, 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 involuntária de um
Service
diferente do app, sempre use um intent explícito para iniciar o próprio serviço.
Observação:para todas as atividades, é necessário declarar os filtros de intent no arquivo de manifesto.
No entanto, filtros para broadcast receivers podem ser registrados dinamicamente ao chamar
registerReceiver()
. Assim, será possível cancelar o registro do receptor com unregisterReceiver()
. Isso permite que o app
receba transmissões específicas durante um período de tempo especificado apenas quando o app
estiver em execução.
Exemplos de filtros
Para demonstrar alguns comportamentos do filtro de intents, confira 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 inicializa o app pela primeira vez com o ícone de inicialização:
- A ação
ACTION_MAIN
indica que esse é o ponto de entrada principal e não espera nenhum dado de intent. - A categoria
CATEGORY_LAUNCHER
indica que o ícone dessa atividade deve ser colocado no inicializador de apps do sistema. Se o elemento<activity>
não especificar um ícone comicon
, o sistema vai usar o ícone do elemento<application>
.
Esses dois devem ser pareados para que a atividade apareça no inicializador do aplicativo.
A segunda atividade, ShareActivity
, destina-se a facilitar o compartilhamento de conteúdo de texto e
mídia. Apesar de os usuários poderem acessar essa atividade pela MainActivity
,
eles também podem acessar ShareActivity
diretamente de outro app que emita uma intent
implícita que corresponda a um dos dois filtros de intents.
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.
Corresponder intents a filtros de outros apps
Se outro app for direcionado ao Android 13 (nível 33 da API) ou mais recente, 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 direcionado ao Android 13
ou mais recente, todas as intents originadas de apps externos serão enviadas a um
componente exportado do app somente se a intent corresponder às ações e
categorias de um elemento <intent-filter>
declarado pelo app. Esse comportamento
ocorre independentemente 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_server
e apps que definemandroid:sharedUserId
comoandroid.uid.system
. - Intents originadas de uma raiz.
Saiba mais sobre a correspondência de intenção.
Uso de um intent pendente
Um objeto PendingIntent
é um wrapper em torno de um objeto Intent
. A principal finalidade de uma PendingIntent
é conceder permissão a um aplicativo externo
para usar a Intent
contida como se ela fosse executada a partir do
processo do próprio app.
Os principais casos de uso de um intent pendente são os seguintes:
- Declarar um intent a ser executado quando o usuário realiza uma ação com a Notificação
(o
NotificationManager
do sistema Android executa oIntent
). - Declarar um intent a ser executado 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 momento específico no futuro (o
AlarmManager
do 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
), uma PendingIntent
também precisa ser
criada com a mesma consideração. Ao usar um intent pendente, o app não
executa o intent com uma chamada como startActivity()
. Em vez disso, é necessário declarar o tipo do componente pretendido ao criar o
PendingIntent
chamando o respectivo método criador:
PendingIntent.getActivity()
para umaIntent
que inicia umaActivity
.PendingIntent.getService()
para umaIntent
que inicia umaService
.PendingIntent.getBroadcast()
para umaIntent
que inicia umaBroadcastReceiver
.
A menos que o app esteja recebendo intents pendentes de outros apps,
os métodos acima para criar uma PendingIntent
são provavelmente os únicos
PendingIntent
necessários.
Cada método toma o Context
do app atual, o
Intent
que você quer agrupar e um ou mais sinalizadores que especificam
como a intent deve ser usada (como se ela pode ser usada mais de uma vez).
Para mais informações sobre o uso de intents pendentes, consulte a documentação dos respectivos casos de uso, como nos guias das APIs de Notificações e Widgets do app.
Especificar mutabilidade
Caso o app seja destinado ao Android 12 ou mais recente, especifique 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 gerará uma
IllegalArgumentException
e
a mensagem a seguir será exibida 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 da
intent.
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 exige uma mudança nos dados de clipe no objeto PendingIntent
associado à resposta. Normalmente, essa mudança é solicitada transmitindo
FILL_IN_CLIP_DATA
como 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 objetoPendingIntent
mutável permite que o sistema aplique as flags corretas, comoFLAG_ACTIVITY_MULTIPLE_TASK
eFLAG_ACTIVITY_NEW_DOCUMENT
. - Solicitar informações de localização do dispositivo chamando
requestLocationUpdates()
ou APIs semelhantes. O objetoPendingIntent
mutável permite que o sistema adicione extras de intent que representam eventos de ciclo de vida de local. Esses eventos incluem uma mudança de local e a disponibilidade de um provedor. - Programação de alarmes usando
AlarmManager
. O objeto mutávelPendingIntent
permite que o sistema adicione o extra de intentEXTRA_ALARM_COUNT
. Esse extra representa o número de vezes que um alarme repetitivo foi acionado. Ao conter esse extra, a intent pode notificar um app com precisão se um alarme recorrente foi acionado várias vezes, por exemplo, quando o dispositivo estava em suspensão.
Se o app criar um objeto PendingIntent
mutável, é altamente recomendável
que você use uma intent explícita e preencha 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 envolva uma intent pendente em uma intent explícita. Para ajudar a 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 umaPendingIntent
preencham propriedades não preenchidas. Se ominSdkVersion
do app for22
ou mais recente, 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 um intent implícito para iniciar uma atividade, ele procura a melhor atividade para o intent comparando-o aos 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 combinadas com os componentes apropriados de acordo com a declaração do filtro de intents no arquivo de manifesto de um app.
Teste de ação
Para especificar ações de intents aceitas, um filtro de intents pode declarar zero ou mais
elementos <action>
, conforme 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 na Intent
precisa corresponder a uma das ações listadas no filtro.
Se o filtro não listar nenhuma ação, não haverá nada a que um
intent corresponda, portanto, todos os intents falharão no teste. No entanto, se um Intent
não especificar uma ação, ele vai passar no teste, desde que o filtro
tenha pelo menos uma ação.
Teste de categoria
Para especificar as categorias de intent aceitas, um filtro de intents pode declarar zero ou mais
elementos <category>
, conforme 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 um intent passe no teste de categoria, cada categoria no Intent
precisa corresponder a uma categoria no filtro. O inverso não é necessário. O filtro de intents pode
declarar mais categorias do que as especificadas no Intent
, e o
Intent
ainda é transmitido. Portanto, um intent sem categorias
sempre vai passar nesse teste, independentemente das categorias declaradas no filtro.
Observação:o Android aplica automaticamente a categoria CATEGORY_DEFAULT
a todos os intents implícitos transmitidos para startActivity()
e startActivityForResult()
.
Para que a atividade receba intents implícitas, ela precisa
incluir uma categoria de "android.intent.category.DEFAULT"
nos filtros de intents, como
mostrado no exemplo de <intent-filter>
anterior.
Teste de dados
Para especificar dados de intents aceitos, um filtro de intents pode declarar zero ou mais
elementos <data>
, conforme 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 abaixo mostra possíveis valores 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 não houver esquema especificado, o host será ignorado.
- Se não houver host especificado, a porta será ignorada.
- Se não houver esquema nem host especificado, o caminho será ignorado.
Quando o URI em um intent é comparado a uma especificação de URI em um filtro, a comparação é feita somente com as partes do URI incluídas no filtro. Exemplo:
- Se um filtro especificar somente um esquema, todas as URIs com esse esquema atenderão ao filtro.
- Se um filtro especificar um esquema e uma autoridade, mas não um 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:a 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 do intent com um URI e um tipo MIME especificados no filtro. As regras são as seguintes:
- O intent que não contiver URI nem tipo MIME vai passar no teste somente se o filtro não especificar nenhum URI nem tipo MIME.
- O intent que contiver um URI, mas nenhum tipo MIME (nem explícito, nem inferível a partir do URI), passará no teste somente se o URI corresponder ao formato de URI do filtro e se o filtro, igualmente, não especificar um tipo MIME.
- O intent que contiver um tipo MIME, mas nenhum URI, vai passar no teste somente se o filtro listar o mesmo tipo MIME e não especificar nenhum formato de URI.
- O intent que contiver URI e tipo MIME (explícito ou inferível a partir do
URI) passará na parte do tipo MIME do teste somente se esse
tipo corresponder a um tipo listado no filtro. Ele vai passar na parte do URI do teste
se corresponder a um URI no filtro ou se tiver um URI
content:
oufile:
e o filtro não especificar nenhum URI. Em outras palavras, presume-se que um componente seja compatível com dados decontent:
efile:
se o filtro listar apenas um tipo MIME.
Observação:se uma intent especificar um URI ou um tipo MIME, o teste de dados
vai falhar se não houver elementos <data>
no <intent-filter>
.
Essa última regra (d) reflete a expectativa
de que os componentes sejam capazes de receber dados de local de um arquivo ou provedor de conteúdo.
Portanto, os filtros 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 exibi-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 pelos provedores de conteúdo.
Outra configuração comum é de filtros 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 de intents
Intents são correspondidos a filtros de intents não somente para descobrir um componente-alvo
a ativar, mas também para descobrir algo sobre o conjunto de
componentes do dispositivo. Por exemplo, o app Home preenche o inicializador do app
encontrando todas as atividades com filtros de intent que especifiquem 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
.
O aplicativo pode usar a correspondência de intents de modo semelhante ao feito pelo aplicativo 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 realizar
a intent transmitida como argumento, e queryIntentServices()
retorna uma lista semelhante de serviços.
Nenhum dos métodos ativa os componentes, eles só listam os que
podem responder. Há um método semelhante,
queryBroadcastReceivers()
, para broadcast receivers.