Conceptos básicos de NFC

Este documento describe las tareas básicas de NFC que realizas en Android. Explica cómo enviar y recibir datos NFC en forma de mensajes NDEF y describe las APIs del framework de Android que admiten estas funciones. Para temas más avanzados, como un debate sobre el trabajo con datos que no son NDEF, consulta Configuración avanzada de NFC.

Hay dos casos prácticos importantes para tener en cuenta al trabajar con datos NDEF y Android:

  • Lectura de datos NDEF de una etiqueta NFC
  • Transmisión de mensajes NDEF de un dispositivo a otro con Android BeamTM

La lectura de datos NDEF de una etiqueta NFC se maneja con el envío de etiquetas sistema, que analiza las etiquetas NFC descubiertas, categoriza los datos adecuadamente e inicia una aplicación interesada en los datos categorizados. Una aplicación que quiere controlar etiqueta NFC escaneada puede declarar un filtro de intents y para manejar los datos.

La función Android BeamTM permite que un dispositivo envíe un mensaje NDEF otro dispositivo tocando físicamente los dispositivos. Esta interacción proporciona una manera más fácil enviar datos que otras tecnologías inalámbricas, como Bluetooth, porque con NFC, no se requiere se requiere detección o vinculación. La conexión se inicia automáticamente cuando llegan dos dispositivos. dentro del rango. Android Beam está disponible a través de un conjunto de APIs de NFC, por lo que cualquier aplicación puede transmitir información entre dispositivos. Por ejemplo, las aplicaciones de Contactos, Navegador y YouTube usan Android Beam para compartir contactos, páginas web y videos con otros dispositivos

Sistema de envío de etiquetas

Los dispositivos con Android suelen buscar etiquetas NFC cuando esté desbloqueado, a menos que la NFC esté inhabilitada en el menú de configuración del dispositivo. Cuando un dispositivo con Android descubre una etiqueta NFC, el comportamiento deseado es hacer que la actividad más adecuada maneje el intent sin preguntarle al usuario qué aplicación usar. Como los dispositivos escanean las etiquetas NFC en un rango muy corto, es probable que seleccionar una actividad los forzaría a alejar el dispositivo de la etiqueta y a interrumpir la conexión. Debes desarrollar tu actividad para manejar solo las etiquetas NFC que le interesan a tu actividad. evitar que aparezca el Selector de actividades.

Para ayudarte con este objetivo, Android proporciona un sistema especial de envío de etiquetas que analiza los las etiquetas NFC, las analiza e intenta ubicar las aplicaciones que están interesadas en los datos escaneados. Integra lo hace de la siguiente manera:

  1. Analizar la etiqueta NFC y averiguar el tipo de MIME o un URI que identifique la carga útil de datos en la etiqueta.
  2. Encapsulando el tipo MIME o URI y la carga útil en un intent. Estos dos primeros Los pasos se describen en Cómo se asignan las etiquetas NFC a tipos de MIME y URI.
  3. Iniciando una actividad basada en el intent. Esto se describe en Cómo se envían las etiquetas NFC a las aplicaciones.

Cómo se asignan las etiquetas NFC a los tipos MIME y URI

Antes de empezar a escribir tus aplicaciones NFC, es importante entender los diferentes tipos de etiquetas NFC, la manera en que el sistema de envío de etiquetas analiza las etiquetas NFC y el trabajo especial que la etiqueta sistema de envío cuando detecta un mensaje NDEF. Las etiquetas NFC vienen una amplia gama de tecnologías y también pueden tener datos escritos de muchas formas diferentes. Android tiene la mayor compatibilidad con el estándar NDEF, que se define en el Foro NFC.

Los datos NDEF se encapsulan dentro de un mensaje (NdefMessage) que contiene uno o más registros (NdefRecord). Cada registro NDEF debe tener el formato correcto de acuerdo con la especificación del tipo de registro que quieres crear. En Android admite otros tipos de etiquetas que no contienen datos NDEF, con los que puedes trabajar usando las clases en el paquete android.nfc.tech. Para obtener más información sobre estas tecnologías, consulta el tema Conceptos avanzados de NFC. Trabajar con estos otros tipos de etiquetas requiere escribir tu propia pila de protocolos para comunicarte con las etiquetas, así que recomendamos usar NDEF cuando posible para facilitar el desarrollo y máxima asistencia para los dispositivos con Android.

Nota: Para descargar especificaciones completas de NDEF, consulta las Especificaciones del foro NFC y en el sitio web Documentos de la postulación Crear tipos comunes de registros NDEF para ver ejemplos de cómo construir registros NDEF.

Ahora que tienes más información sobre las etiquetas NFC, en las siguientes secciones se describe en detalle cómo Android controla etiquetas con formato NDEF. Cuando un dispositivo con Android escanea una etiqueta NFC que contiene NDEF datos con formato, analiza el mensaje e intenta averiguar el tipo de MIME de los datos o identificar URI Para ello, el sistema lee el primer NdefRecord dentro de NdefMessage para determinar cómo interpretar todo el mensaje NDEF (un mensaje NDEF puede tener varios registros NDEF). En un mensaje NDEF bien formado, el primer NdefRecord contiene los siguientes campos:

TNF (Formato de nombre de tipo) de 3 bits
Indica cómo interpretar el campo de tipo de longitud variable. Los valores válidos son se describe en la Tabla 1.
Tipo de longitud variable
Describe el tipo de registro. Si usas TNF_WELL_KNOWN, utiliza este campo para especificar la definición del tipo de registro (RTD). Los valores válidos de RTD se describen en la tabla 2.
ID de longitud variable
Un identificador único para el registro. Este campo no se usa con frecuencia, pero Si necesitas identificar una etiqueta de forma exclusiva, puedes crear un ID para ella.
Carga útil de longitud variable
La carga útil de datos reales que deseas leer o escribir. Un valor NDEF puede contener varios registros NDEF, así que no asumas que la carga útil completa se encuentra en el primer NDEF registro del mensaje NDEF.

El sistema de envío de etiquetas usa los campos de tipo y TNF para intentar asignar un tipo MIME o URI al Mensaje NDEF. Si tiene éxito, encapsula esa información dentro de un intent ACTION_NDEF_DISCOVERED junto con la carga útil real. Sin embargo, hay son casos en los que el sistema de envío de etiquetas no puede determinar el tipo de datos basándose en el primer valor registro. Esto sucede cuando los datos NDEF no pueden asignarse a un tipo MIME o URI, o cuando el En primer lugar, la etiqueta NFC no contiene datos NDEF. En estos casos, se asigna un objeto Tag que contenga información sobre las tecnologías de la etiqueta y la carga útil. se encapsula dentro de un intent ACTION_TECH_DISCOVERED.

En la Tabla 1, se describe cómo el sistema de envío de etiquetas asigna TNF y tipo campos a tipos MIME o URI. También describe qué TNF no se puede asignar a un tipo MIME o URI. En estos casos, el sistema de envío de etiquetas recurre a ACTION_TECH_DISCOVERED

Por ejemplo, si el sistema de envío de etiquetas encuentra un registro de tipo TNF_ABSOLUTE_URI, asigna el campo de tipo de longitud variable de ese registro. en un URI. El sistema de envío de etiquetas encapsula ese URI en el campo de datos de un intent ACTION_NDEF_DISCOVERED junto con otra información sobre la etiqueta. como la carga útil. Por otro lado, si encuentra un registro de tipo TNF_UNKNOWN, crea un intent que encapsula las tecnologías de la etiqueta. en su lugar.

Tabla 1: Archivos TNF compatibles y sus mapeos

Formato de nombre de tipo (TNF) Mapeo
TNF_ABSOLUTE_URI Este URI se basa en el campo de tipo.
TNF_EMPTY Recurre a ACTION_TECH_DISCOVERED.
TNF_EXTERNAL_TYPE Este URI se basa en el URN en el campo de tipo. El URN está codificado en el campo de tipo NDEF en un formato abreviado: <domain_name>:<service_name>. Android lo asigna a un URI de la siguiente forma: vnd.android.nfc://ext/<domain_name>:<service_name>
TNF_MIME_MEDIA Este tipo de MIME se basa en el campo de tipo.
TNF_UNCHANGED No válido en el primer registro, por lo que recurre a ACTION_TECH_DISCOVERED
TNF_UNKNOWN Recurre a ACTION_TECH_DISCOVERED.
TNF_WELL_KNOWN tipo MIME o URI dependiendo de la definición de tipo de registro (RTD), que establezcas en . Consulta la Tabla 2 para obtener más información sobre las RTD disponibles y sus asignaciones.

Tabla 2: RTD admitidas para TNF_WELL_KNOWN y sus asignaciones

Definición de tipo de registro (RTD) Mapeo
RTD_ALTERNATIVE_CARRIER Recurre a ACTION_TECH_DISCOVERED.
RTD_HANDOVER_CARRIER Recurre a ACTION_TECH_DISCOVERED.
RTD_HANDOVER_REQUEST Recurre a ACTION_TECH_DISCOVERED.
RTD_HANDOVER_SELECT Recurre a ACTION_TECH_DISCOVERED.
RTD_SMART_POSTER Este URI se basa en el análisis de la carga útil.
RTD_TEXT Es el tipo MIME de text/plain.
RTD_URI Este tipo de URI se basa en la carga útil.

Cómo se envían las etiquetas NFC a las aplicaciones

Cuando el sistema de envío de etiquetas termina de crear un intent que encapsula la etiqueta NFC y su información de identificación, envía la intención a una aplicación interesada que filtros para el intent. Si más de una aplicación puede controlar el intent, el Selector de actividades para que el usuario pueda seleccionar la actividad. El sistema de envío de etiquetas define tres intents: que se enumeran en orden de mayor a menor prioridad:

  1. ACTION_NDEF_DISCOVERED: Este intent se usa para iniciar una Actividad cuando se analiza una etiqueta que contiene una carga útil NDEF y es de un tipo reconocido. Este es el intent de mayor prioridad, y el sistema de envío de etiquetas intenta iniciar una actividad con este antes que cualquier otro, siempre que sea posible.
  2. ACTION_TECH_DISCOVERED: Si no hay actividades registradas para procesar ACTION_NDEF_DISCOVERED , el sistema de envío de etiquetas intenta iniciar una aplicación con ese intent. Esta El intent también se inicia directamente (sin iniciar ACTION_NDEF_DISCOVERED primero) si la etiqueta que se analiza contiene datos NDEF que no pueden asignarse a un tipo MIME o URI, o si la etiqueta no contiene NDEF datos, pero es de una tecnología de etiquetas conocida.
  3. ACTION_TAG_DISCOVERED: Se inicia este intent. Si ninguna actividad controla los ACTION_NDEF_DISCOVERED o ACTION_TECH_DISCOVERED .

La forma básica en que funciona el sistema de envíos de etiquetas es la siguiente:

  1. Intenta iniciar una actividad con el intent que creó el sistema de envío de etiquetas cuando analices la etiqueta NFC (ya sea ACTION_NDEF_DISCOVERED o ACTION_TECH_DISCOVERED).
  2. Si no hay filtros de actividades para ese intent, intenta iniciar una actividad con los siguientes intent de menor prioridad (ya sea ACTION_TECH_DISCOVERED o ACTION_TAG_DISCOVERED) hasta que una aplicación filtre por el o hasta que el sistema de envío de etiquetas pruebe todos los intents posibles.
  3. Si no se filtran aplicaciones para ninguno de los intents, no hagas nada.
Figura 1: Sistema de envío de etiquetas

Siempre que sea posible, trabaja con mensajes NDEF y el intent ACTION_NDEF_DISCOVERED, porque es el más específico de entre los tres. Este intent te permite iniciar tu aplicación en un momento más apropiado que el otros dos intents, lo que le brinda al usuario una mejor experiencia.

Cómo solicitar acceso NFC en el manifiesto de Android

Para poder acceder al hardware NFC de un dispositivo y manejar adecuadamente los intents NFC, declara estos elementos de tu archivo AndroidManifest.xml:

  • El elemento NFC <uses-permission> para acceder al hardware NFC:
    <uses-permission android:name="android.permission.NFC" />
    
  • La versión mínima de SDK con la que es compatible tu aplicación. El nivel de API 9 solo admite envío limitado de etiquetas a través de ACTION_TAG_DISCOVERED y solo otorga acceso a mensajes NDEF a través del EXTRA_NDEF_MESSAGES extra. No otras propiedades de etiquetas u operaciones de E/S. Nivel de API 10 Incluye compatibilidad integral con lectores y escritores, así como envíos NDEF en primer plano y nivel de API. 14 proporciona una forma más fácil de enviar mensajes NDEF a otros dispositivos con Android Beam y servicios convenientes para crear registros NDEF.
    <uses-sdk android:minSdkVersion="10"/>
    
  • El elemento uses-feature para que tu aplicación aparezca en Google Play solo para dispositivos que tienen hardware NFC:
    <uses-feature android:name="android.hardware.nfc" android:required="true" />
    

    Si tu aplicación usa la funcionalidad de NFC, pero esa funcionalidad no es crucial para tu puedes omitir el elemento uses-feature y verificar la disponibilidad de NFC en del entorno de ejecución verificando si getDefaultAdapter() es null.

Cómo filtrar por intents de NFC

Para iniciar tu aplicación cuando se escanea una etiqueta NFC que deseas controlar, la aplicación puedes filtrar uno, dos o los tres intents de NFC en el manifiesto de Android. Sin embargo, normalmente quieres filtrar el intent ACTION_NDEF_DISCOVERED para el el mayor control del momento en el que se inicia la aplicación. El intent ACTION_TECH_DISCOVERED es un resguardo de ACTION_NDEF_DISCOVERED cuando no hay aplicaciones que filtren por ACTION_NDEF_DISCOVERED o cuando la carga útil no es NDEF Filtrar por ACTION_TAG_DISCOVERED suele ser demasiado general para un categoría para filtrar. Muchas aplicaciones filtrarán por ACTION_NDEF_DISCOVERED o ACTION_TECH_DISCOVERED antes de ACTION_TAG_DISCOVERED, por lo que tu aplicación tiene una baja probabilidad de empezando. ACTION_TAG_DISCOVERED solo está disponible como último recurso aplicaciones para filtrar cuando no hay otras aplicaciones instaladas para controlar el ACTION_NDEF_DISCOVERED o ACTION_TECH_DISCOVERED.

Debido a que las implementaciones de etiquetas NFC varían y muchas veces no están bajo tu control, esto no siempre es así como sea posible, por lo que puedes recurrir a los otros dos intents cuando sea necesario. Cuando tengas control sobre los tipos de etiquetas y datos escritos, se recomienda que uses NDEF para formatear tus rótulos nuevos rápidamente. Las siguientes secciones describen cómo filtrar para cada tipo de intent.

ACTION_NDEF_DISCOVERED

Para filtrar por intents ACTION_NDEF_DISCOVERED, declara la junto con el tipo de datos que quieres filtrar. El los siguientes filtros de ejemplo para ACTION_NDEF_DISCOVERED intents con un tipo de MIME de text/plain:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="text/plain" />
</intent-filter>

En el siguiente ejemplo, se filtra un URI en el formato de https://developer.android.com/index.html

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
   <data android:scheme="https"
              android:host="developer.android.com"
              android:pathPrefix="/index.html" />
</intent-filter>

ACTION_TECH_DISCOVERED

Si tu actividad filtra por el intent ACTION_TECH_DISCOVERED, debes crear un archivo de recursos XML que especifique las tecnologías que admite tu actividad dentro de un conjunto tech-list. Tu actividad es una coincidencia si un conjunto tech-list es un subconjunto de las tecnologías que se compatible con la etiqueta, que puedes obtener llamando a getTechList().

Por ejemplo, si la etiqueta que se analiza es compatible con MifareClassic, NdefFormatable y NfcA, el El conjunto tech-list debe especificar las tres, dos o una de las tecnologías (y ninguna de las dos else) para que tu actividad coincida.

Los siguientes ejemplos definen todas las tecnologías. Debes quitar los que no estén compatibles con la etiqueta NFC. Guarda este archivo (puedes ponerle el nombre que desees) en la <project-root>/res/xml carpeta.

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.IsoDep</tech>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.NfcB</tech>
        <tech>android.nfc.tech.NfcF</tech>
        <tech>android.nfc.tech.NfcV</tech>
        <tech>android.nfc.tech.Ndef</tech>
        <tech>android.nfc.tech.NdefFormatable</tech>
        <tech>android.nfc.tech.MifareClassic</tech>
        <tech>android.nfc.tech.MifareUltralight</tech>
    </tech-list>
</resources>

También puedes especificar múltiples conjuntos tech-list. Cada una de las tech-list se considera de forma independiente, y tu actividad se considera una coincidencia si se detecta El conjunto tech-list es un subconjunto de las tecnologías que muestra getTechList(). Esto proporciona AND y OR. la semántica para las tecnologías de concordancia. El siguiente ejemplo coincide con las etiquetas que pueden admitir la Tecnologías NfcA y Ndef o que pueden ser compatibles con las tecnologías NfcB y Ndef:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcB</tech>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
</resources>

En el archivo AndroidManifest.xml, especifica el archivo de recursos que acabas de crear En el elemento <meta-data> dentro de <activity> como en el siguiente ejemplo:

<activity>
...
<intent-filter>
    <action android:name="android.nfc.action.TECH_DISCOVERED"/>
</intent-filter>

<meta-data android:name="android.nfc.action.TECH_DISCOVERED"
    android:resource="@xml/nfc_tech_filter" />
...
</activity>

Para obtener más información sobre cómo trabajar con tecnologías de etiquetas y el intent ACTION_TECH_DISCOVERED, consulta Cómo trabajar con etiquetas compatibles. Tecnologías en el documento de NFC avanzado.

ACTION_TAG_DISCOVERED

Para filtrar por ACTION_TAG_DISCOVERED, usa el siguiente intent filtro:

<intent-filter>
    <action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>

Cómo obtener información de intents

Si se inicia una actividad debido a un intent NFC, puedes obtener información sobre el NFC escaneado. etiqueta del intent. Los intents pueden contener los siguientes servicios adicionales según la etiqueta escaneada:

Para obtener estos extras, comprueba si tu actividad se inició con uno de los intents de NFC para garantizar que se escaneó una etiqueta, y luego obtener los valores . En el siguiente ejemplo, se verifica el ACTION_NDEF_DISCOVERED. y recibe los mensajes NDEF de un intent adicional.

Kotlin

override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    ...
    if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
        intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMessages ->
            val messages: List<NdefMessage> = rawMessages.map { it as NdefMessage }
            // Process the messages array.
            ...
        }
    }
}

Java

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    ...
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
        Parcelable[] rawMessages =
            intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        if (rawMessages != null) {
            NdefMessage[] messages = new NdefMessage[rawMessages.length];
            for (int i = 0; i < rawMessages.length; i++) {
                messages[i] = (NdefMessage) rawMessages[i];
            }
            // Process the messages array.
            ...
        }
    }
}

Como alternativa, puedes obtener un objeto Tag del intent, que contienen la carga útil y te permiten enumerar las tecnologías de la etiqueta:

Kotlin

val tag: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)

Java

Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

Cómo crear tipos comunes de registros NDEF

Esta sección describe cómo crear tipos comunes de registros NDEF para ayudarte al escribir en Etiquetas NFC o envío de datos con Android Beam. A partir de Android 4.0 (nivel de API 14), la El método createUri() está disponible para ayudarte a crear los URI se registran automáticamente. A partir de Android 4.1 (nivel de API 16), createExternal() y createMime() están disponibles para ayudarte a crear registros MIME y de tipo externo NDEF. Usa estos métodos de ayuda siempre que sea posible para evitar errores cuando se crean registros NDEF manualmente.

En esta sección, también se describe cómo crear el entorno filtro de intents para el registro. Todos estos ejemplos de registros NDEF deben estar en el primer NDEF. registro del mensaje NDEF que estás escribiendo en una etiqueta o transmisión.

TNF_ABSOLUTE_URI

Nota: Te recomendamos que utilices la En su lugar, escribe RTD_URI de TNF_ABSOLUTE_URI, porque es más eficiente.

Puedes crear un registro NDEF TNF_ABSOLUTE_URI de la siguiente manera: :

Kotlin

val uriRecord = ByteArray(0).let { emptyByteArray ->
    NdefRecord(
            TNF_ABSOLUTE_URI,
            "https://developer.android.com/index.html".toByteArray(Charset.forName("US-ASCII")),
            emptyByteArray,
            emptyByteArray
    )
}

Java

NdefRecord uriRecord = new NdefRecord(
    NdefRecord.TNF_ABSOLUTE_URI ,
    "https://developer.android.com/index.html".getBytes(Charset.forName("US-ASCII")),
    new byte[0], new byte[0]);

El filtro de intents para el registro NDEF anterior se vería así:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="https"
        android:host="developer.android.com"
        android:pathPrefix="/index.html" />
</intent-filter>

TNF_MIME_MEDIA

Puedes crear un registro NDEF TNF_MIME_MEDIA de las siguientes maneras:

Con el método createMime():

Kotlin

val mimeRecord = NdefRecord.createMime(
        "application/vnd.com.example.android.beam",
        "Beam me up, Android".toByteArray(Charset.forName("US-ASCII"))
)

Java

NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam",
    "Beam me up, Android".getBytes(Charset.forName("US-ASCII")));

Creando el NdefRecord de forma manual:

Kotlin

val mimeRecord = Charset.forName("US-ASCII").let { usAscii ->
    NdefRecord(
            NdefRecord.TNF_MIME_MEDIA,
            "application/vnd.com.example.android.beam".toByteArray(usAscii),
            ByteArray(0),
            "Beam me up, Android!".toByteArray(usAscii)
    )
}

Java

NdefRecord mimeRecord = new NdefRecord(
    NdefRecord.TNF_MIME_MEDIA ,
    "application/vnd.com.example.android.beam".getBytes(Charset.forName("US-ASCII")),
    new byte[0], "Beam me up, Android!".getBytes(Charset.forName("US-ASCII")));

El filtro de intents para el registro NDEF anterior se vería así:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="application/vnd.com.example.android.beam" />
</intent-filter>

TNF_WELL_KNOWN con RTD_TEXT

Puedes crear un registro NDEF TNF_WELL_KNOWN de la siguiente manera:

Kotlin

fun createTextRecord(payload: String, locale: Locale, encodeInUtf8: Boolean): NdefRecord {
    val langBytes = locale.language.toByteArray(Charset.forName("US-ASCII"))
    val utfEncoding = if (encodeInUtf8) Charset.forName("UTF-8") else Charset.forName("UTF-16")
    val textBytes = payload.toByteArray(utfEncoding)
    val utfBit: Int = if (encodeInUtf8) 0 else 1 shl 7
    val status = (utfBit + langBytes.size).toChar()
    val data = ByteArray(1 + langBytes.size + textBytes.size)
    data[0] = status.toByte()
    System.arraycopy(langBytes, 0, data, 1, langBytes.size)
    System.arraycopy(textBytes, 0, data, 1 + langBytes.size, textBytes.size)
    return NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, ByteArray(0), data)
}

Java

public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
    byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
    Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
    byte[] textBytes = payload.getBytes(utfEncoding);
    int utfBit = encodeInUtf8 ? 0 : (1 << 7);
    char status = (char) (utfBit + langBytes.length);
    byte[] data = new byte[1 + langBytes.length + textBytes.length];
    data[0] = (byte) status;
    System.arraycopy(langBytes, 0, data, 1, langBytes.length);
    System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
    NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
    NdefRecord.RTD_TEXT, new byte[0], data);
    return record;
}

El filtro de intents para el registro NDEF anterior se vería así:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="text/plain" />
</intent-filter>

TNF_WELL_KNOWN con RTD_URI

Puedes crear un registro NDEF TNF_WELL_KNOWN de las siguientes maneras:

Con el método createUri(String):

Kotlin

val rtdUriRecord1 = NdefRecord.createUri("https://example.com")

Java

NdefRecord rtdUriRecord1 = NdefRecord.createUri("https://example.com");

Con el método createUri(Uri):

Kotlin

val rtdUriRecord2 = Uri.parse("https://example.com").let { uri ->
    NdefRecord.createUri(uri)
}

Java

Uri uri = Uri.parse("https://example.com");
NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);

Creando el NdefRecord de forma manual:

Kotlin

val uriField = "example.com".toByteArray(Charset.forName("US-ASCII"))
val payload = ByteArray(uriField.size + 1)                   //add 1 for the URI Prefix
payload [0] = 0x01                                           //prefixes https://www. to the URI
System.arraycopy(uriField, 0, payload, 1, uriField.size)     //appends URI to payload
val rtdUriRecord = NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, ByteArray(0), payload)

Java

byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII"));
byte[] payload = new byte[uriField.length + 1];              //add 1 for the URI Prefix
payload[0] = 0x01;                                           //prefixes https://www. to the URI
System.arraycopy(uriField, 0, payload, 1, uriField.length);  //appends URI to payload
NdefRecord rtdUriRecord = new NdefRecord(
    NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);

El filtro de intents para el registro NDEF anterior se vería así:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="https"
        android:host="example.com"
        android:pathPrefix="" />
</intent-filter>

TNF_EXTERNAL_TYPE

Puedes crear un registro NDEF TNF_EXTERNAL_TYPE en los siguientes objetos maneras:

Con el método createExternal():

Kotlin

var payload: ByteArray //assign to your data
val domain = "com.example" //usually your app's package name
val type = "externalType"
val extRecord = NdefRecord.createExternal(domain, type, payload)

Java

byte[] payload; //assign to your data
String domain = "com.example"; //usually your app's package name
String type = "externalType";
NdefRecord extRecord = NdefRecord.createExternal(domain, type, payload);

Creando el NdefRecord de forma manual:

Kotlin

var payload: ByteArray
...
val extRecord = NdefRecord(
        NdefRecord.TNF_EXTERNAL_TYPE,
        "com.example:externalType".toByteArray(Charset.forName("US-ASCII")),
        ByteArray(0),
        payload
)

Java

byte[] payload;
...
NdefRecord extRecord = new NdefRecord(
    NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType".getBytes(Charset.forName("US-ASCII")),
    new byte[0], payload);

El filtro de intents para el registro NDEF anterior se vería así:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="vnd.android.nfc"
        android:host="ext"
        android:pathPrefix="/com.example:externalType"/>
</intent-filter>

Usa TNF_EXTERNAL_TYPE en implementaciones de etiquetas NFC más genéricas para mejorar la compatibilidad con ambos Dispositivos con Android y sin ella.

Nota: Los URN de TNF_EXTERNAL_TYPE tienen el formato canónico de la siguiente manera: urn:nfc:ext:example.com:externalType; sin embargo, la especificación NFC Forum RTD declara que la porción urn:nfc:ext: del URN debe omitirse de la registro NDEF. Por lo tanto, todo lo que debes proporcionar es el dominio (example.com en el ejemplo). y escribe (externalType en el ejemplo) separados por dos puntos. Cuando se envía TNF_EXTERNAL_TYPE, Android convierte el URN de urn:nfc:ext:example.com:externalType en un URI de vnd.android.nfc://ext/example.com:externalType, que es lo que filtro de intents en el ejemplo declara.

Registros de aplicaciones de Android

Introducido en Android 4.0 (nivel de API 14), un registro de aplicaciones para Android (AAR) proporciona la certeza de que tu aplicación se inicia cuando se escanea una etiqueta NFC. Un AAR tiene el nombre del paquete de una aplicación incorporada dentro de un registro NDEF. Puedes agregar un AAR a cualquier registro NDEF de tu NDEF. porque Android busca AAR en todo el mensaje NDEF. Si encuentra una AAR, comienza la aplicación según el nombre del paquete dentro del AAR. Si la aplicación no está presente en el , se inicia Google Play para descargar la aplicación.

Los AAR son útiles si deseas evitar que otras aplicaciones filtren el mismo intent y y posiblemente controlar etiquetas específicas que implementaste. Las AAR solo se admiten en las a nivel de la aplicación, debido a la restricción del nombre de paquete, y no a nivel de la Actividad, como sucede con filtrado de intents. Si deseas manejar un intent al nivel de la Actividad, usa filtros de intents.

Si una etiqueta contiene un AAR, se despacha el sistema de envío de etiquetas de la siguiente manera:

  1. Intenta iniciar una Actividad usando un filtro de intents como de costumbre. Si la actividad que coincide el intent también coincide con el AAR, inicia la actividad.
  2. Si la actividad que filtra el intent no coincide con el AAR, si varias actividades pueden manejar el intent o si ninguna actividad lo hace, inicia el que especifica el AAR.
  3. Si no se inicia ninguna aplicación con las AAR, ve a Google Play para descargar la aplicación basada en las AAR.

Nota: Puedes anular los AAR y el sistema de envío de intents con el en primer plano de envío, que permite que una actividad en primer plano tenga prioridad cuando se agrega descubierto. Con este método, la actividad debe estar en primer plano para anular los AAR y el de envío de intents.

Si, de todas formas, deseas filtrar las etiquetas escaneadas que no contienen un AAR, puedes declarar filtros de intents de forma normal. Esto es útil si a tu aplicación le interesan otras etiquetas que no contienen un AAR. Por ejemplo, tal vez quieras asegurarte de que tu aplicación maneje las etiquetas propias que implementa, así como las etiquetas generales implementadas por terceros. Recuerda que los AAR son específicos para dispositivos con Android 4.0 o versiones posteriores. Por lo tanto, al implementar etiquetas, usar una combinación de AAR y tipos/URI de MIME para admitir la más amplia gama de dispositivos. En Cuando implementes etiquetas NFC, piensa cómo escribir tus etiquetas NFC para habilitar compatibilidad con la mayoría de los dispositivos (con la tecnología de Android y de otro tipo). Para ello, puedes Definir un tipo de MIME o URI relativamente único para facilitar la distinción por parte de las aplicaciones.

Android proporciona una API simple para crear un AAR, createApplicationRecord() Todo lo que necesitas lo que debes hacer es incorporar el AAR en cualquier parte de tu NdefMessage. No quieres use el primer registro de su NdefMessage, a menos que el AAR sea la única registro en NdefMessage. Esto se debe a que Android el sistema verifica el primer registro de un NdefMessage para determinar el tipo de MIME o Es el URI de la etiqueta que se usa para crear un intent para que las aplicaciones filtren. El siguiente código te muestra cómo crear un AAR:

Kotlin

val msg = NdefMessage(
        arrayOf(
                ...,
                NdefRecord.createApplicationRecord("com.example.android.beam")
        )
)

Java

NdefMessage msg = new NdefMessage(
        new NdefRecord[] {
            ...,
            NdefRecord.createApplicationRecord("com.example.android.beam")}
        );
)

Cómo transmitir mensajes NDEF a otros dispositivos

Android Beam permite el intercambio de datos de igual a igual entre dos dispositivos con Android. El aplicación que quiera transmitir datos a otro dispositivo debe estar en primer plano, y el dispositivo que reciben los datos no deben bloquearse. Cuando el dispositivo transmisor está lo suficientemente cerca en contacto con un receptor, el dispositivo de transmisión muestra la opción "Tocar para transmitir" de la IU de Google. Luego, el usuario puede elegir transmitir o no el mensaje al dispositivo receptor.

Nota: El envío NDEF en primer plano estaba disponible en el nivel de API 10. que brinda una funcionalidad similar a Android Beam. Estas APIs dejaron de estar disponibles desde entonces, pero están disponibles para admitir dispositivos más antiguos. Consulta enableForegroundNdefPush() para obtener más información.

Puedes habilitar Android Beam para tu aplicación llamando uno de los dos métodos:

  • setNdefPushMessage(): Acepta un NdefMessage para establecer como el mensaje que se transmitirá. Transmite el mensaje automáticamente cuando dos dispositivos están lo suficientemente cerca.
  • setNdefPushMessageCallback(): Acepta una devolución de llamada que contiene un createNdefMessage() que se llama cuando un dispositivo está dentro del alcance para transmitir datos. La devolución de llamada te permite crear el mensaje NDEF solo cuando sea necesario.

Una actividad solo puede enviar un mensaje NDEF a la vez, por lo que setNdefPushMessageCallback() tiene prioridad. por sobre setNdefPushMessage() si se configuraron ambos. Para usar Android Beam, deben cumplirse los siguientes lineamientos generales:

  • La actividad que transmite los datos debe estar en primer plano. Ambos dispositivos deben tener que sus pantallas estén desbloqueadas.
  • Debes encapsular los datos que estás transmitiendo en un NdefMessage .
  • El dispositivo NFC que recibe los datos transmitidos debe admitir la com.android.npp protocolo push NDEF o SNEP de NFC Forum (intercambio simple NDEF) protocolo). El protocolo com.android.npp es obligatorio para los dispositivos con nivel de API 9 (Android) 2.3) hasta el nivel de API 13 (Android 3.2). Tanto com.android.npp como SNEP son obligatorios en Nivel de API 14 (Android 4.0) y versiones posteriores

Nota: Si tu actividad habilita Android Beam y se en primer plano, se inhabilita el sistema estándar de envío de intents. Sin embargo, si tu actividad también permite envío en primer plano, aún podrá escanear las etiquetas que coincidan con los filtros de intents establecidos en la envío en primer plano.

Para habilitar Android Beam, haz lo siguiente:

  1. Crea un NdefMessage que contenga los NdefRecord. que quieres enviar al otro dispositivo.
  2. Llama a setNdefPushMessage() con un NdefMessage o llama a setNdefPushMessageCallback pasando un objeto NfcAdapter.CreateNdefMessageCallback en el método onCreate() de tu actividad. Estos métodos requieren al menos una actividad que quieras habilitar con Android Beam, junto con una lista opcional de otras actividades para activar.

    En general, sueles usar setNdefPushMessage() si tu actividad solo necesita envía el mismo mensaje NDEF en todo momento, cuando dos dispositivos están dentro del alcance para comunicarse. Usas setNdefPushMessageCallback cuando el La aplicación se preocupa por el contexto actual de la aplicación y desea enviar un mensaje NDEF. según lo que haga el usuario en tu aplicación.

En el siguiente ejemplo, se muestra cómo una actividad simple llama a NfcAdapter.CreateNdefMessageCallback en el método onCreate() de un (consulta AndroidBeamDemo) para obtener la muestra completa). Este ejemplo también tiene métodos para ayudarte a crear un registro MIME:

Kotlin

package com.example.android.beam

import android.app.Activity
import android.content.Intent
import android.nfc.NdefMessage
import android.nfc.NdefRecord
import android.nfc.NfcAdapter
import android.nfc.NfcAdapter.CreateNdefMessageCallback
import android.nfc.NfcEvent
import android.os.Bundle
import android.os.Parcelable
import android.widget.TextView
import android.widget.Toast
import java.nio.charset.Charset

class Beam : Activity(), NfcAdapter.CreateNdefMessageCallback {
    
    private var nfcAdapter: NfcAdapter? = null
    private lateinit var textView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
        textView = findViewById(R.id.textView)
        // Check for available NFC Adapter
        nfcAdapter = NfcAdapter.getDefaultAdapter(this)
        if (nfcAdapter == null) {
            Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show()
            finish()
            return
        }
        // Register callback
        nfcAdapter?.setNdefPushMessageCallback(this, this)
    }

    override fun createNdefMessage(event: NfcEvent): NdefMessage {
        val text = "Beam me up, Android!\n\n" +
                "Beam Time: " + System.currentTimeMillis()
        return NdefMessage(
                arrayOf(
                        createMime("application/vnd.com.example.android.beam", text.toByteArray())
                )
                /**
                 * The Android Application Record (AAR) is commented out. When a device
                 * receives a push with an AAR in it, the application specified in the AAR
                 * is guaranteed to run. The AAR overrides the tag dispatch system.
                 * You can add it back in to guarantee that this
                 * activity starts when receiving a beamed message. For now, this code
                 * uses the tag dispatch system.
                 *///,NdefRecord.createApplicationRecord("com.example.android.beam")
        )
    }

    override fun onResume() {
        super.onResume()
        // Check to see that the Activity started due to an Android Beam
        if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
            processIntent(intent)
        }
    }

    override fun onNewIntent(intent: Intent) {
        // onResume gets called after this to handle the intent
        setIntent(intent)
    }

    /**
     * Parses the NDEF Message from the intent and prints to the TextView
     */
    private fun processIntent(intent: Intent) {
        textView = findViewById(R.id.textView)
        // only one message sent during the beam
        intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMsgs ->
            (rawMsgs[0] as NdefMessage).apply {
                // record 0 contains the MIME type, record 1 is the AAR, if present
                textView.text = String(records[0].payload)
            }
        }
    }
}

Java

package com.example.android.beam;

import android.app.Activity;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.os.Parcelable;
import android.widget.TextView;
import android.widget.Toast;
import java.nio.charset.Charset;


public class Beam extends Activity implements CreateNdefMessageCallback {
    NfcAdapter nfcAdapter;
    TextView textView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView textView = (TextView) findViewById(R.id.textView);
        // Check for available NFC Adapter
        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (nfcAdapter == null) {
            Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
            finish();
            return;
        }
        // Register callback
        nfcAdapter.setNdefPushMessageCallback(this, this);
    }

    @Override
    public NdefMessage createNdefMessage(NfcEvent event) {
        String text = ("Beam me up, Android!\n\n" +
                "Beam Time: " + System.currentTimeMillis());
        NdefMessage msg = new NdefMessage(
                new NdefRecord[] { createMime(
                        "application/vnd.com.example.android.beam", text.getBytes())
         /**
          * The Android Application Record (AAR) is commented out. When a device
          * receives a push with an AAR in it, the application specified in the AAR
          * is guaranteed to run. The AAR overrides the tag dispatch system.
          * You can add it back in to guarantee that this
          * activity starts when receiving a beamed message. For now, this code
          * uses the tag dispatch system.
          */
          //,NdefRecord.createApplicationRecord("com.example.android.beam")
        });
        return msg;
    }

    @Override
    public void onResume() {
        super.onResume();
        // Check to see that the Activity started due to an Android Beam
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
            processIntent(getIntent());
        }
    }

    @Override
    public void onNewIntent(Intent intent) {
        // onResume gets called after this to handle the intent
        setIntent(intent);
    }

    /**
     * Parses the NDEF Message from the intent and prints to the TextView
     */
    void processIntent(Intent intent) {
        textView = (TextView) findViewById(R.id.textView);
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
                NfcAdapter.EXTRA_NDEF_MESSAGES);
        // only one message sent during the beam
        NdefMessage msg = (NdefMessage) rawMsgs[0];
        // record 0 contains the MIME type, record 1 is the AAR, if present
        textView.setText(new String(msg.getRecords()[0].getPayload()));
    }
}

Ten en cuenta que este código comenta un AAR, que puedes quitar. Si habilitas las AAR, especificada en el AAR siempre recibe el mensaje de Android Beam. Si la aplicación no está presente, Google Play comenzará a descargar la aplicación. Por lo tanto, el siguiente intent técnicamente no es necesario para dispositivos con Android 4.0 o versiones posteriores si se usa el AAR:

<intent-filter>
  <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <data android:mimeType="application/vnd.com.example.android.beam"/>
</intent-filter>

Con este filtro de intents, la aplicación com.example.android.beam ahora se puede iniciar cuando escanea una etiqueta NFC o recibe un Android Beam con un AAR de escribe com.example.android.beam, o cuando un mensaje con formato NDEF contiene un registro MIME. del tipo application/vnd.com.example.android.beam.

Aunque los AAR garantizan que una aplicación se inicie o se descargue, los filtros de intents son porque te permiten iniciar una actividad de tu elección en tu app en lugar de siempre iniciar la actividad principal dentro del paquete especificado por un AAR. Los AAR no tienen nivel de detalle de la actividad. Además, debido a que algunos dispositivos con Android no admiten AAR, también debes incorporar información de identificación en el primer registro NDEF de tu NDEF. mensajes y filtrarlos por si acaso. Consulta Creación de recursos comunes Tipos de registros NDEF para obtener más información sobre cómo crear registros.