Este documento apresenta vários exemplos comuns de casos de uso em que um app interage com outros. Cada seção traz orientações sobre como gerenciar a visibilidade do pacote em outros apps instalados. Você precisa considerar caso seu app seja direcionado ao Android 11 (nível 30 da API) ou mais recente.
Quando o app é destinado ao Android 11 ou mais recente e usa uma intent implícita para iniciar uma
atividade em outro app, a abordagem mais simples é 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 elemento <queries>
do
manifesto do app. Normalmente, esse novo elemento é um <intent>
.
Abrir URLs
Esta seção descreve como abrir URLs em um app destinado ao Android 11 ou versões mais recentes. Siga um dos exemplos nas subseções a seguir, dependendo de como seu app abre URLs.
Abrir URLs em um navegador ou outro app
Para abrir um URL, use uma intent que contenha a ação de intent ACTION_VIEW
, conforme
descrito na seção 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 será exibida, permitindo que o usuário escolha qual app abre o URL.
Um
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 é afetado pelo comportamento da visibilidade
do pacote do sistema, você não precisa adicionar um elemento <queries>
ao manifesto
do seu app.
Verificar 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. Nesse caso, 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.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 verificar se o dispositivo tem um navegador compatível com
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 determinado URL. 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 uma caixa de diálogo de desambiguação para o usuário, onde 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 { // In order 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 { // In order 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 o 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: essa recomendação se aplica a todos os apps, independentemente do seguinte:
- A versão do SDK de destino do app.
- Se o app exporta o provedor de conteúdo.
Para que apps direcionados ao Android 11 ou versões mais recentes possam acessar o
URI de conteúdo, a intent do app precisa declarar permissões de acesso
do URI
definindo ao menos uma das 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);
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 versões anteriores
do Android.
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>
Conectar-se a um 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>
Conectar-se a um 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>
Conectar-se aos serviços do navegador de mídia
No app de
navegação 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>
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. --> <!-- Allows the app to read the "contacts.xml" file from the other apps. --> <intent> <action android:name="android.accounts.AccountAuthenticator" /> </intent> <!-- Allows the app to 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>
Declarar as necessidades de visibilidade do pacote em uma biblioteca
Se você desenvolver uma biblioteca Android, poderá declarar as necessidades de visibilidade do pacote
adicionando um elemento <queries>
ao arquivo de
manifesto AAR. Esse elemento <queries>
tem a mesma
funcionalidade que o elemento pode declarar nos próprios manifestos.
Se a biblioteca envolver a comunicação com um app host, como o uso de um serviço
vinculado, inclua um elemento <package>
que especifique o
nome do pacote do app host:
<!-- Place inside the <queries> element. --> <package android:name=PACKAGE_NAME />
Ao incluir essa declaração, você pode verificar se o app host está instalado e
interagir com ele, como chamando
bindService()
.
O app de chamada que usa sua biblioteca fica automaticamente
visível para o app host
como resultado dessa interação.