¿Cómo se escribe y se bloquea una etiqueta NDEF desde una app iOS?
Abre una sesión NDEF que no termine tras su primera lectura, conéctate a la etiqueta que recibe el delegado, y consulta su estado y su capacidad antes de escribir el mensaje entero en una sola llamada. writeLock deja la etiqueta en solo lectura para siempre, y todo ocurre dentro de una sola sesión.
Una sesión que se queda abierta
La escritura ocurre dentro de una sesión de lectura, así que la sesión no debe terminar en la primera lectura. La nota de Apple sobre el inicializador dice que hay que pasar falso en invalidateAfterFirstRead en una sesión que escribe, lo que la mantiene activa hasta que la aplicación termina.
El delegado implementa readerSession(_:didDetect:), disponible desde iOS 13, para recibir objetos NFCNDEFTag en lugar de mensajes, y después llama a connect(to:) sobre el que quiere. Una etiqueta sigue conectada hasta que la aplicación se conecta a otra o reinicia el sondeo.
Dos etiquetas en el campo son un caso real. El ejemplo de lector de etiquetas de Apple las cuenta antes de escribir, pide mediante alertMessage que las retiren todas, y reinicia el sondeo tras un momento en lugar de escribir en la equivocada.
Primero el estado y la capacidad
queryNDEFStatus devuelve dos valores que deciden si seguir: un estado, notSupported, readOnly o readWrite, y la capacidad, el mayor mensaje NDEF que la etiqueta puede guardar, en bytes.
Compara la capacidad con el mensaje antes de escribir. Un mensaje que no cabe falla con ndefReaderSessionErrorTagSizeTooSmall, después de que alguien haya sostenido el teléfono quieto para nada.
La escritura
writeNDEF(_:) guarda el mensaje entero en una sola llamada y responde a su manejador, o lanza en su forma asíncrona. Su referencia la ata al estado: escribe solo cuando queryNDEFStatus ha devuelto readWrite.
Los errores dicen qué paso falló: ndefReaderSessionErrorTagNotWritable para una etiqueta de solo lectura, ndefReaderSessionErrorTagSizeTooSmall para un mensaje demasiado largo, ndefReaderSessionErrorTagUpdateFailure para una actualización que no se completó, y readerTransceiveErrorTagConnectionLost cuando la etiqueta salió del campo.
Tras una actualización fallida o una conexión perdida, vuelve a leer la etiqueta antes de reintentar. La escritura puede haberse parado a la mitad, el caso que la página del fallo a mitad de camino cubre desde el lado de quien la usa.
Cuando la escritura sale bien, dilo en la hoja y termina la sesión con invalidate(). Hasta entonces, nadie sabe que ya se puede mover el teléfono.
Bloquear es permanente
writeLock() cambia el estado de la etiqueta a solo lectura. Su documentación explica que actualiza el byte de condición de acceso de escritura en el control del archivo NDEF de la etiqueta, y la llama una acción permanente que no se puede deshacer.
Mantenlo como una acción aparte de la escritura, tomada una vez que el contenido se ha vuelto a leer y comprobar en la otra plataforma. Si conviene bloquear o no lo cubre la página del bloqueo.
Lo que las llamadas NDEF no pueden hacer
Las llamadas NDEF se paran en el mensaje. Una contraseña, un contador o una página de configuración son comandos del chip, a los que se llega mediante una sesión de etiqueta y el protocolo propio de la etiqueta, como sendMiFareCommand en una etiqueta MIFARE, con los comandos sacados de la hoja de datos del chip.
Ese trabajo sale por completo de la sesión NDEF, y por eso la elección de sesión va primero, en la página de las sesiones.
Preguntas frecuentes
¿Por qué mi escritura falla con ndefReaderSessionErrorTagSizeTooSmall?
El mensaje es más grande de lo que la etiqueta puede guardar. queryNDEFStatus devuelve la capacidad en bytes, así que compara las dos antes de escribir.
¿Se puede desbloquear una etiqueta bloqueada desde iOS?
No. Apple describe writeLock como una acción permanente que no se puede deshacer.
¿Puede una app de iPhone poner una contraseña a una etiqueta?
Con las llamadas NDEF no. Una contraseña se pone con comandos del chip, enviados en una sesión de etiqueta mediante el protocolo de la etiqueta, con los comandos sacados de la hoja de datos del chip.
¿Por qué la sesión tiene que seguir abierta tras leer?
La escritura ocurre dentro de ella. Con invalidateAfterFirstRead a verdadero, la sesión termina tras la primera lectura y no deja nada con lo que escribir.