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, prepárala para responder a las solicitudes de acción especificando el filtro de intents apropiado en tu actividad.

Por ejemplo, si compilas una aplicación social que puede compartir mensajes o fotos con los amigos del usuario, debes admitir el intent ACTION_SEND. De esta forma, cuando los usuarios inicien una acción de "compartir" desde otra app, la tuya aparecerá como una opción en el diálogo del selector (también conocido como diálogo de desambiguación), como se muestra en la figura 1.

Figura 1: Diálogo del selector.

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.

Si 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 intents admitidos por todas las apps instaladas. Cuando una app llama a startActivity() o startActivityForResult() con un intent implícito, el sistema busca actividades que puedan responder al intent.

Cómo agregar un filtro de intents

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

El sistema puede enviar un Intent determinado a una actividad si esta tiene un filtro de intents según los siguientes criterios del objeto Intent:

Acción
Se trata de una cadena que indica la acción que se debe 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 cadena para la acción, en lugar de la constante de la API, como se muestra en los ejemplos de esta página.

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

Especifica esto en tu filtro de intents con el elemento <data>. Si usas uno o más atributos en este elemento, puedes especificar el tipo de MIME, un prefijo de URI, un esquema de URI, o una combinación de estos y otros atributos para indicar los tipos de datos aceptados.

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

Categoría
Es una forma adicional de caracterizar la actividad que procesa el intent, en general, relacionada con un gesto del usuario o la ubicación desde la que se inicia. El sistema admite varias categorías diferentes, pero la mayoría se usan muy poco. Sin embargo, todos los intents implícitos se definen con CATEGORY_DEFAULT de forma predeterminada.

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

En el filtro de intents, puedes declarar qué criterios acepta tu actividad; para ello, decláralos de manera individual con los elementos XML correspondientes anidados en el elemento <intent-filter>.

Por ejemplo, esta es una actividad con un filtro de intents que controla el intent ACTION_SEND cuando el tipo de datos es 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>

Nota: Si quieres que el ícono que aparece en el diálogo del selector sea diferente del ícono predeterminado de tu actividad, agrega android:icon en el elemento <intent-filter>.

Cada intent entrante especifica solo una acción y un tipo de datos, pero está bien que declares 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 sus comportamientos, crea filtros de intents separados para especificar qué acciones son aceptables cuando están sincronizadas con determinados tipos de datos.

Por ejemplo, supongamos que tu actividad procesa 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 con el esquema de URI send o sendto. Esto se muestra en el siguiente 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 a todos los intents como si declararan la categoría CATEGORY_DEFAULT. Si no la declaras en el filtro de intents, no se resuelve ningún intent implícito en la actividad.

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

Cómo controlar el intent en tu actividad

Para decidir qué acción realizar en tu actividad, lee el Intent que se usa para iniciarla.

Al iniciar tu actividad, llama 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().

Esto se muestra en el siguiente 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 quieres mostrar un resultado a la actividad que invocó la tuya, llama al setResult() para especificar el código y el Intent de resultado. Cuando la operación finalice y el usuario regrese a la actividad original, llama al elemento finish() para cerrar (y destruir) tu actividad. Esto se muestra en el siguiente 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. En general, es RESULT_OK o RESULT_CANCELED. Luego, puedes proporcionar datos adicionales con un Intent, según sea necesario.

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

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:

Kotlin

setResult(RESULT_COLOR_RED)
finish()

Java

setResult(RESULT_COLOR_RED);
finish();

En este caso, solo puede haber unos pocos resultados posibles, de modo que el código de resultado es un valor entero definido localmente (mayor que 0). Esto funciona bien cuando muestras 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 verificar si tu actividad se inició con startActivity() o startActivityForResult(). Simplemente llama a setResult() si el intent que inició tu actividad puede esperar un resultado. Si la actividad inicial llamó a startActivityForResult(), el sistema mostrará el resultado que proporciones a setResult(); de lo contrario, se ignorará el resultado.