¿Modo lector o despacho en primer plano en una app Android?
El modo lector, para una pantalla cuyo fin es leer etiquetas. Entrega cada etiqueta a una devolución de llamada, puede saltarse la comprobación NDEF y el sonido del sistema, y suspende la emulación de tarjeta mientras corre. El despacho en primer plano encaja en una app que se cruza con etiquetas de vez en cuando.
Lo que hacen los dos
Los dos le dan a la actividad que está en pantalla el primer derecho sobre la etiqueta siguiente, por delante de todas las aplicaciones que se registraron para recibir etiquetas en su manifiesto. La referencia de NfcAdapter describe el despacho en primer plano como dar prioridad a la actividad en primer plano, y el modo lector como limitar el controlador mientras la actividad está en primer plano.
Ninguno sobrevive a que la actividad salga de la pantalla. El despacho en primer plano tiene que activarse mientras la actividad está reanudada y desactivarse antes de que termine su onPause, y llamarlo mientras la actividad no está en primer plano lanza IllegalStateException.
Y ninguno cambia lo que pasa cuando la aplicación está cerrada. Una etiqueta que debe arrancar la aplicación pasa por el manifiesto, lo que cubre la página del manifiesto.
Lo que cambia el modo lector
El modo lector convierte el controlador en un lector y en nada más. La referencia declara que desactiva el punto a punto y la emulación de tarjeta mientras corre, así que quien abre tu pantalla de lectura en una caja no puede pagar con el teléfono hasta que salga de ella.
Sondea solo las tecnologías que nombras, mediante marcas como FLAG_READER_NFC_A o FLAG_READER_NFC_V. Una pantalla hecha para etiquetas ISO/IEC 15693 que sondea solo NFC-V no reacciona a una tarjeta bancaria puesta al lado.
FLAG_READER_SKIP_NDEF_CHECK impide que la plataforma lea la etiqueta en busca de NDEF antes de que corra tu devolución de llamada. La referencia es explícita sobre el precio: la clase Ndef no se enumera entonces en la etiqueta, y el despacho basado en NDEF no funciona. Es la marca para una pantalla que envía sus propios comandos, y la equivocada para una pantalla que lee mensajes.
FLAG_READER_NO_PLATFORM_SOUNDS calla el sonido de descubrimiento del sistema, lo que deja a tu aplicación la tarea de decir que ha pasado algo. El extra EXTRA_READER_PRESENCE_CHECK_DELAY fija el retardo con el que la plataforma comprueba que la etiqueta sigue ahí.
Las etiquetas llegan por onTagDiscovered y no como intents. Desde el nivel de API 37 la devolución de llamada tiene además onTagLost, que se llama cuando la etiqueta se va; antes de ese nivel, una salida aparece como una excepción en el intercambio siguiente.
Para un teléfono que emula una tarjeta mediante la emulación de tarjeta host, la referencia recomienda FLAG_READER_NFC_A junto con FLAG_READER_SKIP_NDEF_CHECK.
Lo que conserva el despacho en primer plano
El despacho en primer plano cambia quién recibe la etiqueta y poco más. La plataforma sigue leyendo la etiqueta en busca de NDEF y sigue tocando su sonido de descubrimiento, ya que la marca que lo calla pertenece al modo lector, y nada en la referencia suspende la emulación de tarjeta mientras está activo.
La etiqueta llega como un intent, mediante el PendingIntent que pasas. La guía NFC avanzada lo construye con FLAG_MUTABLE, porque el sistema tiene que añadir la etiqueta al intent, y desde Android 12 la referencia de PendingIntent exige que cada PendingIntent declare su mutabilidad. El mismo ejemplo añade FLAG_ACTIVITY_SINGLE_TOP, para que la etiqueta llegue a la actividad abierta en onNewIntent en lugar de arrancar una segunda copia.
Los filtros y las listas de tecnologías estrechan lo que recibe la actividad, con las mismas reglas que el manifiesto. Pasar null en los dos hace que la actividad reciba todas las etiquetas por ACTION_TAG_DISCOVERED, una acción que la referencia marca como obsoleta desde el nivel de API 37.
La entrega cae en onNewIntent, y la guía de procesos e hilos dice que las devoluciones de llamada del ciclo de vida corren siempre en el hilo principal. Cualquier intercambio con la etiqueta tiene que irse a otra parte, ya que la referencia de TagTechnology prohíbe la entrada y salida en ese hilo.
Elegir entre los dos
| Pregunta | Modo lector | Despacho en primer plano |
|---|---|---|
| Cómo llega la etiqueta | Una devolución de llamada, onTagDiscovered | Un intent, en onNewIntent |
| Emulación de tarjeta mientras está activo | Suspendida | Sin cambios |
| Tecnologías sondeadas | Solo las que nombran las marcas | Todas |
| Comprobación NDEF y sonido del sistema | Se pueden saltar | Siempre se hacen |
| Disponible desde | Nivel de API 19 | Nivel de API 10 |
Elige el modo lector cuando la pantalla existe para leer etiquetas: un recuento de existencias, una herramienta de configuración, un lector para una tarjeta propietaria. La etiqueta va derecha a tu código y nada más en el teléfono compite por ella.
Elige el despacho en primer plano cuando las etiquetas son una entrada entre otras, y el teléfono debe seguir pagando y comportándose con normalidad mientras tu actividad está abierta.
Preguntas frecuentes
¿Por qué el teléfono deja de pagar mientras mi app está abierta?
Está activo el modo lector. La referencia declara que desactiva la emulación de tarjeta mientras la actividad está en primer plano, así que resérvalo para pantallas cuyo fin sea leer.
¿Qué marcas debo usar para leer otro teléfono?
Para un teléfono que emula una tarjeta mediante la emulación de tarjeta host, la referencia recomienda FLAG_READER_NFC_A junto con FLAG_READER_SKIP_NDEF_CHECK.
¿Sigo necesitando filtros de intent en el manifiesto?
Solo para las etiquetas que deben arrancar la aplicación cuando no está abierta. Ni el modo lector ni el despacho en primer plano valen hasta que hay una actividad en pantalla.
¿Por qué enableForegroundDispatch lanza IllegalStateException?
Se llamó mientras la actividad no estaba en primer plano, por ejemplo desde onCreate. Actívalo en onResume y desactívalo en onPause.