En este documento, se describen temas avanzados de NFC (por ejemplo, el trabajo con varias tecnologías de etiquetas), la escritura en etiquetas NFC y el envío en primer plano, lo que permite que una aplicación en primer plano gestionar intents incluso cuando otras aplicaciones filtren por los mismos.
Cómo trabajar con tecnologías de etiquetas compatibles
Cuando trabajas con etiquetas NFC y dispositivos con Android, el formato principal que usas para leer
y escribir datos en las etiquetas es NDEF. Cuando un dispositivo escanea una etiqueta con datos NDEF, Android proporciona asistencia.
analizar el mensaje y entregarlo en un NdefMessage
cuando
como sea posible. Sin embargo, hay casos en los que se escanea una etiqueta que no contiene
Datos NDEF o cuando los datos NDEF no pudieron asignarse a un tipo MIME o URI.
En estos casos, debes abrir la comunicación directamente con la etiqueta y leerla y escribir en ella con
tu propio protocolo (en bytes sin procesar). Android ofrece compatibilidad genérica para estos casos de uso con el
android.nfc.tech
, que se describe en la Tabla 1 Puedes
usar el método getTechList()
para determinar las tecnologías
compatibles con la etiqueta y crea el TagTechnology
correspondiente
Un objeto con una de las clases proporcionadas por android.nfc.tech
Clase | Descripción |
---|---|
TagTechnology |
La interfaz que deben implementar todas las clases de tecnología de etiquetas. |
NfcA |
Proporciona acceso a propiedades de NFC-A (ISO 14443-3A) y a las operaciones de E/S. |
NfcB |
Proporciona acceso a las propiedades NFC-B (ISO 14443-3B) y a las operaciones de E/S. |
NfcF |
Proporciona acceso a las propiedades NFC-F (JIS 6319-4) y a las operaciones de E/S. |
NfcV |
Proporciona acceso a las propiedades NFC-V (ISO 15693) y a las operaciones de E/S. |
IsoDep |
Proporciona acceso a las propiedades ISO-DEP (ISO 14443-4) y a las operaciones de E/S. |
Ndef |
Proporciona acceso a datos y operaciones NDEF en etiquetas NFC que han sido formateadas como NDEF |
NdefFormatable |
Proporciona operaciones de formato para etiquetas que pueden tener formato NDEF. |
No es necesario que los dispositivos con Android sean compatibles con las siguientes tecnologías de etiquetas.
Clase | Descripción |
---|---|
MifareClassic |
Proporciona acceso a las propiedades de MIFARE Classic y a las operaciones de E/S si este dispositivo Android admite MIFARE. |
MifareUltralight |
Proporciona acceso a las propiedades de MIFARE Ultralight y a las operaciones de E/S si este dispositivo es compatible con MIFARE. |
Cómo trabajar con tecnologías de etiquetas y el intent ACTION_TECH_DISCOVERED
Cuando un dispositivo escanea una etiqueta que tiene datos NDEF, pero no puede asignarse a un MIME o URI,
el sistema de envío de etiquetas intenta iniciar una actividad con el ACTION_TECH_DISCOVERED
. El ACTION_TECH_DISCOVERED
también se usa cuando una etiqueta
con datos que no son NDEF. Tener este resguardo le permite trabajar con los datos en la etiqueta
directamente si el sistema de envío de etiquetas no pudo analizarlo. Los pasos básicos cuando trabajas con
de etiquetas son las siguientes:
- Filtra por un intent
ACTION_TECH_DISCOVERED
que especifique la tecnologías de etiquetas que quieres manejar. Consulta Filtrado para NFC intents para obtener más información. En general, el sistema de envío de etiquetas intenta iniciar un intentACTION_TECH_DISCOVERED
cuando se muestra un mensaje NDEF no se puede asignar a un tipo MIME o URI, o si la etiqueta analizada no contenía datos NDEF. Para Para obtener más información sobre cómo se determina esto, consulta El sistema de envío de etiquetas. - Cuando tu aplicación reciba el intent, obtén el objeto
Tag
del el intent:Kotlin
var tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
Java
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
- Obtén una instancia de
TagTechnology
llamando a uno de los Métodos de fábricaget
de las clases en el paqueteandroid.nfc.tech
. Puedes Para enumerar las tecnologías compatibles de la etiqueta, llama agetTechList()
antes de llamar a un método de fábricaget
. Por ejemplo, para obtener una instancia deMifareUltralight
desde unTag
, haz lo siguiente:Kotlin
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))
Java
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
Cómo leer y escribir en etiquetas
Leer y escribir en una etiqueta NFC implica obtener la etiqueta del intent y abriendo la comunicación con la etiqueta. Debes definir tu propia pila de protocolos para leer y escribir datos a la etiqueta. Sin embargo, ten en cuenta que aún puedes leer y escribir datos NDEF cuando trabajes directamente con una etiqueta. Tú eliges cómo estructurar las cosas. El En el siguiente ejemplo, se muestra cómo trabajar con una placa MIFARE Ultralight.
Kotlin
package com.example.android.nfc import android.nfc.Tag import android.nfc.tech.MifareUltralight import java.io.IOException import java.nio.charset.Charset class MifareUltralightTagTester { fun writeTag(tag: Tag, tagText: String) { MifareUltralight.get(tag)?.use { ultralight -> ultralight.connect() Charset.forName("US-ASCII").also { usAscii -> ultralight.writePage(4, "abcd".toByteArray(usAscii)) ultralight.writePage(5, "efgh".toByteArray(usAscii)) ultralight.writePage(6, "ijkl".toByteArray(usAscii)) ultralight.writePage(7, "mnop".toByteArray(usAscii)) } } } fun readTag(tag: Tag): String? { return MifareUltralight.get(tag)?.use { mifare -> mifare.connect() val payload = mifare.readPages(4) String(payload, Charset.forName("US-ASCII")) } } }
Java
package com.example.android.nfc; import android.nfc.Tag; import android.nfc.tech.MifareUltralight; import android.util.Log; import java.io.IOException; import java.nio.charset.Charset; public class MifareUltralightTagTester { private static final String TAG = MifareUltralightTagTester.class.getSimpleName(); public void writeTag(Tag tag, String tagText) { MifareUltralight ultralight = MifareUltralight.get(tag); try { ultralight.connect(); ultralight.writePage(4, "abcd".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(5, "efgh".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(6, "ijkl".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(7, "mnop".getBytes(Charset.forName("US-ASCII"))); } catch (IOException e) { Log.e(TAG, "IOException while writing MifareUltralight...", e); } finally { try { ultralight.close(); } catch (IOException e) { Log.e(TAG, "IOException while closing MifareUltralight...", e); } } } public String readTag(Tag tag) { MifareUltralight mifare = MifareUltralight.get(tag); try { mifare.connect(); byte[] payload = mifare.readPages(4); return new String(payload, Charset.forName("US-ASCII")); } catch (IOException e) { Log.e(TAG, "IOException while reading MifareUltralight message...", e); } finally { if (mifare != null) { try { mifare.close(); } catch (IOException e) { Log.e(TAG, "Error closing tag...", e); } } } return null; } }
Cómo usar el sistema de envío en primer plano
El sistema de envío en primer plano permite que una actividad intercepte un intent y una reclamación prioridad sobre otras actividades que manejan el mismo intent. El uso de este sistema implica construir algunas estructuras de datos para que el sistema Android pueda enviar la respuesta intents a tu aplicación. Para habilitar el sistema de envío en primer plano, haz lo siguiente:
- Agrega el siguiente código al método
onCreate()
de tu actividad:- Crea un objeto
PendingIntent
mutable para que el sistema Android pueda propagarlo con los detalles de la etiqueta cuando se escanea.Kotlin
val intent = Intent(this, javaClass).apply { addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) } var pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE)
Java
PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE);
- Declara filtros de intent para manejar los intents que deseas interceptar. El primer plano
el sistema de envío verifica los filtros de intents especificados con el intent que se recibe cuando
el dispositivo escanea una etiqueta. Si coincide, entonces tu aplicación maneja el intent. Si aparece
no coincide, el sistema de envío en primer plano recurre al sistema de envío de intents.
Cuando especificas un array
null
de filtros de intents y filtros de tecnología, se especifica que quieres filtrar para todas las etiquetas que recurren aTAG_DISCOVERED
. El siguiente fragmento de código maneja todos los tipos MIME paraNDEF_DISCOVERED
. Tú solo debe manejar los que necesites.Kotlin
val ndef = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED).apply { try { addDataType("*/*") /* Handles all MIME based dispatches. You should specify only the ones that you need. */ } catch (e: IntentFilter.MalformedMimeTypeException) { throw RuntimeException("fail", e) } } intentFiltersArray = arrayOf(ndef)
Java
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); try { ndef.addDataType("*/*"); /* Handles all MIME based dispatches. You should specify only the ones that you need. */ } catch (MalformedMimeTypeException e) { throw new RuntimeException("fail", e); } intentFiltersArray = new IntentFilter[] {ndef, };
- Configura una variedad de tecnologías de etiquetas que tu aplicación quiera manejar. Llama al
Object.class.getName()
para obtener la clase de la tecnología que usas que deseas admitir.Kotlin
techListsArray = arrayOf(arrayOf<String>(NfcF::class.java.name))
Java
techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
- Crea un objeto
- Anula las siguientes devoluciones de llamada del ciclo de vida de la actividad y agrega lógica para habilitar e inhabilitar la
envío en primer plano cuando la actividad pierde (
onPause()
) y recupera (onResume()
) el enfoque. Se debe llamar aenableForegroundDispatch()
desde el subproceso principal y solo cuando la actividad está en primer plano (llamar aonResume()
garantiza esto). También debes implementar la devolución de llamadaonNewIntent
para procesar los datos del NFC escaneado. etiqueta.
Kotlin
public override fun onPause() { super.onPause() adapter.disableForegroundDispatch(this) } public override fun onResume() { super.onResume() adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray) } public override fun onNewIntent(intent: Intent) { val tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) // do something with tagFromIntent }
Java
public void onPause() { super.onPause(); adapter.disableForegroundDispatch(this); } public void onResume() { super.onResume(); adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray); } public void onNewIntent(Intent intent) { Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); // do something with tagFromIntent }