¿Cómo emula una tarjeta una aplicación de Android con Host Card Emulation?
Con un servicio que extiende HostApduService y responde a las APDU, declarado en el manifiesto con el filtro de intent de la emulación de tarjeta, el permiso BIND_NFC_SERVICE y un archivo XML que registra sus identificadores de aplicación en una categoría. Android arranca el servicio con un toque, incluso con la aplicación cerrada.
El servicio y sus dos métodos
La emulación vive en un servicio, no en una actividad. La guía de Android sobre la emulación de tarjeta construye el mecanismo sobre HostApduService, que se ejecuta en segundo plano: un toque lo arranca si no está en marcha, y la transacción ocurre sin que se abra la aplicación. Comprueba FEATURE_NFC_HOST_CARD_EMULATION antes de contar con nada de esto, y decláralo con uses-feature en el manifiesto.
La clase tiene dos métodos que implementar. processCommandApdu() se llama por cada APDU que envía el lector, y devuelve los bytes de la respuesta. Se ejecuta en el hilo principal, así que una respuesta que exige trabajo devuelve null y llega más tarde por sendResponseApdu() desde otro hilo. onDeactivated() se llama cuando el lector selecciona un identificador que lleva a otro servicio, o cuando se rompe el enlace de radio, y su argumento dice cuál de las dos cosas ha pasado.
Lo que viaja es una APDU, como describe la página de las APDU. Android emula ISO-DEP, ISO/IEC 14443-4, y trata los comandos de la ISO/IEC 7816-4; la guía impone ISO-DEP sobre NFC-A y deja NFC-B como opcional. El intercambio es semidúplex y Android admite un solo canal lógico, así que comandos y respuestas se alternan de uno en uno.
Lo que declaran el manifiesto y el XML
La declaración del servicio lleva tres añadidos: un filtro de intent para la acción del servicio APDU de host, el permiso android.permission.BIND_NFC_SERVICE con android:exported puesto a verdadero, y una entrada meta-data que apunta a un recurso XML. El permiso es del sistema, así que exigirlo significa que solo el sistema operativo puede vincularse al servicio. La aplicación tiene además el permiso NFC.
El archivo XML es donde viven los identificadores. Su raíz, host-apdu-service, lleva una descripción destinada a quien usa el teléfono y, si quieres, requireDeviceUnlock. Contiene uno o varios elementos aid-group, cada uno con su propia descripción, una categoría y uno o varios elementos aid-filter que llevan un solo identificador cada uno, escrito en hexadecimal con un número par de caracteres.
Un servicio que responde desde un elemento seguro en lugar de desde tu código se declara igual, con la acción fuera de host y una raíz offhost-apdu-service. Android no tiene ninguna API para hablar directamente con un elemento seguro, lo que la página del elemento seguro sitúa en su contexto.
Grupos de identificadores y categorías
Un identificador de aplicación ocupa hasta dieciséis bytes, y el lector lo nombra en un comando SELECT. La guía recomienda registrar el tuyo propio conforme a la ISO/IEC 7816-5 cuando despliegas tus propios lectores, para que no choque con nadie. Los identificadores que van juntos se ponen en un mismo grupo, y Android encamina un grupo entero: o todos sus identificadores llegan a tu servicio, o ninguno.
Cada grupo declara una categoría, pago u otra. Solo puede haber un grupo de pago activo a la vez en el aparato, y una aplicación que registra identificadores de pago solo hace la transacción cuando tiene el papel de cartera, desde Android 15, o cuando está en primer plano y ha llamado a setPreferredService. Un sistema cerrado, utilizable en un solo comercio, va en la otra categoría, donde los grupos pueden quedarse activos todo el tiempo. Qué servicio alcanza realmente un lector es el asunto de la página del encaminamiento.
Lo que el intercambio tiene que respetar
Que sea corto. La guía pone un límite superior razonable en torno a 1 KB de datos, intercambiables en unos 300 ms, y ese presupuesto decide cuánto tiempo tiene que sostener el teléfono contra el lector quien lo usa.
Que quepa en lo que la plataforma emula. Host Card Emulation responde al intercambio de comandos normalizado; un sistema cuya seguridad vive por debajo de esa capa, MIFARE Classic entre ellos, no se puede emular, como explica la página de Host Card Emulation a quien no está escribiendo el código.
Y decide pronto qué pasa con la pantalla apagada o el teléfono bloqueado, porque la respuesta depende de la versión de Android y de un ajuste del aparato más que de tu código solo. La página de la pantalla apagada lo va viendo versión por versión.
Preguntas frecuentes
¿Tiene que estar abierta la aplicación para que funcione la emulación?
No. Un toque arranca el servicio si no estaba ya en marcha, y el intercambio ocurre en segundo plano sin ninguna pantalla tuya.
¿Puede Host Card Emulation emular una tarjeta MIFARE Classic?
No. Android emula ISO-DEP y trata los comandos de la ISO/IEC 7816-4, y los sistemas cuya seguridad vive por debajo de esa capa quedan fuera de su alcance.
¿Por qué se llama a processCommandApdu en el hilo principal?
Porque el lector espera una respuesta. Devuelve null cuando la respuesta exige trabajo, y envíala luego con sendResponseApdu desde otro hilo.
¿Qué significa onDeactivated?
O bien el lector ha seleccionado un identificador que lleva a otro servicio, o bien se ha roto el enlace de radio. El argumento dice cuál de las dos cosas.