The Android Developer Challenge is back! Submit your idea before December 2.

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, 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, você pode criar uma solicitação para ver 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, Criar seu primeiro app, você precisa usar intents para navegar entre atividades no app. Geralmente, isso é feito com um intent explícito que define o nome de classe exato do componente que você quer iniciar. No entanto, quando quiser que um app separado execute uma ação, como "ver um mapa", use um intent implícito.

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

Criar um intent implícito

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. Os intents geralmente também incluem dados associados à ação, como o endereço que você quer ver ou a mensagem de e-mail que quer enviar. Dependendo do intent que você quer criar, os dados podem ser um Uri, um de vários outros tipos de dados ou o intent pode não precisar de dado algum.

Se seus dados forem um Uri, existe um construtor Intent() simples que você pode usar 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 de 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 esse intent chamando startActivity(), o app Telefone inicia uma chamada para o número especificado.

Estes são alguns outros 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ícitos 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 um intent exige com base nos dados de 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 MIME especifica melhor que tipos de atividade 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 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: esse intent para evento da agenda é compatível apenas com a API de nível 14 e superior.

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

Verificar se há um app para receber o 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 um intent e não houver um app disponível no dispositivo para processá-lo, o app falhará.

Para verificar se há atividade disponível para responder ao intent, chame queryIntentActivities() e receba uma lista de atividades que podem processar seu 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 app responderá ao intent. Se for false, isso significa que não há apps 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á-lo. Se você conhece um app específico que lide com o 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 um intent.

Depois de criar seu Intent e definir as informações extras, chame para startActivity() para enviá-lo ao sistema. Se o sistema identificar mais de uma atividade que possa processar o 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 aplicativo 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 seu Intent para startActivity() e quando há mais de um app que responde ao intent, o usuário pode selecionar qual aplicativo usar por padrão marcando uma caixa de seleção na parte inferior da caixa de diálogo (consulte a Figura 1). Isso é bom ao realizar uma ação para qual o usuário geralmente quer usar o mesmo app todas as vezes, como 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(). 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 exibe uma caixa de diálogo com uma lista de apps que respondem ao intent transmitido ao método createChooser() e usa o texto fornecido como título da caixa de diálogo.