Este documento apresenta vários casos de uso comuns em que um app interage com outros. Cada seção oferece orientações sobre como realizar a função do app com visibilidade limitada de pacotes. Você precisa pensar nisso caso seu app seja destinado ao Android 11 (API de nível 30) ou mais recente.
Quando um app destinado ao Android 11 ou versões mais recentes usar uma intent para
iniciar uma atividade em outro, a abordagem mais direta é invocar
a intent e processar a exceção
ActivityNotFoundException
,
se nenhum app estiver disponível.
Se parte do app depender de saber se a chamada para
startActivity()
pode ser bem-sucedida, como mostrar uma IU, adicione um elemento ao
<queries>
do
manifesto do app. Normalmente, é um elemento <intent>
.
Abrir URLs
Esta seção descreve várias maneiras de abrir URLs em um app destinado ao Android 11 ou versões mais recentes.
Abrir URLs em um navegador ou outro app
Para abrir um URL, use uma intent que contenha a
ação da intent ACTION_VIEW
, conforme
descrito no guia sobre como carregar um URL da
Web. Depois de chamar startActivity()
usando essa intent, acontece uma das seguintes ações:
- O URL é aberto em um app de navegador da Web.
- O URL é aberto em um app compatível com o URL, como um link direto.
- Uma caixa de diálogo de desambiguação é mostrada, permitindo que o usuário escolha qual app abre o URL.
Uma
ActivityNotFoundException
ocorre porque não há nenhum app instalado no dispositivo que possa abrir o URL. Isso é incomum.Recomenda-se que o app detecte e processe o
ActivityNotFoundException
se ele ocorrer.
Como o método startActivity()
não exige visibilidade do pacote para
iniciar a atividade de outro aplicativo, não é necessário adicionar um elemento <queries>
ao manifesto do app, nem fazer mudanças em um
elemento <queries>
. Isso é válido para intents implícitas e explícitas que abrem um URL.
Conferir se um navegador está disponível
Em alguns casos, o app pode verificar se há pelo menos um navegador
disponível no dispositivo ou se um navegador específico é o navegador padrão
antes de tentar abrir um URL. Nesses casos, inclua o seguinte elemento
<intent>
como parte do elemento <queries>
no manifesto:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https" /> </intent>
Quando você chama queryIntentActivities()
e transmite uma intent da Web como argumento,
a lista retornada inclui os apps de navegação disponíveis em alguns casos. A lista
não incluirá apps de navegação se o usuário tiver configurado o URL para ser aberto em um
app que não seja de navegador por padrão.
Abrir URLs em guias personalizadas
As guias personalizadas permitem
que um app personalize a aparência do navegador. É possível abrir um URL em
uma guia personalizada
sem precisar adicionar ou mudar o elemento <queries>
no manifesto do app.
No entanto, convém conferir se o dispositivo tem um navegador que ofereça suporte a
guias personalizadas
ou selecionar um navegador específico para iniciar com guias personalizadas usando
CustomTabsClient.getPackageName()
.
Nesses casos, inclua o seguinte elemento <intent>
como parte do elemento
<queries>
no manifesto:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.support.customtabs.action.CustomTabsService" /> </intent>
Permitir que apps que não sejam navegadores processem URLs
Mesmo que seu app possa abrir URLs usando guias personalizadas, é recomendável
permitir que um app sem navegador abra um URL, se possível. Para fornecer esse
recurso no app, tente uma chamada para startActivity()
usando uma intent
que defina a
sinalização de intent
FLAG_ACTIVITY_REQUIRE_NON_BROWSER
. Se o sistema gerar um ActivityNotFoundException
, o app poderá
abrir o URL em uma guia personalizada.
Se uma intent incluir essa sinalização, uma chamada para startActivity()
fará com que um
ActivityNotFoundException
seja lançado quando uma das seguintes
condições ocorrer:
- A chamada teria iniciado um app de navegador diretamente.
- A chamada teria mostrado ao usuário uma caixa de diálogo de desambiguação em que as únicas opções são apps de navegador.
O snippet de código a seguir mostra como atualizar sua lógica para usar a
sinalização de intent FLAG_ACTIVITY_REQUIRE_NON_BROWSER
:
Kotlin
try { val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply { // The URL should either launch directly in a non-browser app (if it's // the default) or in the disambiguation dialog. addCategory(CATEGORY_BROWSABLE) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER } startActivity(intent) } catch (e: ActivityNotFoundException) { // Only browser apps are available, or a browser is the default. // So you can open the URL directly in your app, for example in a // Custom Tab. openInCustomTabs(url) }
Java
try { Intent intent = new Intent(ACTION_VIEW, Uri.parse(url)); // The URL should either launch directly in a non-browser app (if it's the // default) or in the disambiguation dialog. intent.addCategory(CATEGORY_BROWSABLE); intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER); startActivity(intent); } catch (ActivityNotFoundException e) { // Only browser apps are available, or a browser is the default. // So you can open the URL directly in your app, for example in a // Custom Tab. openInCustomTabs(url); }
Evitar uma caixa de diálogo de desambiguação
Se você quiser evitar a exibição da caixa de diálogo de desambiguação que os usuários podem ver ao
abrir um URL e preferir lidar com o URL nessas
situações, use uma intent que defina a
sinalização de intent
FLAG_ACTIVITY_REQUIRE_DEFAULT
.
Se uma intent incluir essa sinalização, uma chamada para startActivity()
gerará um
ActivityNotFoundException
quando a chamada mostraria uma
caixa de diálogo de desambiguação ao usuário.
Se uma intent incluir essa sinalização e a sinalização de intent
FLAG_ACTIVITY_REQUIRE_NON_BROWSER
, uma chamada para startActivity()
fará com que um ActivityNotFoundException
seja lançado quando uma das seguintes condições ocorrer:
- A chamada teria iniciado o app do navegador diretamente.
- A chamada teria mostrado uma caixa de diálogo de desambiguação para o usuário.
O snippet de código a seguir mostra como usar as sinalizações FLAG_ACTIVITY_REQUIRE_NON_BROWSER
e FLAG_ACTIVITY_REQUIRE_DEFAULT
juntas:
Kotlin
val url = URL_TO_LOAD try { // For this intent to be invoked, the system must directly launch a // non-browser app. val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply { addCategory(CATEGORY_BROWSABLE) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER or FLAG_ACTIVITY_REQUIRE_DEFAULT } startActivity(intent) } catch (e: ActivityNotFoundException) { // This code executes in one of the following cases: // 1. Only browser apps can handle the intent. // 2. The user has set a browser app as the default app. // 3. The user hasn't set any app as the default for handling this URL. openInCustomTabs(url) }
Java
String url = URL_TO_LOAD; try { // For this intent to be invoked, the system must directly launch a // non-browser app. Intent intent = new Intent(ACTION_VIEW, Uri.parse(url)); intent.addCategory(CATEGORY_BROWSABLE); intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER | FLAG_ACTIVITY_REQUIRE_DEFAULT); startActivity(intent); } catch (ActivityNotFoundException e) { // This code executes in one of the following cases: // 1. Only browser apps can handle the intent. // 2. The user has set a browser app as the default app. // 3. The user hasn't set any app as the default for handling this URL. openInCustomTabs(url); }
Abrir um arquivo
Se o app processa arquivos ou anexos, como para verificar se um dispositivo pode abrir
um determinado arquivo, geralmente é mais fácil tentar iniciar uma atividade que possa processar
o arquivo. Para fazer isso, use uma intent que inclua a ação de intent ACTION_VIEW
e o URI que representa o arquivo específico. Se nenhum app estiver disponível no
dispositivo, seu app poderá capturar a ActivityNotFoundException
. Na sua
lógica de processamento de exceções, você pode mostrar um erro ou tentar processar o arquivo
por conta própria.
Se o app precisar saber com antecedência se outro app pode abrir um determinado arquivo,
inclua o elemento <intent>
no snippet de código a seguir como parte do
elemento <queries>
no manifesto. Inclua o tipo de arquivo se você já souber
qual é no momento da compilação.
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.VIEW" /> <!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". --> <data android:mimeType="application/pdf" /> </intent>
Em seguida, verifique se um app está disponível chamando resolveActivity()
com a intent.
Conceder acesso ao URI
Observação: é obrigatório declarar permissões de acesso ao URI para apps destinados ao Android 11 (API de nível 30) ou versões mais recentes, conforme descrito nesta seção. Essa ação é recomendada para todos os apps, seja qual for a versão do SDK de destino e quer eles exportem ou não os provedores de conteúdo.
Para que apps destinados ao Android 11 ou versões mais recentes
acessem o URI de conteúdo, a intent do app precisa declarar permissões de acesso
do URI
configurando uma ou ambas as seguintes sinalizações de intent:
FLAG_GRANT_READ_URI_PERMISSION
e
FLAG_GRANT_WRITE_URI_PERMISSION
.
No Android 11 e versões mais recentes, as permissões de acesso do URI oferecem os seguintes recursos ao app que recebe a intent:
- Ler ou gravar os dados que o URI de conteúdo representa, dependendo das permissões de URI fornecidas.
- Ganhar visibilidade do app que contém o provedor de conteúdo correspondente à autoridade de URI. O app que com o provedor de conteúdo pode ser diferente do app que envia a intent.
O snippet de código a seguir demonstra como adicionar uma sinalização de intent de permissões de URI para que outro app destinado ao Android 11 ou versões mais recentes possa visualizar os dados no URI de conteúdo:
Kotlin
val shareIntent = Intent(Intent.ACTION_VIEW).apply { flags = Intent.FLAG_GRANT_READ_URI_PERMISSION data = CONTENT_URI_TO_SHARE_WITH_OTHER_APP }
Java
Intent shareIntent = new Intent(Intent.ACTION_VIEW); shareIntent.setFlags(FLAG_GRANT_READ_URI_PERMISSION); shareIntent.setData(CONTENT_URI_TO_SHARE_WITH_OTHER_APP);
Conexão com serviços
Caso seu app precise interagir com um serviço que não esteja visível
automaticamente, é possível declarar a
ação de intent adequada em um elemento <queries>
. Nas seções a seguir,
confira exemplos usando serviços acessados com frequência.
Conexão com mecanismo de conversão de texto em voz
Se o app interagir com um mecanismo de conversão de texto em voz (TTS, na sigla em inglês), inclua o seguinte
elemento <intent>
como parte do elemento <queries>
no manifesto:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.TTS_SERVICE" /> </intent>
Conexão com serviço de reconhecimento de fala
Se o app interagir com um serviço de reconhecimento de fala, inclua o seguinte elemento
<intent>
como parte do elemento <queries>
no manifesto:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.speech.RecognitionService" /> </intent>
Conexão com serviços do navegador de mídia
Se o app for um app de navegador de mídia
do cliente, inclua
o seguinte elemento <intent>
como parte do elemento <queries>
no
manifesto:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.media.browse.MediaBrowserService" /> </intent>
Oferecer funcionalidades personalizáveis
Se o app precisar executar ações ou mostrar informações personalizáveis
com base nas interações com outros apps, você poderá representar esse comportamento
personalizado usando assinaturas de filtro
de intent como
parte do elemento <queries>
no manifesto. As seções a seguir oferecem
uma orientação mais detalhada para vários cenários comuns.
Consultar apps de SMS
Se o app precisar de informações sobre o conjunto de apps de SMS instalados em um
dispositivo, por exemplo, para conferir qual app é o gerenciador de SMS padrão dele,
inclua o seguinte elemento <intent>
como parte do elemento <queries>
no
seu manifesto:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.SENDTO"/> <data android:scheme="smsto" android:host="*" /> </intent>
Criar uma planilha personalizada
Sempre que possível, use um compartilhamento de arquivos
fornecido pelo sistema. Como alternativa,
inclua o seguinte elemento <intent>
como parte do elemento <queries>
no manifesto:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.SEND" /> <!-- Replace with the MIME type that your app works with, if needed. --> <data android:mimeType="image/jpeg" /> </intent>
O processo de criação da planilha na lógica do app, como a chamada para
queryIntentActivities()
, permanece inalterado em comparação com
as versões anteriores ao Android 11.
Mostrar ações personalizadas de seleção de texto
Quando os usuários selecionam texto no seu app, uma barra de ferramentas
de seleção de texto
mostra o conjunto de operações que podem ser feitas no texto selecionado. Se essa
barra de ferramentas mostrar ações personalizadas de outros apps, inclua o seguinte
elemento <intent>
como parte do elemento <queries>
no manifesto:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.PROCESS_TEXT" /> <data android:mimeType="text/plain" /> </intent>
Mostrar linhas de dados personalizadas para um contato
Os apps podem adicionar linhas de dados personalizadas ao Provedor de contatos. Para que um app de contatos mostre esses dados personalizados, ele precisa fazer o seguinte:
- Ler o arquivo
contacts.xml
dos outros apps. - Carregar um ícone correspondente ao tipo MIME personalizado.
Se o app for um app de contatos, inclua os seguintes elementos <intent>
como parte
do elemento <queries>
no manifesto:
<!-- Place inside the <queries> element. --> <!-- Lets the app read the contacts.xml file from other apps. --> <intent> <action android:name="android.accounts.AccountAuthenticator" /> </intent> <!-- Lets the app load an icon corresponding to the custom MIME type. --> <intent> <action android:name="android.intent.action.VIEW" /> <data android:scheme="content" android:host="com.android.contacts" android:mimeType="vnd.android.cursor.item/*" /> </intent>