Leggere i tag NFC con Android

Sei curioso di sapere cos'è l'NFC e come può essere integrato nelle tue applicazioni Android? Questo tutorial ti introdurrà rapidamente all'argomento prima di immergerti e ti insegnerà come creare una semplice app per lettore NFC!


Cos'è NFC?

NFC è l'abbreviazione di Near Field Communication. È lo standard internazionale per lo scambio di dati senza contatto. A differenza di una vasta gamma di altre tecnologie, come la LAN wireless e il Bluetooth, la distanza massima di due dispositivi è di 10 cm. Lo sviluppo dello standard è iniziato nel 2002 da NXP Semiconductors e Sony. Il Forum NFC, un consorzio di oltre 170 aziende e membri, che comprendeva Mastercard, NXP, Nokia, Samsung, Intel e Google, dal 2004 progetta nuove specifiche.

Esistono varie possibilità per l'utilizzo NFC con i dispositivi mobili; per esempio, biglietti senza carta, controlli di accesso, pagamenti senza contanti e chiavi della macchina. Con l'aiuto dei tag NFC è possibile controllare il telefono e modificare le impostazioni. I dati possono essere scambiati semplicemente tenendo due dispositivi uno accanto all'altro.

In questo tutorial voglio spiegare come implementare NFC con l'SDK di Android, quali insidie ​​esistono e cosa tenere a mente. Creeremo un'app passo dopo passo, in grado di leggere il contenuto dei tag NFC che supportano NDEF.


Tecnologie NFC

Ci sono una varietà di tag NFC che possono essere letti con uno smartphone. Lo spettro spazia da semplici adesivi e portachiavi a carte complesse con hardware crittografico integrato. I tag differiscono anche nella loro tecnologia dei chip. Il più importante è NDEF, che è supportato dalla maggior parte dei tag. In aggiunta, Mifare dovrebbe essere menzionato in quanto è la tecnologia di chip contactless più utilizzata in tutto il mondo. Alcuni tag possono essere letti e scritti, mentre altri sono di sola lettura o crittografati.

In questo tutorial viene discusso solo il formato NDE Data Exchange Format (NDEF).


Aggiunta del supporto NFC in un'app

Iniziamo con un nuovo progetto e un'attività vuota. È importante selezionare una versione SDK minima del livello 10, poiché NFC è supportato solo dopo Android 2.3.3. Ricordati di scegliere il nome del tuo pacchetto. ho scelto net.vrallev.android.nfc.demo, perché vrallev.net è il dominio del mio sito Web e l'altra parte si riferisce all'argomento di questa applicazione.

 

Il layout predefinito generato da Eclipse è quasi sufficiente per noi. Ho solo aggiunto un ID a TextView e ho cambiato il testo.

 

Per accedere all'hardware NFC, devi richiedere un'autorizzazione nel manifest. Se l'app non funziona senza NFC, puoi specificare la condizione con il tag uses-feature. Se è necessario NFC, l'app non può essere installata sui dispositivi senza di essa e Google Play visualizzerà la tua app solo agli utenti che possiedono un dispositivo NFC.

  

MainActivity dovrebbe consistere solo del metodo onCreate (). Puoi interagire con l'hardware tramite la classe NfcAdapter. È importante scoprire se NfcAdapter è nullo. In questo caso, il dispositivo Android non supporta NFC.

 pacchetto net.vrallev.android.nfc.demo; importare android.app.Activity; import android.nfc.NfcAdapter; importare android.os.Bundle; import android.widget.TextView; importare android.widget.Toast; / ** * Attività per la lettura di dati da un tag NDEF. * * @author Ralf Wondratschek * * / public class MainActivity estende Activity public static final String TAG = "NfcDemo"; TextView privato mTextView; private 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 (this); if (mNfcAdapter == null) // Stop qui, abbiamo sicuramente bisogno di NFC Toast.makeText (questo, "Questo dispositivo non supporta NFC.", Toast.LENGTH_LONG) .show (); finire(); ritorno;  if (! mNfcAdapter.isEnabled ()) mTextView.setText ("NFC is disabled.");  else mTextView.setText (R.string.explanation);  handleIntent (getIntent ());  private void handleIntent (Intent intento) // TODO: handle Intent

Se iniziamo ora la nostra app, possiamo vedere il testo se l'NFC è abilitato o disabilitato.

Come filtrare per i tag NFC

Abbiamo la nostra app di esempio e vogliamo ricevere una notifica dal sistema quando alleghiamo un tag NFC al dispositivo. Come al solito, Android utilizza il proprio sistema Intent per fornire tag alle app. Se più app sono in grado di gestire l'intenzione, viene visualizzato il selettore di attività e l'utente può decidere quale app verrà aperta. L'apertura degli URL o la condivisione delle informazioni viene gestita allo stesso modo.


Filtro Intento NFC

Esistono tre diversi filtri per i tag:

  1. ACTION_NDEF_DISCOVERED
  2. ACTION_TECH_DISCOVERED
  3. ACTION_TAG_DISCOVERED

L'elenco è ordinato dalla priorità più alta a quella più bassa.

Ora cosa succede quando un tag è collegato allo smartphone? Se il sistema rileva un tag con supporto NDEF, viene attivato un intent. Un ACTION_TECH_DISCOVERED L'intent viene attivato se nessuna attività da qualsiasi app è registrata per l'intento NDEF o se il tag non supporta NDEF. Se ancora una volta non viene trovata alcuna app per Intent o la tecnologia del chip non può essere rilevata, allora a ACTION_TAG_DISCOVERED L'intenzione è licenziata. Il seguente grafico mostra il processo:


In sintesi, ciò significa che ogni app deve filtrare dopo l'Intento con la priorità più alta. Nel nostro caso, questo è l'intento NDEF. Implementiamo il ACTION_TECH_DISCOVERED Intenzione prima di evidenziare la differenza tra le priorità.


Tech Discovered Intent

Dobbiamo specificare la tecnologia a cui siamo interessati. Per questo scopo, creiamo una sottocartella chiamata xml nel res cartella. In questa cartella creiamo il file nfc_tech_filter.xml, in cui specifichiamo le tecnologie.

    android.nfc.tech.Ndef    

Ora dobbiamo creare un IntentFilter nel manifest e l'app verrà avviata quando alleghiamo un tag.

           

Se non ci sono altre app registrate per questo intent, la nostra attività inizierà immediatamente. Sul mio dispositivo, tuttavia, sono installate altre app, quindi viene visualizzato il selettore di attività.



NDEF Discovered Intent

Come accennato in precedenza, il Tech Discovered Intent ha la seconda priorità più alta. Tuttavia, poiché la nostra app supporterà solo NDEF, possiamo invece utilizzare l'intento scoperto NDEF, che ha una priorità più alta. Possiamo cancellare di nuovo l'elenco delle tecnologie e sostituire IntentFilter con il seguente.

     

Quando alleghiamo il tag ora, l'app verrà avviata come prima. C'è una differenza per me, comunque. Il selettore di attività non viene visualizzato e l'app viene avviata immediatamente, poiché l'intento NDEF ha una priorità più alta e le altre app registrate solo per le priorità inferiori. Questo è esattamente quello che vogliamo.


Invio in primo piano

Si noti che rimane un problema. Quando la nostra app è già aperta e ricolleghiamo il tag, l'app viene aperta una seconda volta invece di consegnare il tag direttamente. Questo non è il nostro comportamento previsto. È possibile aggirare il problema utilizzando un messaggio in primo piano.

Invece del sistema che ha distribuito l'intenzione, puoi registrare la tua attività per ricevere direttamente il tag. Questo è importante per un particolare flusso di lavoro, in cui non ha senso aprire un'altra app.

Ho inserito le spiegazioni nei punti appropriati del codice.

 pacchetto net.vrallev.android.nfc.demo; importare android.app.Activity; importare android.app.PendingIntent; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentFilter.MalformedMimeTypeException; import android.nfc.NfcAdapter; importare android.os.Bundle; import android.widget.TextView; importare android.widget.Toast; / ** * Attività per la lettura di dati da un tag NDEF. * * @author Ralf Wondratschek * * / public class MainActivity estende Activity public static final String MIME_TEXT_PLAIN = "text / plain"; public static final String TAG = "NfcDemo"; TextView privato mTextView; private 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 (this); if (mNfcAdapter == null) // Stop qui, abbiamo sicuramente bisogno di NFC Toast.makeText (questo, "Questo dispositivo non supporta NFC.", Toast.LENGTH_LONG) .show (); finire(); ritorno;  if (! mNfcAdapter.isEnabled ()) mTextView.setText ("NFC is disabled.");  else mTextView.setText (R.string.explanation);  handleIntent (getIntent ());  @Override protected void onResume () super.onResume (); / ** * È importante che l'attività sia in primo piano (ripresa). Altrimenti viene lanciata una IllegalStateException. * / setupForegroundDispatch (questo, mNfcAdapter);  @Override protected void onPause () / ** * Chiamalo prima di onPause, altrimenti viene lanciata anche UnlegalArgumentException. * / stopForegroundDispatch (questo, mNfcAdapter); super.onPause ();  @Override protected void onNewIntent (Intent intent) / ** * Questo metodo viene chiamato, quando un nuovo intent viene associato all'istanza di attività corrente. * Invece di creare una nuova attività, verrà chiamato onNewIntent. Per maggiori informazioni dare un'occhiata * alla documentazione. * * Nel nostro caso questo metodo viene chiamato, quando l'utente allega un tag al dispositivo. * / handleIntent (intento);  private void handleIntent (Intent intent) // TODO: handle Intent / ** * @param activity L'@link Activity corrispondente che richiede l'invio in primo piano. * @param adapter @link NfcAdapter utilizzato per l'invio in primo piano. * / public static void setupForegroundDispatch (attività attività finale, adattatore NfcAdapter) final Intent intent = new Intent (activity.getApplicationContext (), activity.getClass ()); intent.setFlags (Intent.FLAG_ACTIVITY_SINGLE_TOP); finale PendingIntent pendingIntent = PendingIntent.getActivity (activity.getApplicationContext (), 0, intent, 0); IntentFilter [] filters = new IntentFilter [1]; String [] [] techList = new String [] [] ; // Si noti che questo è lo stesso filtro del nostro manifest. filters [0] = new IntentFilter (); filtri [0] .addAction (NfcAdapter.ACTION_NDEF_DISCOVERED); filtri [0] .addCategory (Intent.CATEGORY_DEFAULT); prova filters [0] .addDataType (MIME_TEXT_PLAIN);  catch (MalformedMimeTypeException e) throw new RuntimeException ("Controlla il tuo tipo mime.");  adapter.enableForegroundDispatch (activity, pendingIntent, filters, techList);  / ** * @param activity @link BaseActivity che richiede di interrompere l'invio in primo piano. * @param adapter @link NfcAdapter utilizzato per l'invio in primo piano. * / public static void stopForegroundDispatch (attività attività finale, adattatore NfcAdapter) adapter.disableForegroundDispatch (attività); 

Ora, quando si allega un tag e la nostra app è già aperta, viene chiamato onNewIntent e non viene creata alcuna nuova attività.


Lettura dei dati da un tag NDEF

L'ultimo passo è leggere i dati dal tag. Le spiegazioni sono inserite nuovamente nei punti appropriati del codice. Il NdefReaderTask è una classe interna privata.

 pacchetto net.vrallev.android.nfc.demo; import java.io.UnsupportedEncodingException; import java.util.Arrays; importare android.app.Activity; importare android.app.PendingIntent; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentFilter.MalformedMimeTypeException; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.nfc.tech.Ndef; importa android.os.AsyncTask; importare android.os.Bundle; import android.util.Log; import android.widget.TextView; importare android.widget.Toast; / * * ... other code parts * / private void handleIntent (Intent intent) String action = intent.getAction (); if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals (action)) String type = intent.getType (); if (MIME_TEXT_PLAIN.equals (type)) Tag tag = intent.getParcelableExtra (NfcAdapter.EXTRA_TAG); nuovo NdefReaderTask (). execute (tag);  else Log.d (TAG, "Tipo mime errato:" + tipo);  else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals (action)) // Nel caso in cui si utilizzasse ancora il tag Tech Intento scoperto tag = intent.getParcelableExtra (NfcAdapter.EXTRA_TAG); String [] techList = tag.getTechList (); String searchedTech = Ndef.class.getName (); for (String tech: techList) if (searchedTech.equals (tech)) new NdefReaderTask (). execute (tag); rompere; 
 / ** * Attività in background per la lettura dei dati. Non bloccare il thread dell'interfaccia utente durante la lettura. * * @author Ralf Wondratschek * * / classe privata NdefReaderTask estende AsyncTask @Override stringa protetta doInBackground (tag ... params) tag tag = params [0]; Ndef ndef = Ndef.get (tag); if (ndef == null) // NDEF non è supportato da questo Tag. return null;  NdefMessage ndefMessage = ndef.getCachedNdefMessage (); NdefRecord [] records = ndefMessage.getRecords (); per (NdefRecord ndefRecord: records) if (ndefRecord.getTnf () == NdefRecord.TNF_WELL_KNOWN && Arrays.equals (ndefRecord.getType (), NdefRecord.RTD_TEXT)) try return readText (ndefRecord);  catch (UnsupportedEncodingException e) Log.e (TAG, "Encoding non supportato", e);  restituisce null;  private String readText (record NdefRecord) genera UnsupportedEncodingException / * * Vedere le specifiche del forum NFC per "Definizione del tipo di record di testo" a 3.2.1 * * http://www.nfc-forum.org/specs/ * * bit_7 definisce la codifica * bit_6 riservato per uso futuro, deve essere 0 * bit_5 ... 0 lunghezza del codice lingua IANA * / byte [] payload = record.getPayload (); // Ottieni la stringa di codifica del testo textEncoding = ((payload [0] e 128) == 0)? "UTF-8": "UTF-16"; // Ottieni il codice lingua int languageCodeLength = payload [0] & 0063; // String languageCode = new String (payload, 1, languageCodeLength, "US-ASCII"); // per esempio. "en" // Ottieni il testo restituisce una nuova stringa (payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);  @Override protected void onPostExecute (String result) if (result! = Null) mTextView.setText ("Leggi contenuto:" + result); 

L'app ora legge con successo il contenuto.



App utili

Per verificare se i dati sono letti e scritti correttamente, personalmente mi piace usare le seguenti app:

  • NFC TagInfo di NFC Research Lab per la lettura dei dati
  • TagInfo di NXP SEMICONDUCTORS per la lettura dei dati
  • TagWriter di NXP SEMICONDUCTORS per la scrittura dei dati

Conclusione

In questo tutorial ti ho mostrato come estrarre i dati da un tag NDEF. Potresti espandere l'esempio ad altri tipi di mime e tecnologie di chip; una funzione per scrivere i dati sarebbe utile pure. Il primo passo per lavorare con NFC è stato fatto. Tuttavia, l'SDK di Android offre molte più possibilità, come un facile scambio di dati (chiamato Android Beam).

Se vuoi migliorare ulteriormente lo sviluppo Android, consulta l'ampia gamma di utili modelli di app Android su Envato Market. O assumere uno sviluppatore Android su Envato Studio.


Circa l'autore

Ralf Wondratschek è uno studente di informatica della Germania. Oltre ai suoi studi, Ralf lavora come libero professionista nel campo del mobile computing. Negli ultimi anni ha lavorato con Java, XML, HTML, JSP, JSF, Eclipse, Google App Engine e, naturalmente, Android. Ha pubblicato due app per Android che possono essere trovate qui.

Puoi saperne di più sul lavoro dell'autore sulla sua homepage vrallev.net.


fonti

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