Cómo permitir que otras apps inicien tu actividad

Si tu app puede realizar una acción que podría ser útil para otra app, tu app debe estar preparada para responder a las solicitudes de acción de otras apps especificando los filtros de intents correspondientes en tu actividad.

Por ejemplo, si creas una app de redes sociales que permite compartir fotos o mensajes con los contactos de un usuario, deberías admitir el intent ACTION_SEND. Luego, cuando los usuarios inicien una acción para "compartir" contenido desde otra app, tu app aparecerá como una opción en el diálogo de selección (también conocido como "diálogo de desambiguación"), como se muestra en la figura 1.

Figura 1. Diálogo de selección

Para permitir que otras apps inicien tu actividad de esta forma, debes agregar un elemento <intent-filter> en tu archivo de manifiesto para el elemento <activity> correspondiente.

Cuando tu app está instalada en un dispositivo, el sistema identifica tus filtros de intents y agrega la información a un catálogo interno de los intents admitidos por todas las apps instaladas. Cuando una app invoca a startActivity() o a startActivityForResult() con un intent implícito, el sistema comprueba qué actividad (o actividades) puede responder al intent.

Cómo agregar un filtro de intents

Para definir adecuadamente los intents que tu actividad puede manejar, cada filtro de intents que agregues debe ser lo más específico posible en cuanto al tipo de acción y los datos que acepta la actividad.

El sistema puede enviar un Intent determinado a una actividad si esa actividad tiene un filtro de intents que cumple con los siguientes criterios del objeto Intent:

Acción
Una string que indica la acción que se ha de realizar. Por lo general, es uno de los valores definidos por la plataforma, como ACTION_SEND o ACTION_VIEW.

Especifica esto en tu filtro de intents con el elemento <action>. El valor que especifiques en este elemento debe ser el nombre completo de la string de acción en lugar de la constante de la API (consulta los ejemplos más adelante).

Datos
Es una descripción de los datos relacionados con el intent.

Especifica esto en tu filtro de intents con el elemento <data>. Utilizando uno o más atributos en este elemento, puedes especificar el tipo MIME, un prefijo URI, un esquema URI o una combinación de estos y otros valores que indique el tipo de datos aceptados.

Nota: Si no necesitas indicar detalles específicos sobre el Uri de datos (por ejemplo, cuando tu actividad controla otro tipo de datos "adicionales" en lugar de un URI), debes especificar solo el atributo android:mimeType para declarar el tipo de datos que maneja tu actividad, como text/plain o image/jpeg.

Categoría
Proporciona una forma adicional de caracterizar la actividad que maneja el intent, generalmente relacionada con el gesto del usuario o la ubicación desde la cual se inicia. El sistema admite varias categorías diferentes, pero la mayoría no suelen utilizarse. Sin embargo, se definen todos los intents implícitos de forma predeterminada con CATEGORY_DEFAULT.

Especifica esto en tu filtro de intents con el elemento <category>.

En tu filtro de intents, puedes declarar los criterios que tu actividad acepta incluyendo cada uno de ellos con los elementos XML correspondientes anidados en el elemento <intent-filter>.

Por ejemplo, a continuación se muestra una actividad con un filtro que controla el intent ACTION_SEND cuando el tipo de datos es un texto o una imagen:

<activity android:name="ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
</activity>

Sugerencia: Si deseas que el ícono del cuadro de diálogo del selector difiera del ícono predeterminado de la actividad, agrega android:icon en el elemento <intent-filter>.

Cada intent entrante especifica solo una acción y un tipo de datos, pero es correcto declarar varias instancias de los elementos <action>, <category> y <data> en cada <intent-filter>.

Si existen dos pares de acción y datos que son mutuamente excluyentes en tus comportamientos, debes crear filtros de intents separados para especificar qué acciones son aceptables combinadas con qué tipos de datos.

Por ejemplo, supongamos que tu actividad maneja texto e imágenes para los intents ACTION_SEND y ACTION_SENDTO. En este caso, debes definir dos filtros de intents separados para las dos acciones porque un intent ACTION_SENDTO debe usar el Uri de datos para especificar la dirección del destinatario usando el esquema de URI send o sendto. Por ejemplo:

<activity android:name="ShareActivity">
    <!-- filter for sending text; accepts SENDTO action with sms URI schemes -->
    <intent-filter>
        <action android:name="android.intent.action.SENDTO"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:scheme="sms" />
        <data android:scheme="smsto" />
    </intent-filter>
    <!-- filter for sending text or images; accepts SEND action and text or image data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

Nota: Para recibir intents implícitos, debes incluir la categoría CATEGORY_DEFAULT en el filtro de intents. Los métodos startActivity() y startActivityForResult() tratan todos los intents como si pertenecieran a la categoría CATEGORY_DEFAULT. Si no lo declaras en tu filtro de intents, no se aplicará ningún intent implícito a tu actividad.

Para obtener más información sobre el envío y la recepción de intents ACTION_SEND relacionados con comportamientos sociales y uso compartido, consulta la lección Cómo recibir datos simples de otras apps. También encontrarás información útil sobre este tema en Cómo compartir datos simples y Cómo compartir archivos.

Cómo manejar el intent en tu actividad

A fin de decidir la acción que debe realizarse en tu actividad, puedes leer el Intent que se usó para iniciarla.

Al iniciar tu actividad, invoca a getIntent() para recuperar el Intent que inició la actividad. Puedes hacerlo en cualquier momento del ciclo de vida de la actividad, pero generalmente debes hacerlo durante las primeras devoluciones de llamadas, como onCreate() o onStart().

Por ejemplo:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    setContentView(R.layout.main)

    val data: Uri? = intent?.data

    // Figure out what to do based on the intent type
    if (intent?.type?.startsWith("image/") == true) {
        // Handle intents with image data ...
    } else if (intent?.type == "text/plain") {
        // Handle intents with text ...
    }
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    // Get the intent that started this activity
    Intent intent = getIntent();
    Uri data = intent.getData();

    // Figure out what to do based on the intent type
    if (intent.getType().indexOf("image/") != -1) {
        // Handle intents with image data ...
    } else if (intent.getType().equals("text/plain")) {
        // Handle intents with text ...
    }
}

Cómo mostrar un resultado

Si deseas mostrar un resultado a la actividad que invocó la tuya, simplemente invoca a setResult() para especificar el código y el Intent de resultado. Cuando finalices la operación y el usuario deba volver a la actividad original, invoca a finish() para cerrar (y destruir) tu actividad. Por ejemplo:

Kotlin

// Create intent to deliver some kind of result data
Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri")).also { result ->
    setResult(Activity.RESULT_OK, result)
}
finish()

Java

// Create intent to deliver some kind of result data
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri"));
setResult(Activity.RESULT_OK, result);
finish();

Siempre debes especificar un código de resultado con el resultado. Generalmente, es RESULT_OK o RESULT_CANCELED. Luego, puedes proporcionar datos adicionales con un Intent, según sea necesario.

Nota: De forma predeterminada, se establece en RESULT_CANCELED. De este modo, si el usuario presiona el botón Atrás antes de completar la acción y antes de que hayas establecido el resultado, la actividad original recibe el resultado "cancelado".

Si solo necesitas mostrar un valor entero que indique una de las opciones de resultado, puedes fijar el código de resultado en cualquier valor superior a 0. Si usas el código de resultado para brindar un entero y no necesitas incluir el Intent, puedes invocar al setResult() y transferir solo un código de resultado. Por ejemplo:

Kotlin

setResult(RESULT_COLOR_RED)
finish()

Java

setResult(RESULT_COLOR_RED);
finish();

En este caso, solo puede haber un puñado de resultados posibles, por lo que el código de resultado es un entero definido localmente (superior a 0). Esto funciona bien cuando se muestra un resultado a una actividad en tu propia app, porque la actividad que recibe el resultado puede hacer referencia a la constante pública que determina el valor del código de resultado.

Nota: No es necesario comprobar si tu actividad se inició con startActivity() o startActivityForResult(). Simplemente invoca a setResult() si el intent que inició tu actividad puede prever un resultado. Si la actividad inicial invoca a startActivityForResult(), el sistema te mostrará el resultado que proporciones a setResult(); de lo contrario, se ignorará el resultado.