Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Cómo enviar al usuario a otra app

Una de las funciones más importantes de Android es la capacidad que tiene una app de enviar al usuario a otra en función de una "acción" que le gustaría realizar. Por ejemplo, si tu app tiene la dirección de una empresa que quieres mostrar en un mapa, no necesitas compilar una actividad en tu app para mostrar el mapa. En su lugar, puedes crear una solicitud para ver la dirección mediante un Intent. Luego, el sistema Android inicia una app que puede mostrar la dirección en un mapa.

Como se explicó en la primera clase, Cómo compilar tu primera aplicación, debes utilizar intents para navegar entre las actividades de tu propia app. En general, debes utilizar un intent explícito, que define el nombre exacto de la clase de componente que deseas iniciar. Sin embargo, si quieres que otra app realice una acción, como "mostrar un mapa", debes usar un intent implícito.

En esta lección, se muestra cómo crear un intent implícito para una acción determinada y cómo utilizarlo con el objetivo de iniciar una actividad que realice la acción en otra app. Además, mira el video incorporado a fin de entender por qué es importante que incluyas verificaciones del tiempo de ejecución para tus intents implícitos.

Cómo crear un intent implícito

Los intents implícitos no declaran el nombre de clase del componente que se iniciará, sino que declaran una acción que se llevará a cabo. La acción especifica lo que deseas hacer, por ejemplo, ver, editar, enviar u obtener algo. Los intents también suelen incluir datos asociados con la acción, como la dirección que quieres ver o el mensaje de correo electrónico que quieres enviar. Según el intent que quieras crear, los datos pueden ser un Uri o uno de varios otros tipos de datos. También es posible que el intent no necesite información.

Si tus datos son un Uri, existe un simple constructor Intent() que puedes usar para definir la acción y los datos.

Por ejemplo, a continuación se muestra la manera de crear un intent a fin de iniciar una llamada telefónica usando los datos de un Uri para especificar el número de teléfono:

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

Cuando tu app invoca este intent llamando a startActivity(), la app de teléfono inicia una llamada al número de teléfono especificado.

Estos son otros ejemplos de intents y sus acciones y pares de datos de Uri:

  • Ver un 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 una página 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);
    

Otros tipos de intents implícitos requieren datos "adicionales" que proporcionan diferentes tipos de datos, como una string. Puedes agregar uno o más datos adicionales usando los diferentes métodos putExtra().

De forma predeterminada, el sistema define el tipo de MIME requerido por un intent según los datos de Uri incluidos. Si no incluyes un Uri en el intent, deberás utilizar un elemento setType() para especificar el tipo de datos relacionados con el intent. Cuando se configura el tipo de MIME, también se especifica qué tipos de actividades deben recibir el intent.

A continuación, se incluyen otros intents que agregan datos adicionales para especificar la acción deseada:

  • Enviar un correo electrónico con un archivo adjunto:

    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
    
  • Crear un evento del calendario:

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

    Nota: Este intent para un evento de calendario se admite solamente con la API nivel 14 o superior.

Nota: Es importante que definas un Intent lo más específico posible. Por ejemplo, si deseas mostrar una imagen usando el intent ACTION_VIEW, debes especificar un MIME de tipo image/*, lo que evita que el intent active las apps que pueden "ver" otros tipos de datos (como una app de mapas).

Cómo comprobar que existe una app para recibir el intent

Si bien la plataforma de Android garantiza que se resolverán ciertos intents con una de las apps integradas (como Teléfono, Correo electrónico o Calendario), siempre debes incluir un paso de verificación antes de invocar un intent.

Precaución: Si invocas un intent y no hay ninguna app disponible en el dispositivo que pueda controlarlo, se detendrá tu app.

Para verificar que haya una actividad disponible que pueda responder al intent, invoca a queryIntentActivities() a fin de obtener una lista de actividades capaces de manejar tu Intent. Si no se muestra la List, puedes usar de forma segura el intent. Por ejemplo:

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;

Si isIntentSafe es true, al menos una app responderá al intent. Si es false, no hay apps que puedan controlar el intent.

Nota Debes realizar esta comprobación cuando se inicie por primera vez tu actividad, en caso de que necesites inhabilitar la función que utiliza el intent antes de que el usuario trate de utilizarla. Si conoces una app específica que pueda controlar el intent, proporciona un vínculo para que el usuario la descargue (consulta cómo vincular tu producto en Google Play).

Cómo iniciar una actividad con el intent

Figura 1: Ejemplo del diálogo de selección que aparece cuando más de una app puede controlar un intent

Una vez que hayas creado tu Intent y establecido la información adicional, invoca a startActivity() para enviar el elemento al sistema. Si el sistema identifica más de una actividad que puede controlar el intent, se mostrará un diálogo (a veces denominado "diálogo de desambiguación") para que el usuario seleccione qué app usar, como se muestra en la figura 1. Si existe una única actividad que puede manejar el intent, el sistema la iniciará de inmediato.

Kotlin

startActivity(intent)

Java

startActivity(intent);

A continuación, se incluye un ejemplo completo que muestra cómo crear un intent para ver un mapa, verificar que exista una app para controlar el intent y luego iniciarlo:

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

Cómo mostrar un selector de apps

Figura 2: Diálogo de selección

Ten presente que, cuando inicias una actividad transfiriendo tu Intent a startActivity() y existe más de una app que responde al intent, el usuario puede seleccionar la app que se usará de forma predeterminada (seleccionando la casilla de verificación de la parte inferior del diálogo; consulta la figura 1). Esto es útil cuando se realiza una acción para la que el usuario quiere utilizar siempre la misma app, por ejemplo, cuando se abre una página web (los usuarios suelen usar un solo navegador web) o se toma una fotografía (suelen preferir una cámara).

Sin embargo, si la acción que se realizará se puede controlar mediante varias apps y el usuario quizás prefiere utilizar una diferente cada vez, por ejemplo, una acción de "compartir" un elemento, debes mostrar explícitamente un diálogo de selección, como se indica en la figura 2. El diálogo de selección obliga al usuario a seleccionar qué app quiere utilizar para la acción en cada caso (no puede elegir una app predeterminada para la acción).

Para mostrar el diálogo de selección, crea un Intent usando createChooser() y transfiérelo a startActivity(). Por ejemplo:

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

Aquí se muestra un diálogo con una lista de apps que responden al intent pasado al método createChooser(), con el texto proporcionado como título del diálogo.