Como direcionar o usuário para outro aplicativo

Um dos recursos mais importantes do Android é a capacidade do app de direcionar o usuário para outro app com base em uma “ação” que ele gostaria de realizar. Por exemplo, caso seu app tenha o endereço de uma empresa que você gostaria de mostrar em um mapa, não será necessário criar uma atividade no seu app que mostre um mapa. Em vez disso, é possível criar uma solicitação para exibir o endereço usando uma Intent. O sistema Android inicia um app capaz de mostrar o endereço em um mapa.

Como explicado na primeira lição, Como criar seu primeiro app, use intents para navegar entre atividades no próprio app. Em geral, isso é feito com intents explícitas, que definem o nome exato da classe do componente que você quer iniciar. No entanto, quando quiser que um app separado execute uma ação, como "ver um mapa", use uma intent implícita.

Esta lição mostra como criar uma intent implícita para uma ação específica e como usá-la para iniciar uma atividade que realize a ação em outro app. Veja também o vídeo incorporado aqui para entender por que é importante incluir verificações de tempo de execução para suas intents implícitas.

Criar uma intent implícita

Intents implícitas não declaram o nome da classe do componente que será iniciado, mas sim uma ação a ser executada. A ação especifica o que precisa ser feito, como ver, editar, enviar ou receber algo.

Associar ações da intent aos dados

As intents geralmente também incluem dados associados à ação, por exemplo, o endereço que você quer ver ou a mensagem de e-mail que quer enviar. Dependendo da intent que você quer criar, os dados podem ser um Uri, um dos vários outros tipos de dados, ou a intent talvez não precise de dados.

Se os dados forem um Uri, use este construtor de Intent() simples para definir a ação e os dados.

Este é um exemplo de como criar uma intent para iniciar uma chamada telefônica usando os dados do Uri para especificar o número de telefone:

Kotlin

val callIntent: Intent = Uri.parse("tel:5551234").let { number ->
    Intent(Intent.ACTION_DIAL, number)
}

Java

Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);

Quando seu app invoca essa intent chamando startActivity(), o app Telefone inicia uma chamada para o número especificado.

Estas são algumas outras intents, bem como as ações e os pares de dados Uri delas:

Ver um mapa

Kotlin

// Map point based on address
val mapIntent: Intent = Uri.parse(
        "geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"
).let { location ->
    // Or map point based on latitude/longitude
    // val location: Uri = Uri.parse("geo:37.422219,-122.08364?z=14") // z param is zoom level
    Intent(Intent.ACTION_VIEW, location)
}

Java

// Map point based on address
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// Or map point based on latitude/longitude
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

Ver uma página da Web

Kotlin

val webIntent: Intent = Uri.parse("https://www.android.com").let { webpage ->
    Intent(Intent.ACTION_VIEW, webpage)
}

Java

Uri webpage = Uri.parse("https://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);

Adicionar extras a uma intent

Outros tipos de intents implícitas exigem dados "extras" que fornecem diferentes tipos de dados, como uma string. Você pode adicionar um ou mais dados extras usando vários métodos putExtra().

Por padrão, o sistema determina o tipo MIME adequado que uma intent exige com base nos dados de Uri incluídos. Se você não incluir um Uri na intent, sempre use setType() para especificar o tipo de dado associado à intent. Definir o tipo MIME especifica melhor que tipos de atividade receberão a intent.

Estas são mais algumas intents que adicionam dados extras para especificar a ação visada:

Enviar um e-mail com um anexo

Kotlin

Intent(Intent.ACTION_SEND).apply {
    // The intent does not have a URI, so declare the "text/plain" MIME type
    type = "text/plain"
    putExtra(Intent.EXTRA_EMAIL, arrayOf("jan@example.com")) // recipients
    putExtra(Intent.EXTRA_SUBJECT, "Email subject")
    putExtra(Intent.EXTRA_TEXT, "Email message text")
    putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"))
    // You can also attach multiple items by passing an ArrayList of Uris
}

Java

Intent emailIntent = new Intent(Intent.ACTION_SEND);
// The intent does not have a URI, so declare the "text/plain" MIME type
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jan@example.com"}); // recipients
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
// You can also attach multiple items by passing an ArrayList of Uris

Criar um evento na agenda

Observação: essa intent para evento da agenda é compatível apenas com a API de nível 14 e mais recentes.

Kotlin

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent(Intent.ACTION_INSERT, Events.CONTENT_URI).apply {
    val beginTime: Calendar = Calendar.getInstance().apply {
        set(2021, 0, 23, 7, 30)
    }
    val endTime = Calendar.getInstance().apply {
        set(2021, 0, 23, 10, 30)
    }
    putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.timeInMillis)
    putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.timeInMillis)
    putExtra(Events.TITLE, "Ninja class")
    putExtra(Events.EVENT_LOCATION, "Secret dojo")
}

Java

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
Calendar beginTime = Calendar.getInstance();
beginTime.set(2021, 0, 23, 7, 30);
Calendar endTime = Calendar.getInstance();
endTime.set(2021, 0, 23, 10, 30);
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
calendarIntent.putExtra(Events.TITLE, "Ninja class");
calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");

Observação: é importante que você defina a Intent para ser o mais específica possível. Por exemplo, se você quiser exibir uma imagem usando a intent ACTION_VIEW, especifique o tipo de MIME como image/*. Isso evita que apps que podem aplicar a ação "ver" para outros tipos de dados (como um app de mapa) sejam acionados pela intent.

Iniciar uma atividade com a intent

Depois de criar sua Intent e definir as informações extras, chame startActivity() para enviá-la ao sistema:

Kotlin

startActivity(intent)

Java

startActivity(intent);

Lidar com a situação em que nenhum app pode receber uma intent

Embora muitas intents sejam processadas por outro app instalado no dispositivo, como um app de telefone, e-mail ou agenda, seu app precisa estar preparado para a situação em que nenhuma atividade possa processar a intent do app. Sempre que você invocar uma intent, esteja pronto para capturar um ActivityNotFoundException, que ocorre quando não há outra atividade que pode lidar com a intent do seu app:

Kotlin

try {
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

try {
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

Depois de capturar essa exceção, decida o que o app fará em seguida. A próxima etapa depende das características específicas da intent que você tentou invocar. Por exemplo, caso você conheça um app específico que processa a intent, forneça um link para que o usuário faça o download dele. Saiba mais sobre como incluir links para seu produto no Google Play.

Caixa de diálogo de desambiguação

Se o sistema identificar mais de uma atividade que possa processar a intent, uma caixa de diálogo (às vezes chamada de "caixa de diálogo de desambiguação") será exibida para que o usuário selecione qual app usar, como mostrado na Figura 1. Se existir apenas uma atividade que possa processar a intent, o sistema a iniciará imediatamente.

Um painel será exibido
  perto da parte inferior da tela. Esse painel lista os diferentes apps que podem
  processar a intent.

Figura 1. Exemplo da caixa de diálogo de seleção que é exibida quando mais de um app pode processar uma intent.

Exemplo completo

Este é um exemplo completo que mostra como criar uma intent para mostrar um mapa, verificar se há um app para processar a intent e iniciá-la:

Kotlin

// Build the intent.
val location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California")
val mapIntent = Intent(Intent.ACTION_VIEW, location)

// Try to invoke the intent.
try {
    startActivity(mapIntent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

// Build the intent.
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

// Try to invoke the intent.
try {
    startActivity(mapIntent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

Mostrar um seletor de app

Figura 2. Caixa de diálogo seletora.

Observe que, ao iniciar uma atividade transmitindo a Intent para startActivity() e quando há mais de um app que responde à intent, o usuário poderá selecionar qual app usar por padrão (marcando uma caixa de seleção na parte inferior da caixa de diálogo, conforme mostrado na Figura 1). Isso é bom ao realizar uma ação para qual o usuário geralmente quer usar o mesmo app todas as vezes, por exemplo, ao abrir uma página da Web (o usuário geralmente usa apenas um navegador) ou tirar uma foto (o usuário costuma preferir uma câmera).

Contudo, se a ação a ser realizada puder ser processada por vários apps e o usuário preferir um diferente a cada vez, como a ação "compartilhar", em que os usuários podem ter vários apps para compartilhar um item, você precisará exibir explicitamente uma caixa de diálogo seletora conforme mostrado na Figura 2. A caixa de diálogo seletora força o usuário a selecionar qual app usar para a ação todas as vezes. Não é possível selecionar um app padrão para a ação.

Para mostrar o seletor, crie uma Intent usando createChooser() e transmita-o para startActivity(). Por exemplo:

Kotlin

val intent = Intent(Intent.ACTION_SEND)

// Create intent to show chooser
val chooser = Intent.createChooser(intent, /* title */ null)

// Try to invoke the intent.
try {
    startActivity(chooser)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

Intent intent = new Intent(Intent.ACTION_SEND);

// Create intent to show chooser
Intent chooser = Intent.createChooser(intent, /* title */ null);

// Try to invoke the intent.
try {
    startActivity(chooser);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

Isso mostra uma caixa de diálogo com uma lista de apps que respondem à intent transmitida ao método createChooser(). O parâmetro title poderá ser fornecido se a ação não for ACTION_SEND ou ACTION_SEND_MULTIPLE.