Participe do evento ⁠#Android11: apresentação de lançamento da versão Beta no dia 3 de junho.

Como enviar o usuário para outro app

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, se seu app tiver 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 um 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 aplicativo. Geralmente, isso é feito com intents explícitas, que define 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ícitos não declaram o nome da classe do componente a iniciar, mas declaram uma ação a executar. A ação especifica o que precisa ser feito, como ver, editar, enviar ou receber algo. 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 simples Intent() 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 deles:

  • 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
            // 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);
        
  • Ver 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í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.

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

    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: essa intent para evento da agenda é compatível apenas com a API de nível 14 e mais recente.

Observação: é importante que você defina Intent para ser o mais específico 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.

Verificar se há um app para receber a intent

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

Cuidado: se você invocar uma intent e não houver um app disponível no dispositivo para processá-la, o app falhará.

Confirme se há atividade disponível para responder à intent chamando queryIntentActivities() para gerar uma lista de atividades que podem processar Intent. Se a List retornada não estiver vazia, a intent poderá ser usada com segurança. 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 app responderá à intent. Se for false, isso significa que não há apps para processar a intent.

Observação: faça essa verificação quando a atividade for iniciada caso seja necessário desativar o recurso que usa a intent antes de o usuário tentar usá-lo. Se você conhece um app específico que lide com a intent, é possível fornecer um link para que o usuário faça o download dele (veja como vincular seus produtos no Google Play).

Iniciar uma atividade com o intent

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

Depois de criar seu Intent e definir as informações extras, chame startActivity() para enviá-lo ao sistema. 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 houver apenas uma atividade que processe o intent, o sistema o 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 app 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 apps

Figura 2. Caixa de diálogo seletora.

Observe que, ao iniciar uma atividade transmitindo o 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 um Intent usando createChooser() e transmita-o para startActivity(). 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 exibe uma caixa de diálogo com uma lista de apps que respondem à intent transmitida ao método createChooser() e usa o texto fornecido como título da caixa de diálogo.