O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Casos de uso para visibilidade do pacote no Android 11

Este documento apresenta vários exemplos comuns de casos de uso em que um app interage com outros apps. Cada seção fornece orientações sobre como atualizar seu app para que ele seja compatível com a mudança de comportamento de visibilidade do pacote que ocorre no Android 11.

Quando o app é destinado ao Android 11 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 direcionado ao Android 11. 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 app usa uma intent implícita para abrir o URL, não é necessário adicionar um elemento <queries> ao manifesto do 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>

Em seguida, quando você chamar queryIntentActivities() e transmitir uma intent da Web como argumento, a lista retornada incluirá os apps de navegador disponíveis.

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.

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.

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

  1. Ler o arquivo contacts.xml dos outros apps.
  2. 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.