Intents e filtros

Um 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 Activity representa uma única tela em um app. É possível iniciar uma nova instância de uma Activity transmitindo uma Intent para startActivity(). O Intent 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 objeto Intent separado no callback onActivityResult() 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. Com o Android 5.0 (nível 21 da API) e versões mais recentes, é possível iniciar um serviço com JobScheduler. Para mais informações sobre JobScheduler, consulte API-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 um Intent para startService(). O Intent descreve o serviço a ser iniciado 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 para bindService(). Para mais informações, consulte o guia Serviços.

  • Como transmitir um programa

    Transmissão é uma mensagem que qualquer aplicativo pode receber. O sistema oferece várias Transmissões para eventos do sistema, como quando o sistema é inicializado ou o dispositivo começa a carregar. Você pode transmitir uma transmissão para outros apps transmitindo um Intent para sendBroadcast() ou sendOrderedBroadcast().

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 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. Para exemplo, você pode iniciar uma nova atividade no aplicativo em resposta a uma ação do usuário ou um serviço para fazer o download de um arquivo em segundo plano.
  • As intents implícitas não nomeiam nenhum componente específico, mas declaram uma ação geral. que permite que um componente de outro aplicativo a execute. 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.

Figura 1. Como uma intent implícita é entregue pelo sistema para iniciar outra atividade: [1] a atividade A cria uma Intent com uma descrição da ação e a transmite para startActivity(). [2] O sistema Android procura, em todos os apps, um filtro de intent que corresponda à intent. Quando uma correspondência for encontrada, [3] o sistema inicia a atividade correspondente (atividade B) invocando o método onCreate() e transmitindo a Intent.

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 iniciará esse componente e o entregará o objeto Intent. Se vários filtros de intents forem compatíveis, o sistema exibe uma caixa de diálogo para que o usuário possa escolher qual aplicativo usar.

Um filtro de intents é uma expressão no arquivo de manifesto de um app que especifica o tipo de intents que o componente gostaria de receber. Por exemplo, ao declarar um filtro de intents para uma atividade, você possibilita 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 a segurança do seu app, sempre usar uma linguagem ao iniciar uma Service e não declarar filtros de intent para seus 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. A partir do Android 5.0 (API de nível 21), 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 categoria que deve receber a intenção), além das informações que o componente destinatário usa em para realizar adequadamente a ação (como a ação a ser tomada e os dados a serem seguidos).

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 fundamental que faz uma intenção explicit, o que significa que a intent precisa ser entregue somente 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 em seu aplicativo, você deve especificar o nome do componente.

Observação:ao iniciar uma 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 objeto ComponentName 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 com setComponent(), setClass(), setClassName() ou com o construtor Intent.

Ação
Uma string que especifica a ação genérica a ser realizada (como view ou pick).

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 suas próprias ações para uso por intents dentro do seu aplicativo (ou para uso por outros invoquem componentes no app), mas você geralmente especifica constantes de ação definido pela classe Intent ou outras classes de framework. Confira alguns 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 share, 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 mais constantes que definem ações genéricas. Outras ações são definidas em outros locais no framework do Android, como em Settings para ações que abrem telas específicas no app Configurações do sistema.

Você pode especificar a ação para uma intent com setAction() ou com um construtor Intent.

Se você definir as próprias ações, inclua o nome do pacote do seu app como prefixo, conforme mostrado no exemplo abaixo:

const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
Dados
O URI (um objeto Uri) que referencia os dados ao ser executadas e/ou tipo MIME desses dados. O tipo dos dados fornecidos geralmente é determinado pela ação da intent. Para Por exemplo, se a ação for ACTION_EDIT, os dados deverã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 reproduzir um arquivo de áudio, mesmo que os formatos de URI possam ser 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 a partir do URI, especialmente quando os dados são um URI content:. Um URI content: indica que os dados estão localizados no dispositivo. e controladas por uma ContentProvider, que torna o tipo MIME de dados visível para o sistema.

Para definir apenas o URI de dados, chame setData(). Para definir apenas o tipo MIME, chame setType(). Se necessário, é possível definir ambos explicitamente com setDataAndType().

Cuidado:se você quiser definir o URI e o tipo MIME, não chame setData() e setType() porque cada um anula o valor do outro. Sempre use setDataAndType() 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 de destino pode ser iniciada por um navegador da Web para mostrar dados referenciada 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 ver a lista completa categorias.

É possível especificar uma categoria com addCategory().

As propriedades listadas acima (nome do componente, ação, dados e categoria) representam que definem as características de uma intent. Ao ler essas propriedades, o sistema Android é capaz de resolver qual componente do aplicativo deve iniciar. No entanto, uma intent pode ter informações adicionais que não afetem como isso é resolvido em 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 mais dados com vários métodos putExtra(), cada um aceita dois parâmetros: o nome da chave e o valor. Também é possível criar um objeto Bundle com todos os dados extras e inserir o Bundle no Intent com putExtras().

Por exemplo, ao criar uma intent para enviar um e-mail com ACTION_SEND, é possível especificar o destinatário to com o EXTRA_EMAIL e especifique o subject com o EXTRA_SUBJECT.

A classe Intent especifica muitas constantes EXTRA_*. para tipos de dados padronizados. Se você precisa declarar chaves extras (para intents que seu app recebe), inclua o nome do pacote do app como um prefixo, conforme mostrado neste exemplo:

const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";

Cuidado: não use Parcelable ou Serializable de dados ao enviar uma intent esperada outro app para receber. Se um app tentar acessar dados em um objeto Bundle, mas não tiver acesso à classe parcelada ou serializada, o sistema vai gerar um RuntimeException.

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:

// Executed in an Activity, so 'this' is the Context
// 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)
// Executed in an Activity, so 'this' is the Context
// 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.

// 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.
}
// 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 aplicativos instalados para determinar quais podem processar esse tipo de intent (uma com a ação ACTION_SEND e que carrega "text/plain" dados). 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.

O guia também oferece mais informações sobre como iniciar outros apps sobre enviar o usuário para outro app.

Figura 2. Caixa de diálogo seletora.

Como forçar um seletor de aplicativo

Quando há mais de um app que responde à intent implícita, o usuário pode selecionar qual aplicativo usar e tornar esse aplicativo a escolha padrão para o à 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 o usuário selecione qual aplicativo usar para a ação (o usuário não pode selecionar um aplicativo 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.

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)
}
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:

  1. O app separa as intents aninhadas das outras intents enviadas.
  2. O app imediatamente inicia um componente do app usando essa intent aninhada, como ao transmitir a intent para startActivity(), startService() ou bindService().

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 se há inicializações 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.

fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build())
}
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 sem necessidade. Por exemplo, se você pretende iniciar um componente de aplicativo usando uma intent aninhada interna, defina que atributo android:exported do componente para false.

Use uma PendingIntent em vez de uma intent aninhada. Dessa forma, quando outro app descompactar o PendingIntent do contendo Intent, o outro app poderá iniciar a PendingIntent usando a a identidade do seu app. Esta configuração permite que o outro app seja iniciado com segurança qualquer componente no seu app, incluindo um componente não exportado.

O diagrama na Figura 2 mostra como o sistema transmite o controle do seu app (cliente) para outro app (serviço) e vice-versa:

  1. O app cria uma intent que invoca uma atividade em outro app. Dentro de essa intent, adicione um objeto PendingIntent como um extra. Essa intent pendente invoca um componente no seu app; esse componente não será exportado.
  2. Ao receber a intent do app, o outro app extrai o objeto PendingIntent aninhado.
  3. O outro app invoca o método send() no objeto PendingIntent.
  4. Depois de retornar o controle ao aplicativo, o sistema invoca o servidor usando o contexto do seu 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 seu app pode receber, declare um ou mais filtros de intent cada um dos componentes do app com um <intent-filter> no seu 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 entrega um intent implícito ao componente do seu app somente se o pode passar por um de seus 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:se uma atividade, um serviço ou uma transmissão receptor no seu app usa filtros de intent e não define explicitamente o valor para android:exported, o app não poderá ser instalado em um dispositivo que execute o Android 12 ou versões mais recentes.

No <intent-filter>, é possível especificar os tipos de intents aceitos usando um ou mais desses três elementos:

<action>
Declara a ação da 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 aceito, usando um ou mais atributos que especificam diversos do URI de dados (scheme, host, port, path) e o tipo MIME.
<category>
Declara a categoria da 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, faça o seguinte: deve incluir o CATEGORY_DEFAULT no filtro de intents. Métodos startActivity() e startActivityForResult() tratam todas as intents como se ele declarasse a categoria CATEGORY_DEFAULT. Se você não declarar essa categoria em seu filtro de intents, nenhuma intent implícita será resolvida para sua atividade.

Por exemplo, aqui está uma declaração de atividade com um filtro de intent para receber uma ACTION_SEND quando o tipo de dado for 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 todo e qualquer e combinações desses 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 vários filtros de intents, uma intent que não não passar por um dos filtros de um componente pode passar por outro filtro. Mais informações sobre como o sistema resolve intents são fornecidas na seção abaixo sobre Resolução de intents.

Cuidado : o uso de um filtro de intent não é uma maneira segura de impedir que outros apps sejam iniciados. seus componentes. Embora os filtros de intent restrinjam um componente a responder certos tipos de intents implícitas, outro aplicativo pode iniciar o componente do seu aplicativo 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 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 intents no arquivo de manifesto. No entanto, filtros para broadcast receivers podem ser registrados de forma dinâmica chamando registerReceiver(): É possível cancelar o registro do destinatário com unregisterReceiver(). Isso permite que o app para detectar transmissões específicas durante apenas um período específico enquanto o app está em execução.

Exemplos de filtros

Para demonstrar alguns dos comportamentos dos filtros de intents, 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 é aberto quando o usuário inicia o app pela primeira vez com o ícone na tela de início:

  • 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 deve ser colocado no inicializador de aplicativos do sistema. Se o elemento <activity> não especificar um ícone com icon, 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 dado especial que especifica fotos panorâmicas, que você pode manipular com o Google panorama.

Corresponder intents a outros apps filtros de intent

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 destinado ao Android 13 ou superior, todas as intents originadas de aplicativos externos serão entregues a uma 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 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 definem android:sharedUserId como android.uid.system.
  • Intents originadas de uma raiz.

Saiba mais sobre a correspondência de intent.

Uso de um intent pendente

Um objeto PendingIntent é um wrapper em torno de um objeto Intent. O objetivo principal de um PendingIntent é conceder permissão a um aplicativo externo para usar o Intent contido como se ele fosse executado do seu 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 o Intent).
  • Declarar uma intent que será executada quando o usuário realizar uma ação com a Widget de app O app de tela inicial executa o Intent.
  • Declarar uma intent a ser executada em um momento específico no futuro (o AlarmManager do sistema Android executa o Intent).

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, você precisa declarar o tipo de componente pretendido ao criar o PendingIntent chamando o respectivo método criador:

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 métodos PendingIntent necessários.

Cada método usa a Context atual do app, a Intent que você quer unir e uma ou mais sinalizações que especificam como a intent precisa ser usada (por exemplo, se a intent pode ser usada mais de uma vez).

Para mais informações sobre o uso de intents pendentes, consulte a documentação de cada dos respectivos casos de uso, como em Notificações e App Widgets.

Especificar a 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 aplicativos não poderão modificar a intenção para ajustar o resultado da invocação do intenção.

val pendingIntent = PendingIntent.getActivity(applicationContext,
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE)
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE);

No entanto, alguns casos de uso exigem objetos PendingIntent mutáveis:

  • Oferecer suporte a ações de resposta direta em notificações. O a resposta direta exige uma alteração nos dados de clipe no objeto PendingIntent que está associado à resposta. Normalmente, essa mudança é solicitada transmitindo FILL_IN_CLIP_DATA como uma flag para o método fillIn().
  • Associar notificações ao framework do Android Auto usando instâncias de CarAppExtender.
  • Como colocar conversas em balões usando instâncias de PendingIntent. Um objeto PendingIntent mutável permite que o sistema aplique as flags corretas, como FLAG_ACTIVITY_MULTIPLE_TASK e FLAG_ACTIVITY_NEW_DOCUMENT.
  • Solicitar informações de localização do dispositivo chamando requestLocationUpdates() ou APIs semelhantes. O objeto PendingIntent mutável permite que o sistema adicione extras da intent que representam eventos de ciclo de vida do local. Esses eventos incluem uma mudança de local e a disponibilidade de um provedor.
  • Programação de alarmes usando AlarmManager. O objeto PendingIntent mutável permite que o sistema adicione o EXTRA_ALARM_COUNT de intent extra. Esse extra representa o número de vezes que um alarme repetitivo foi acionado. Ao conter esse extra, a intent pode notificar com precisão em um app para saber se um alarme recorrente foi acionado várias vezes, por exemplo, quando o dispositivo estava suspenso.

Caso o app crie um objeto PendingIntent mutável, é altamente recomendado 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 encapsular uma intent pendente em uma intent explícita. Para ajudar a seguir essa prática recomendada, faça o seguinte:

  1. Verifique se os campos de ação, pacote e componente da intent de base estão definidos.
  2. Use FLAG_IMMUTABLE, adicionado no Android 6.0 (API de nível 23), para criar intents pendentes. Essa flag impede que apps que recebem uma PendingIntent preencham propriedades não preenchidas. Se o minSdkVersion do app for 22 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 uma intent implícita para iniciar uma atividade, ele procura o melhor atividade para a intent comparando-a aos filtros de intents 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 correspondidas aos componentes apropriados de acordo com a declaração do filtro de intent no arquivo de manifesto do 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 transmitir esse filtro, a ação especificada no Intent precisa corresponder a uma das ações listadas no filtro.

Se o filtro não listar ações, não haverá nada para uma para que haja correspondência, todas as 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 intent 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 uma intent seja aprovada no teste de categoria, todas as categorias em Intent precisa corresponder a uma categoria no filtro. O contrário não é necessário. O filtro de intenção pode declarar mais categorias do que o especificado nos Intent e no Intent ainda passa. Portanto, uma intent sem categorias sempre 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(). Se você quiser que a atividade receba intents implícitas, ela precisa incluir uma categoria para "android.intent.category.DEFAULT" nos filtros de intent, conforme mostrado no exemplo anterior de <intent-filter>.

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 nenhum caminho, todos os URIs com o mesmo esquema e autoridade, passam 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 da intent com um URI e o tipo MIME especificado no filtro. As regras são as seguintes:

  1. O intent que não contiver URI nem tipo MIME passa o testar somente se o filtro não especificar nenhum URI ou tipo MIME.
  2. Uma intent que contém um URI, mas nenhum tipo MIME (nem explícito nem inferido do URI) será aprovado no teste somente se o URI corresponder ao formato de URI do filtro e o filtro, da mesma forma, não especifica um tipo MIME.
  3. O intent que contiver um tipo MIME, mas não tiver um URI, passar no teste. somente se o filtro listar o mesmo tipo MIME e não especificar um formato de URI.
  4. Uma intent que contém um URI e um tipo MIME (explícito ou inferido pelo URI) passará na parte do tipo MIME do teste somente se esse tipo corresponde a um dos listados no filtro. Ele é aprovado na parte de URI do teste. se o URI corresponder a um URI no filtro ou se tiver um content: ou file: e o filtro não especificar nenhum URI. Em outras palavras, presume-se que um componente seja compatível com dados de content: e file: se o filtro listar apenas um tipo MIME.

Observação:se uma intent especificar um URI ou um tipo MIME, o teste de dados vão 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>

Filtros que especificar um tipo de dados, mas não um URI, talvez sejam os mais comuns, porque a maioria os dados são dispensados pelos provedores de conteúdo.

Outra configuração comum é de filtros com um esquema e um tipo de dados. Para exemplo, um <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

As intents são correspondidas a filtros de intents não apenas para descobrir um alvo componente seja ativado, mas também para descobrir algo sobre o conjunto de no 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. A correspondência só é bem-sucedida se as ações e as categorias da intenção corresponderem. ao filtro, conforme descrito na documentação do 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.