Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

Cómo permitir que otras apps inicien tu actividad

Si tu app puede realizar una acción que podría ser útil desde otra app, debe estar preparada para responder a las solicitudes de acción especificando el filtro de intents apropiado en tu actividad.

Por ejemplo, si compilas una app social que puede compartir mensajes o fotos con los amigos del usuario, debes admitir el intent ACTION_SEND. Luego, cuando los usuarios inician una acción de "compartir" desde otra app, tu app aparece 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 manera, debes agregar un elemento <intent-filter> del 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 aplicación llama a startActivity() o startActivityForResult(), con un intent implícito, el sistema encuentra qué actividad (o actividades) puede responder al intent.

Cómo agregar un filtro de intents

Con el fin de definir de manera adecuada los intents que tu actividad puede controlar, 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 la actividad acepta.

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:

Action
Se trata de una string 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.

Especifícalo en el filtro de intents con el elemento <action>. El valor que especifiques en este elemento debe ser el nombre completo de la string para la acción, en lugar de la constante de la API (consulta los ejemplos que aparecen a continuación).

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

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

Nota: Si no necesitas declarar información específica acerca del Uri de los datos (por ejemplo, cuando tu actividad controla cualquier otro tipo de datos "adicionales", en lugar de un URI), debes especificar solo el atributo android:mimeType para declarar el tipo de datos que controla tu actividad, como text/plain o image/jpeg.

Category
Proporciona una forma adicional de caracterizar la actividad que controla el intent, en general, relacionada con el 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.

Especifícalo en el 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>
    

Sugerencia: Si quieres que el ícono del 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 puedes 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 cuando están sincronizadas con determinados tipos de datos.

Por ejemplo, supongamos que la actividad controla tanto texto como imágenes para los intents ACTION_SEND y ACTION_SENDTO. En ese caso, debes definir dos filtros de intents separados para las dos acciones porque un intent ACTION_SENDTO debe utilizar el Uri de datos para especificar la dirección del destinatario mediante 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 declararan la categoría CATEGORY_DEFAULT. Si no la declaras en el filtro de intents, no se resolverá ningún intent implícito en la actividad.

Para obtener más información sobre cómo enviar y recibir intents ACTION_SEND que realizan comportamientos de uso compartido en redes sociales, consulta la lección sobre Cómo recibir datos simples desde 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

Con el fin de decidir qué acción llevarás a cabo en tu actividad, puedes leer el Intent que se usó para iniciarla.

Cuando comience tu actividad, llama a getIntent() para recuperar el Intent que inició la actividad. Puedes hacerlo en cualquier momento durante el ciclo de vida de la actividad, pero, en general, debes hacerlo durante las primeras devoluciones de llamada, 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 quieres mostrar un resultado a la actividad que invocó la tuya, tan solo llama a setResult() para especificar el código y el Intent del resultado. Cuando finalices la operación y el usuario deba volver a la actividad original, llama a finish() para cerrar (y finalizar) 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. 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 tan solo necesitas mostrar un número entero que indique una de varias opciones de resultado, puedes establecer el código de resultado en cualquier valor superior a 0. Si usas el código de resultado para mostrar un número entero y no necesitas incluir el Intent, puedes llamar a setResult() y pasar 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 unos pocos resultados posibles, de modo que el código de resultado es un número 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 la 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 original llama a startActivityForResult(), el sistema le mostrará el resultado que proporciones a setResult(); de lo contrario, se omitirá el resultado.