Leyendo NFC Tags con Android

¿Tienes curiosidad por saber qué es NFC y cómo se puede integrar en tus propias aplicaciones de Android? Este tutorial le presentará rápidamente el tema antes de sumergirse y enseñarle cómo crear una aplicación de lector NFC simple!


Que es la nfc?

NFC es la abreviatura de Cerca de un campo de comunicación. Es el estándar internacional para el intercambio de datos sin contacto. En contraste con una gran variedad de otras tecnologías, como LAN inalámbrica y Bluetooth, la distancia máxima de dos dispositivos es de 10 cm. El desarrollo de la norma comenzó en 2002 por NXP Semiconductors y Sony. El Foro NFC, un consorcio de más de 170 compañías y miembros, que incluía Mastercard, NXP, Nokia, Samsung, Intel y Google, ha diseñado nuevas especificaciones desde 2004..

Hay varias posibilidades para el uso de NFC con dispositivos móviles; por ejemplo, boletos sin papel, controles de acceso, pagos sin efectivo y llaves de auto. Con la ayuda de las etiquetas NFC puedes controlar tu teléfono y cambiar la configuración. Los datos se pueden intercambiar simplemente sosteniendo dos dispositivos uno al lado del otro.

En este tutorial, quiero explicar cómo implementar NFC con el SDK de Android, qué trampas existen y qué tener en cuenta. Crearemos una aplicación paso a paso, que puede leer el contenido de las etiquetas NFC compatibles con NDEF..


Tecnologías NFC

Hay una variedad de etiquetas NFC que se pueden leer con un teléfono inteligente. El espectro abarca desde simples adhesivos y llaveros hasta tarjetas complejas con hardware criptográfico integrado. Las etiquetas también difieren en su tecnología de chip. El más importante es NDEF, que es compatible con la mayoría de las etiquetas. Además, debe mencionarse a Mifare ya que es la tecnología de chip sin contacto más utilizada en todo el mundo. Algunas etiquetas se pueden leer y escribir, mientras que otras son de solo lectura o cifradas.

Solo el formato de intercambio de datos NFC (NDEF) se trata en este tutorial.


Agregar soporte NFC en una aplicación

Comenzamos con un nuevo proyecto y una actividad en blanco. Es importante seleccionar una versión mínima de SDK de nivel 10, ya que NFC solo es compatible después de Android 2.3.3. Recuerde elegir su propio nombre de paquete. He elegido net.vrallev.android.nfc.demo, Porque vrallev.net es el dominio de mi sitio web y la otra parte se refiere al tema de esta aplicación..

 

El diseño predeterminado generado por Eclipse es casi suficiente para nosotros. Solo he añadido una ID a TextView y he cambiado el texto.

 

Para obtener acceso al hardware NFC, debe solicitar un permiso en el manifiesto. Si la aplicación no funciona sin NFC, puede especificar la condición con la etiqueta de característica de uso. Si se requiere NFC, la aplicación no se puede instalar en dispositivos sin ella y Google Play solo mostrará su aplicación a los usuarios que poseen un dispositivo NFC.

  

MainActivity solo debe consistir en el método onCreate (). Puede interactuar con el hardware a través de la clase NfcAdapter. Es importante averiguar si el NfcAdapter es nulo. En este caso, el dispositivo Android no es compatible con NFC..

 paquete net.vrallev.android.nfc.demo; importar android.app.Activity; importar android.nfc.NfcAdapter; importar android.os.Bundle; importar android.widget.TextView; importar android.widget.Toast; / ** * Actividad para leer datos de una etiqueta NDEF. * * @autor Ralf Wondratschek * * / public class MainActivity extiende la actividad public static final String TAG = "NfcDemo"; privado TextView mTextView; privado NfcAdapter mNfcAdapter; @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); mTextView = (TextView) findViewById (R.id.textView_explanation); mNfcAdapter = NfcAdapter.getDefaultAdapter (este); if (mNfcAdapter == null) // Deténgase aquí, definitivamente necesitamos NFC Toast.makeText (esto, "Este dispositivo no admite NFC.", Toast.LENGTH_LONG) .show (); terminar(); regreso;  if (! mNfcAdapter.isEnabled ()) mTextView.setText ("NFC está deshabilitado.");  else mTextView.setText (R.string.explanation);  handleIntent (getIntent ());  private void handleIntent (Intención de intento) // TODO: handle Intent

Si iniciamos nuestra aplicación ahora, podemos ver el texto si NFC está habilitado o deshabilitado.

Cómo filtrar las etiquetas NFC

Tenemos nuestra aplicación de muestra y queremos recibir una notificación del sistema cuando adjuntamos una etiqueta NFC al dispositivo. Como es habitual, Android usa su sistema Intent para entregar etiquetas a las aplicaciones. Si varias aplicaciones pueden manejar la Intención, se muestra el selector de actividad y el usuario puede decidir qué aplicación se abrirá. Abrir URLs o compartir información se maneja de la misma manera.


Filtro de Intención NFC

Hay tres filtros diferentes para las etiquetas:

  1. ACTION_NDEF_DISCOVERED
  2. ACTION_TECH_DISCOVERED
  3. ACTION_TAG_DISCOVERED

La lista está ordenada de la prioridad más alta a la más baja.

Ahora, ¿qué sucede cuando se adjunta una etiqueta al teléfono inteligente? Si el sistema detecta una etiqueta con soporte NDEF, se activa un intento. Un ACTION_TECH_DISCOVERED La intención se activa si no se registra ninguna Actividad de ninguna aplicación para la Intento NDEF o si la etiqueta no es compatible con NDEF. Si, de nuevo, no se encuentra ninguna aplicación para el Intent o la tecnología del chip no se pudo detectar, entonces un ACTION_TAG_DISCOVERED La intención es disparada. El siguiente gráfico muestra el proceso:


En resumen, esto significa que cada aplicación debe filtrarse después de la Intención con la máxima prioridad. En nuestro caso, esta es la Intención NDEF. Implementamos el ACTION_TECH_DISCOVERED Intención primero en resaltar la diferencia entre prioridades..


La tecnología descubrió la intención

Debemos especificar la tecnología en la que estamos interesados. Para este fin, creamos una subcarpeta llamada xml en el res carpeta. En esta carpeta creamos el archivo. nfc_tech_filter.xml, en el que especificamos las tecnologías.

    android.nfc.tech.Ndef    

Ahora debemos crear un IntentFilter en el manifiesto, y la aplicación se iniciará cuando adjuntemos una etiqueta.

           

Si no se registra ninguna otra aplicación para esta Intención, nuestra Actividad comenzará de inmediato. En mi dispositivo, sin embargo, hay otras aplicaciones instaladas, por lo que se muestra el selector de actividad.



NDEF Intención descubierta

Como mencioné antes, el Tech Discovered Intent tiene la segunda prioridad más alta. Sin embargo, dado que nuestra aplicación solo es compatible con NDEF, podemos utilizar la Intención Descubierta de NDEF, que tiene una prioridad más alta. Podemos eliminar de nuevo la lista de tecnologías y reemplazar el IntentFilter con el siguiente.

     

Cuando adjuntemos la etiqueta ahora, la aplicación se iniciará como antes. Sin embargo, hay una diferencia para mí. El selector de actividad no aparece y la aplicación se inicia de inmediato, porque el Intento NDEF tiene una prioridad más alta y las otras aplicaciones solo se registran para las prioridades más bajas. Eso es exactamente lo que queremos..


Despacho de primer plano

Tenga en cuenta que un problema permanece. Cuando nuestra aplicación ya está abierta y adjuntamos la etiqueta nuevamente, la aplicación se abre por segunda vez en lugar de entregar la etiqueta directamente. Este no es nuestro comportamiento previsto. Puede evitar el problema utilizando un Despacho de primer plano.

En lugar de que el sistema haya distribuido la Intención, puede registrar su Actividad para recibir la etiqueta directamente. Esto es importante para un flujo de trabajo en particular, donde no tiene sentido abrir otra aplicación.

He insertado las explicaciones en los lugares apropiados en el código..

 paquete net.vrallev.android.nfc.demo; importar android.app.Activity; importar android.app.PendingIntent; import android.content.Intent; importar android.content.IntentFilter; importar android.content.IntentFilter.MalformedMimeTypeException; importar android.nfc.NfcAdapter; importar android.os.Bundle; importar android.widget.TextView; importar android.widget.Toast; / ** * Actividad para leer datos de una etiqueta NDEF. * * @author Ralf Wondratschek * * / public class MainActivity extiende la actividad public String final String MIME_TEXT_PLAIN = "text / plain"; final estático público String TAG = "NfcDemo"; privado TextView mTextView; privado NfcAdapter mNfcAdapter; @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); mTextView = (TextView) findViewById (R.id.textView_explanation); mNfcAdapter = NfcAdapter.getDefaultAdapter (este); if (mNfcAdapter == null) // Deténgase aquí, definitivamente necesitamos NFC Toast.makeText (esto, "Este dispositivo no admite NFC.", Toast.LENGTH_LONG) .show (); terminar(); regreso;  if (! mNfcAdapter.isEnabled ()) mTextView.setText ("NFC está deshabilitado.");  else mTextView.setText (R.string.explanation);  handleIntent (getIntent ());  @ Anular la anulación de onResume () super.onResume (); / ** * Es importante que la actividad esté en primer plano (reanudada). De lo contrario * se lanza una IllegalStateException. * / setupForegroundDispatch (this, mNfcAdapter);  @ Anular la anulación protegida onPause () / ** * Llame a esto antes de onPause, de lo contrario también se lanzará una IllegalArgumentException. * / stopForegroundDispatch (this, mNfcAdapter); super.onPause ();  @ Anular la anulación protegida en Nueva Intención (Intención de intención) / ** * Se llama a este método cuando una nueva Intención se asocia con la instancia de actividad actual. * En lugar de crear una nueva actividad, se llamará onNewIntent. Para más información echar un vistazo * a la documentación. * * En nuestro caso, se llama a este método cuando el usuario adjunta una etiqueta al dispositivo. * / handleIntent (intención);  private void handleIntent (Intención) // TODO: handle Intent / ** * @param activity La @link Activity correspondiente solicitando el envío de primer plano. * @param adapter El @link NfcAdapter utilizado para el envío de primer plano. * / public static void setupForegroundDispatch (actividad final de la actividad, adaptador NfcAdapter) intención final del intento = nuevo intento (activity.getApplicationContext (), activity.getClass ()); intent.setFlags (Intent.FLAG_ACTIVITY_SINGLE_TOP); final PendingIntent pendingIntent = PendingIntent.getActivity (activity.getApplicationContext (), 0, intent, 0); IntentFilter [] filters = new IntentFilter [1]; String [] [] techList = new String [] [] ; // Observe que este es el mismo filtro que en nuestro manifiesto. filtros [0] = nuevo IntentFilter (); filtros [0] .addAction (NfcAdapter.ACTION_NDEF_DISCOVERED); filtros [0] .addCategory (Intent.CATEGORY_DEFAULT); intente filters [0] .addDataType (MIME_TEXT_PLAIN);  catch (MalformedMimeTypeException e) lanza una nueva RuntimeException ("Comprueba tu tipo mime.");  adapter.enableForegroundDispatch (actividad, pendingIntent, filters, techList);  / ** * actividad @param La solicitud @link BaseActivity correspondiente para detener el envío de primer plano. * @param adapter El @link NfcAdapter utilizado para el envío de primer plano. * / public static void stopForegroundDispatch (actividad final de la actividad, adaptador NfcAdapter) adapter.disableForegroundDispatch (actividad); 

Ahora, cuando adjunta una etiqueta y nuestra aplicación ya está abierta, se llama onNewIntent y no se crea una nueva Actividad.


Lectura de datos de una etiqueta NDEF

El último paso es leer los datos de la etiqueta. Las explicaciones se insertan en los lugares apropiados en el código una vez más. La NdefReaderTask es una clase interna privada.

 paquete net.vrallev.android.nfc.demo; importar java.io.UnsupportedEncodingException; import java.util.Arrays; importar android.app.Activity; importar android.app.PendingIntent; import android.content.Intent; importar android.content.IntentFilter; importar android.content.IntentFilter.MalformedMimeTypeException; importar android.nfc.NdefMessage; importar android.nfc.NdefRecord; importar android.nfc.NfcAdapter; importar android.nfc.Tag; importar android.nfc.tech.Ndef; importar android.os.AsyncTask; importar android.os.Bundle; import android.util.Log; importar android.widget.TextView; importar android.widget.Toast; / * *… Otras partes del código * / private void handleIntent (Intención de intención) String action = intent.getAction (); if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals (acción)) String type = intent.getType (); if (MIME_TEXT_PLAIN.equals (type)) Tag tag = intent.getParcelableExtra (NfcAdapter.EXTRA_TAG); nueva NdefReaderTask (). execute (etiqueta);  else Log.d (TAG, "Tipo mime incorrecto:" + tipo);  else else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals (action)) // En caso de que aún utilicemos la etiqueta Tech Discovered Intent Tag = intent.getParcelableExtra (NfcAdapter.EXTRA_TAG); String [] techList = tag.getTechList (); Cadena searchTech = Ndef.class.getName (); para (String tech: techList) if (searchTech.equals (tech)) new NdefReaderTask (). execute (etiqueta); descanso; 
 / ** * Tarea de fondo para leer los datos. No bloquee el hilo de la interfaz de usuario mientras lee. * * @autor Ralf Wondratschek * * / clase privada NdefReaderTask extiende AsyncTask @Override protected String doInBackground (Tag… params) Tag tag = params [0]; Ndef ndef = Ndef.get (etiqueta); if (ndef == null) // NDEF no es compatible con esta etiqueta. retorno nulo  NdefMessage ndefMessage = ndef.getCachedNdefMessage (); NdefRecord [] records = ndefMessage.getRecords (); para (NdefRecord ndefRecord: registros) if (ndefRecord.getTnf () == NdefRecord.TNF_WELL_KNOWN && Arrays.equals (ndefRecord.getType (), NdefRecord.RTD_TEXT)) try return readText  catch (UnsupportedEncodingException e) Log.e (TAG, "Codificación no compatible", e);  devolver nulo;  private String readText (registro NdefRecord) lanza UnsupportedEncodingException / * * Consulte la especificación del foro NFC para "Definición de tipo de registro de texto" en 3.2.1 * * http://www.nfc-forum.org/specs/ * * bit_7 define la codificación * bit_6 reservado para uso futuro, debe ser 0 * bit_5… 0 longitud del código de idioma IANA * / byte [] payload = record.getPayload (); // Obtener la cadena de codificación de texto textEncoding = ((payload [0] & 128) == 0)? "UTF-8": "UTF-16"; // Obtenga el código de idioma int languageCodeLength = payload [0] & 0063; // String languageCode = new String (payload, 1, languageCodeLength, "US-ASCII"); // p.ej. "en" // Obtener el texto devuelve una nueva cadena (payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);  @ Anular la anulación protegida onPostExecute (resultado de cadena) if (result! = Null) mTextView.setText ("Leer contenido:" + resultado); 

La aplicación ahora lee con éxito el contenido..



Aplicaciones útiles

Para verificar si los datos se leen y escriben correctamente, personalmente me gusta usar las siguientes aplicaciones:

  • NFC TagInfo de NFC Research Lab para leer datos
  • TagInfo by NXP SEMICONDUCTORS para leer datos
  • TagWriter por NXP SEMICONDUCTORS para escribir datos

Conclusión

En este tutorial, he mostrado cómo se pueden extraer los datos de una etiqueta NDEF. Podría ampliar el ejemplo a otros tipos de mime y tecnologías de chip; una característica para escribir datos también sería útil. Se realizó el primer paso para trabajar con NFC. Sin embargo, el SDK de Android ofrece muchas más posibilidades, como un fácil intercambio de datos (llamado Android Beam).

Si desea llevar más lejos su desarrollo de Android, consulte la amplia gama de plantillas de aplicaciones de Android en Envato Market. O contratar a un desarrollador de Android en Envato Studio.


Sobre el Autor

Ralf Wondratschek es un estudiante de ciencias informáticas de Alemania. Además de sus estudios, Ralf trabaja como freelance en el campo de la computación móvil. En los últimos años ha trabajado con Java, XML, HTML, JSP, JSF, Eclipse, Google App Engine y, por supuesto, Android. Ha publicado dos aplicaciones de Android hasta la fecha que se pueden encontrar aquí..

Puede encontrar más información sobre el trabajo del autor en su página de inicio vrallev.net.


Fuentes

http://www.nfc-forum.org/home/n-mark.jpg

http://commons.wikimedia.org/wiki/File%3A%C3%9Cberlagert.jpg

http://developer.android.com/images/nfc_tag_dispatch.png