Como direcionar o usuário para outro aplicativo

Uma das características mais importantes do Android é a habilidade do aplicativo de direcionar o usuário para outro aplicativo com base em uma “ação” que gostaria de executar. Por exemplo, se o aplicativo tiver o endereço de um negócio que você gostaria de mostrar em um mapa, não será necessário criar uma atividade no aplicativo que mostre um mapa. Em vez disso, é possível criar uma solicitação para exibir o endereço usando um Intent. O sistema Android inicia um aplicativo que pode mostrar o endereço em um mapa.

Como explicado na primeira lição, Como criar seu primeiro aplicativo, use intents para navegar entre atividades no aplicativo. Geralmente, isso é feito com um intent explícito que define o nome exato da classe do componente que você quer iniciar. No entanto, quando você quiser que outro aplicativo execute uma ação, como “visualizar um mapa”, será preciso usar um intent implícito.

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

Criar um intent implícito

Os intents implícitos não declaram o nome da classe do componente que será iniciado, em vez disso, eles declaram uma ação a executar. A ação especifica o que deve ser feito, como visualizar, editar, enviar ou gerar algo. Em geral, os intents incluem dados associados à ação, como o endereço que você quer visualizar ou a mensagem de e-mail que pretende enviar. Dependendo do intent que você quer criar, os dados podem ser um Uri, um dos vários outros tipos de dados, ou o intent talvez não precise de dados.

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

Este é um exemplo de como criar um 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 o aplicativo invoca o intent chamando startActivity(), o aplicativo do telefone inicia uma chamada para o número especificado.

Estes são alguns outros intents, as ações correspondentes e os pares de dados de Uri:

  • Visualizar 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
        // Uri location = 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);
    
  • Visualizar uma página da Web:

    Kotlin

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

    Java

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

Outros tipos de intents implícitos exigem dados “extras” que fornecem diferentes tipos de informações, como uma string. É possível adicionar um ou mais dados extras usando vários métodos putExtra().

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

Estes são mais alguns intents que adicionam dados extras para especificar a ação desejada:

  • 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 = HTTP.PLAIN_TEXT_TYPE
        putExtra(Intent.EXTRA_EMAIL, arrayOf("jon@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[] {"jon@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 de calendário:

    Kotlin

    Intent(Intent.ACTION_INSERT, Events.CONTENT_URI).apply {
        val beginTime: Calendar = Calendar.getInstance().apply {
            set(2012, 0, 19, 7, 30)
        }
        val endTime = Calendar.getInstance().apply {
            set(2012, 0, 19, 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

    Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
    Calendar beginTime = Calendar.getInstance();
    beginTime.set(2012, 0, 19, 7, 30);
    Calendar endTime = Calendar.getInstance();
    endTime.set(2012, 0, 19, 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: esse intent para evento de calendário é compatível somente com nível de API 14 e posteriores.

Observação: é importante definir o Intent para ser o mais específico possível. Por exemplo, se você quer exibir uma imagem usando o intent ACTION_VIEW, especifique o tipo de MIME como image/*. Isso evita que aplicativos que podem “exibir” outros tipos de dados (como um aplicativo de mapas) sejam acionados pelo intent.

Verificar se há um aplicativo para receber o Intent

Embora a plataforma do Android garanta que determinados intents sejam resolvidos com um dos aplicativos embutidos (como aplicativo de Telefone, E-mail ou Agenda), sempre inclua uma etapa de confirmação antes de invocar um intent.

Atenção: se você invocar um intent e não houver um aplicativo disponível no dispositivo para processá-lo, o aplicativo falhará.

Confirme se há atividade disponível para responder ao intent chamando queryIntentActivities() para gerar uma lista de atividades que podem processar o Intent. Se a List retornada não estiver vazia, o intent poderá ser usado com segurança. Por exemplo:

Kotlin

val activities: List<ResolveInfo> = packageManager.queryIntentActivities(
        intent,
        PackageManager.MATCH_DEFAULT_ONLY
)
val isIntentSafe: Boolean = activities.isNotEmpty()

Java

PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent,
        PackageManager.MATCH_DEFAULT_ONLY);
boolean isIntentSafe = activities.size() > 0;

Se isIntentSafe for true, pelo menos um aplicativo responderá ao intent. Caso seja false, não haverá aplicativos disponíveis para processar o intent.

Observação: faça essa verificação quando a atividade for iniciada caso seja necessário desativar o recurso que usa o intent antes de o usuário tentar usá-la. Se você conhecer um aplicativo específico que lide com o intent, forneça um link para que o usuário faça o download (veja como incluir links para seus produtos no Google Play).

Iniciar uma Activity com o Intent

Figura 1. Exemplo de diálogo de seleção que aparece quando mais de um aplicativo pode processar um intent.

Quando tiver criado seu Intent e definido as informações extras, chame startActivity() para enviá-lo ao sistema. Se o sistema identificar mais de uma atividade que possa processar o intent, ele exibirá um diálogo (às vezes chamado de “diálogo de desambiguação”) para o usuário selecionar o aplicativo que será usado, como mostrado na figura 1. Se houver somente uma atividade gerenciando o intent, o sistema a iniciará imediatamente.

Kotlin

startActivity(intent)

Java

startActivity(intent);

Este é um exemplo completo que mostra como criar um intent para exibir um mapa, verificar se há um aplicativo para processar o intent e iniciá-lo:

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)

// Verify it resolves
val activities: List<ResolveInfo> = packageManager.queryIntentActivities(mapIntent, 0)
val isIntentSafe: Boolean = activities.isNotEmpty()

// Start an activity if it's safe
if (isIntentSafe) {
    startActivity(mapIntent)
}

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);

// Verify it resolves
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;

// Start an activity if it's safe
if (isIntentSafe) {
    startActivity(mapIntent);
}

Mostrar um seletor de aplicativo

Figura 2. Caixa de diálogo seletora.

Observe que, ao iniciar uma atividade passando o Intent para startActivity() e quando há mais de um aplicativo que responde ao intent, o usuário poderá selecionar qual aplicativo usar por padrão (marcando uma caixa de seleção na parte inferior da caixa de diálogo, conforme a figura 1). Isso é útil ao executar uma ação em que o usuário quer usar o mesmo aplicativo todas as vezes, como para abrir uma página da Web (o usuário geralmente usa apenas um navegador) ou para tirar fotos (o usuário prefere uma câmera).

Contudo, se a ação a ser executada puder ser processada por vários aplicativos, e o usuário preferir usar um diferente a cada vez (como a ação “compartilhar” em que um item é compartilhado por meio de vários aplicativos), você deverá exibir explicitamente uma caixa de diálogo seletora, conforme a figura 2. Essa caixa exige todas as vezes que o usuário selecione um aplicativo que será usado para a ação (o usuário não pode selecionar um aplicativo padrão para a ação).

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

Kotlin

val intent = Intent(Intent.ACTION_SEND)
...

// Always use string resources for UI text.
// This says something like "Share this photo with"
val title = resources.getString(R.string.chooser_title)
// Create intent to show chooser
val chooser = Intent.createChooser(intent, title)

// Verify the intent will resolve to at least one activity
if (intent.resolveActivity(packageManager) != null) {
    startActivity(chooser)
}

Java

Intent intent = 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 chooser
Intent chooser = Intent.createChooser(intent, title);

// Verify the intent will resolve to at least one activity
if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

Isso exibirá uma caixa de diálogo com uma lista de aplicativos que respondem ao intent passado ao método createChooser() e usa o texto fornecido como título da caixa de diálogo.