Near Field Communication, ¿el futuro?
domingo, abril 22, 2012 at 12:09PM
rmontero

Near Field Communication (NFC)  es una tecnología inalámbrica de corto alcance que permite la comunicación entre dos dispositivos separados por escasos centímetros. Se trata de una tecnología abierta bajo el amparo del estándar  ISO 18092  establecido a finales del año 2003. NFC opera en la frecuencia de 13.56 MHz lo que la abstiene de cualquier tipo de licencia o permiso de emisión.

Además de su carácter libre, la principal ventaja de este protocolo de comunicación es que opera a muy corta distancia, lo que dificulta cualquier intento de interceptar la señal entre los dos dispositivos que se están comunicando. Esta peculiaridad la hace ideal para realizar transferencias de datos privados y sensibles. Además se incorporan mecanismos de autenticación y verificación de datos para evitar escuchas. También permite establecer sistemas de cifrado de datos similares a los de las tarjetas bancarias.

El hecho de empotrar esta tecnología en los teléfonos móviles, es decir en útiles que nos acompañan a todas partes, da pié a infinidad de usos como por ejemplo:

Android dispone de un completo API para manejar esta tecnología. En este tutorial realizaremos una introducción a algunas de estas clases para intercambiar información entre dispositivos o con tarjetas y chips inteligentes a través de mensajes NDEF (NFC Data Exchange Format), formato estándar para la transmisión NFC. 

Figura 1- http://www.xataka.com

 

MODOS DE OPERACIÓN CON NFC

A través de este API y usando el formato estándar NDEF, podemos trabajar con nuestro terminal en tres modos diferentes:

 

 

  

Figura 2-Tag

 

Figura 3-NFC SmartPoster

Figura 4-Tag Emulation como pase de acceso

Figura 4-Presentación de Android Beam

TERMINALES ANDROID CON TECNOLOGÍA NFC Y EMULADORES

Actualmente los dispositivos móviles disponibles en el mercado con esta tecnología son más bien escasos. Algunos ejemplos son:

Figura 5-Terminales con NFC

 

A la hora de desarrollar aplicaciones NFC en Android, podremos encontrarnos con bastantes problemas si nos disponemos de algunos de los terminales enumerados anteriormente, ya que los dispositivos virtuales de la SDK (AVD) no disponen de funcionalidades para simular mensajes NFC.

En la página www.open-nfc.org podemos encontrar un sistema para emular un entorno NFC, aunque se trata de un conjunto de herramientas un tanto complejas y podríamos decir que aún no se encuentran en un estado estable como para depender de ella en nuestros desarrollos:

Figura 6- NFC Simulator

BREVE VISTAZO AL API

El API se aglutina en el paquete android.nfc, donde podemos encontrar algunas clases como:

NfcManager

Servicio del sistema (getSystemService(NFC_SERVICE)) que permite obtener una instancia del adaptador NFC (NfcAdapter).

NfcAdapter

Adaptador NFC. Podemos definirla como la clase base para trabajar con este API.

NdefMessage

Encapsula un mensaje NDEF (NFC Data Exchange Format). Estos mensajes estarán compuestos por varios registros encapsulados por la clase NdefRecords. También encontramos clases para manipular mensajes en el paque android.nfc.tec.

NdefRecord

Representa un registro del  mensaje NDEF. 

Tag

Representa un tag NFC que ha sido descubierto.

Tabla 1- Principales clase de android.nfc

En este paquete también encontramos algunas clases relacionadas con la definición de listeners:

NfcAdapter.CreateNdefMessageCallback

Será invocada para enviar mensajes NDEF (Android Beam). 

NfcAdapter.OnNdefPushCompleteCallback

Será invocada cuando el dispositivo ha enviado correctamente un mensaje (NdefMessage) a otro dispositivo.  

NfcEvent

Evento relacionado con los “callback” anteriores.

Tabla 2- Clases relacionadas con los listeners

COMPRENDIENDO LOS MENSAJES NFC

Como vimos en la tabla 1, un mensaje NDEF estará representado por la clase NdefMessage, que a su vez estará compuesto por varios registros encapsulados en clases NdefRecord. El primer registro de un mensaje NDEF (NdefRecord) determina como interpretar el conjunto del mensaje. Generalmente un registro NdefRecord de un mensaje NDEF contiene al menos los siguientes cuatro campos:

-          3-bit TNF (Type Name Format): Campo que indica cómo se interpretará el mensaje. (tabla 3)

-          Variable length type: Formato del registro.

-          Variable length ID: Identificador único del registro.

-          Variable length payload: Datos. 

TNF_EMPTY

Mensaje vacío

TNF_WELL_KNOWN

Mensaje NDEF correcto. De acuerdo con la especificación Record Type Definition (RTD)(Tabla 4).

TNF_MIME_MEDIA

Registro definido con un  MIME-type,

TNF_ABSOLUTE_URI

URI

TNF_EXTERNAL_TYPE

Tipo especial definido en el NFC-Forum.

TNF_UNKNOWN

Desconocido

TNF_UNCHANGED

Trozo del mensaje.

Tabla 3- TNF , definidos como constantes en Ndef Record

Cuando la parte correspondiente al TNF (Type Name Format) es de tipo WELL_KNOWN,  significa que el mensaje NDEF contiene algunos de los siguientes tipos de información (RTD Record Type Definition):

RTD_TEXT

Texto plano (acompañado del código ISO de idioma).

RTD_URI

Contiene una URI

RTD_SMART_POSTER

Contiene varios registros de información (URI, títulos en diferentes idiomas, acciones, etc),

Tabla 4- RTD, definidos como constantes en Ndef Record

EJEMPLOS API NFC: LEER MENSAJES NDEF

Antes de realizar cualquier acción con el API NFC, debemos solicitar los permisos oportunos para manipular este hardware. Para ello, añadimos la siguiente línea al descriptor de la aplicación (AndroidManifest.xml):

<uses-permission android:name="android.permission.NFC" />

Para detectar mensajes NDEF registramos componentes de tipo Broadcast Receivers, Actividades o incluso servicios. Probablemente nuestra aplicación estará preparada para procesar solamente algunos de los tipos de mensajes enumerados en el apartado anterior, por ello debe de incorporar un filtro para recibir sólo los que será capaz de tratar:

 <intent-filter>

    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>

    <category android:name="android.intent.category.DEFAULT"/>

    <data android:mimeType="text/plain" />

</intent-filter>

Listado 1.1- Filtro TNF_WELL_KNOWN y RTD_TEXT

El ejemplo anterior muestra un filtro para recibir mensajes de tipo TNF_WELL_KNOWN  y RTD_TEXT. A continuación vemos otros ejemplos para filtrar diferentes tipos de mensajes:

<intent-filter>

  <action android:name="android.nfc.action.NDEF_DISCOVERED"/>

   <category android:name="android.intent.category.DEFAULT"/>

   <data android:scheme="http" android:host="javahispano.org" android:path="/Test" />

</intent-filter>

Listado 1.2- Filtro TNF_WELL_KNOWN y RTD_TEXT RTD_URI o RTD_SMART_POSTER

<intent-filter>

  <action android:name="android.nfc.action.NDEF_DISCOVERED"/>

   <category android:name="android.intent.category.DEFAULT"/>

   <data android:mimeType="x-urn-nfc-ext/fhnw.ch:selfserviceshop" />

</intent-filter>

Listado 1.3- Filtro TNF_MIME_MEDIA 

NOTA: En nuestros filtros de ejemplo hemos utilizado la acción android.nfc.action.NDEF_DISCOVERED, aunque existen otras acciones que componen el mecanismo de resolución de filtros NFC. No entraremos en detalles sobre este mecanismo, pero puede consultarlo en http://developer.android.com/guide/topics/nfc/nfc.html#dispatching

La aplicación (generalmente una Actividad, aunque también puede ser un Broadcast Receiver o un servicio) leerá el intent extrayendo de él los objetos definidos en la tabla  1 (NdefMessage y NdefRecord):

  void resolveIntent(Intent intent) {

    String action = intent.getAction();

    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {

      Parcelable[] rawMsgs = intent

          .getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);

      NdefMessage[] msgs;

      if (rawMsgs != null) {

        msgs = new NdefMessage[rawMsgs.length];

        for (int i = 0; i < rawMsgs.length; i++) {

          msgs[i] = (NdefMessage) rawMsgs[i];

        }

      } else {

        // Unknown tag type

        byte[] empty = new byte[] {};

        NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN, empty,

            empty, empty);

        NdefMessage msg = new NdefMessage(new NdefRecord[] { record });

        msgs = new NdefMessage[] { msg };

      }

    } else {

      Log.e(TAG, "Unknown intent " + intent);

      finish();

      return;

    }

  }

Listado 1.4- Leer mensaje NDEF. 

EJEMPLOS API NFC: ESCRIBIR MENSAJES NDEF EN UN TAG

Tal y como comentábamos anteriormente, existen tags que pueden ser grabados fácilmente mediante nuestros dispositivos. El proceso  será similar al de la lectura, tendremos un intent filter para detectar cuando el dispositivo está encima de un tag, pero en esta ocasión construiremos un objeto tipo  NdefRecord  que grabaremos en el objeto Tag recogido del intent. Por ejemplo podemos grabar texto en un tag, tal y como reflejan los siguientes métodos:

private NdefRecord createRecord() throws UnsupportedEncodingException {
    String text       = "Hello, World!";
    String lang       = "en";
    byte[] textBytes  = text.getBytes();
    byte[] langBytes  = lang.getBytes("US-ASCII");
    int    langLength = langBytes.length;
    int    textLength = textBytes.length;
    byte[] payload    = new byte[1 + langLength + textLength];

    // set status byte (see NDEF spec for actual bits)
    payload[0] = (byte) langLength;

    // copy langbytes and textbytes into payload
    System.arraycopy(langBytes, 0, payload, 1,              langLength);
    System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);

    NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
                                       NdefRecord.RTD_TEXT,
                                       new byte[0],
                                       payload);

    return record;
}

private void write(Intent intent) throws IOException, FormatException {

String accion = intent.getAction();
   if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(accion)) {

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

 NdefRecord[] records = { createRecord() };
    NdefMessage  message = new NdefMessage(records);

    // Get an instance of Ndef for the tag.
    Ndef ndef = Ndef.get(tag);

    // Enable I/O
    ndef.connect();

    // Write the message
    ndef.writeNdefMessage(message);

    // Close the connection
    ndef.close();

}
}

Listado 1.5- Escribir un tag de tipo texto. 

Como vimos anteriormente, podemos crear diferentes tipos de mensajes NDEF. Otro ejemplo consistiría grabar un tag con una URL:

  void writeUrlToTag(Intent intent, String url) throws IOException,

      FormatException {

    String action = intent.getAction();

    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {

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

      Ndef ndefTag = Ndef.get(tag);

      NdefRecord rec = NdefRecordRtdUri.createRtdUriRecord(url);

      NdefMessage msg = new NdefMessage(new NdefRecord[] { rec });

      ndefTag.connect();

      ndefTag.writeNdefMessage(msg);

      ndefTag.close();

    }

  }

Listado 1.6- Escribir una URL en un tag. 

Estos últimos listados, incluido el de la sección anterior (1.3), podrían formar parte de la aplicación NXP Tagwriter, que es un programa capaz de leer y escribir tags. Para escribir en un tag con esta herramienta seguiríamos los siguientes pasos:

Figura 7- Paso 1. Adquirir un tag NFC

Figura 8- Paso 2. Pantalla inicial del programa

Figura 9- Paso 3. Definir los datos a escribir. Por ejemplo una URL

Figura 10- Paso 4. Colocar el dispositivo encima del tag para comenzar el proceso de grabado

La siguiente vez que pasemos el dispositivo por encima del tag, podremos recoger y abrir la URL grabada previamente. Por ejemplo, tal y como muestra el blog http://buildcontext.com/blog/2011/nfc-tag-sticker-writing-programming-google-android-nexus-s:

Figura 11-Lectura de un tag con una URL

Figura 12- URL Ejecutada en el navegador

EJEMPLOS API NFC: Android Bean: Per-to-Per

Android Beam permitirá intercambiar información “Per-to-Per” entre dos dispositivos Android. Un condicionante es que la aplicación que quiere transferir información debe encontrase en primer plano con el dispositivo sin bloquear. Cuando el terminal receptor se encuentre suficientemente cerca, aparecerá en la pantalla un mensaje tipo "Touch to Beam".

Podemos habilitar el uso de Android Beam de alguna de las dos formas siguientes:

 A continuación se presenta un pequeño listado extraído de la aplicación NfcBeam, disponible entre los proyectos de ejemplo de eclipse:

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 mNfcAdapter;
    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
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (mNfcAdapter == null) {
            Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
            finish();
            return;
        }
        // Register callback
        mNfcAdapter.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[] { createMimeRecord(
                        "application/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()));
    }

    /**
     * Creates a custom MIME type encapsulated in an NDEF record
     */
    public NdefRecord createMimeRecord(String mimeType, byte[] payload) {
        byte[] mimeBytes = mimeType.getBytes(Charset.forName("US-ASCII"));
        NdefRecord mimeRecord = new NdefRecord(
                NdefRecord.TNF_MIME_MEDIA, mimeBytes, new byte[0], payload);
        return mimeRecord;
    }
}

 

Listado 1.6- Escribir una URL en un tag. 

 CONCLUSIONES

Android incorpora un API muy completo para dar soporte a cualquier mecanismo de comunicación NFC. En este tutorial tan sólo se ha realizado una pequeña introducción a este estándar, pero debe saber que existen muchos más conceptos de los aquí comentados, aunque esperamos que este artículo puede servirle para iniciarse en esta tecnología. Un impedimento en las prácticas con el API NFC, es que no es posible emularlo en un entorno de desarrollo, por ello debe disponer de un dispositivo real de última generación. Es más, en el caso de las prácticas de Android Beam, necesitará de dos dispositivos, para realizar una comunicación Per-to-Per.

Tal y como hemos querido reflejar en este artículo, NFC se trata de una tecnología con mucho futuro, y que está abriendo y abrirá nuevos mercados y líneas de negocio para nuestras empresas. Sin duda, no debemos dejar escapar la oportunidad de ahondar en ella, ni perder de vista su evolución.


Article originally appeared on javaHispano (http://www.javahispano.org/).
See website for complete article licensing information.