NFC-Tags mit Android lesen

Sind Sie neugierig, was NFC ist und wie es in Ihre eigenen Android-Anwendungen integriert werden kann? In diesem Lernprogramm werden Sie schnell mit dem Thema vertraut gemacht, bevor Sie mit dem Erstellen einer einfachen NFC-Reader-App beginnen!


Was ist NFC??

NFC ist die Abkürzung für Near Field Communication. Es ist der internationale Standard für den kontaktlosen Datenaustausch. Im Gegensatz zu vielen anderen Technologien wie Wireless LAN und Bluetooth beträgt die maximale Entfernung von zwei Geräten 10 cm. Die Entwicklung des Standards begann im Jahr 2002 von NXP Semiconductors und Sony. Das NFC-Forum, ein Konsortium aus über 170 Unternehmen und Mitgliedern, darunter Mastercard, NXP, Nokia, Samsung, Intel und Google, entwickelt seit 2004 neue Spezifikationen.

Es gibt verschiedene Möglichkeiten für die Verwendung von NFC mit mobilen Geräten. B. papierlose Tickets, Zugangskontrollen, bargeldlose Zahlungen und Autoschlüssel. Mit Hilfe von NFC-Tags können Sie Ihr Telefon steuern und Einstellungen ändern. Daten können einfach ausgetauscht werden, indem zwei Geräte nebeneinander gehalten werden.

In diesem Lernprogramm möchte ich erklären, wie NFC mit dem Android SDK implementiert wird, welche Fallstricke bestehen und was zu beachten ist. Wir werden Schritt für Schritt eine App erstellen, die den Inhalt von NFC-Tags lesen kann, die NDEF unterstützen.


NFC-Technologien

Es gibt verschiedene NFC-Tags, die mit einem Smartphone gelesen werden können. Das Spektrum reicht von einfachen Aufklebern und Schlüsselringen bis hin zu komplexen Karten mit integrierter kryptografischer Hardware. Tags unterscheiden sich auch in ihrer Chiptechnologie. Das wichtigste ist NDEF, das von den meisten Tags unterstützt wird. Darüber hinaus sollte Mifare erwähnt werden, da es sich um die weltweit am häufigsten eingesetzte Technologie für kontaktlose Chips handelt. Einige Tags können gelesen und geschrieben werden, während andere schreibgeschützt oder verschlüsselt sind.

In diesem Lernprogramm wird nur das NFC-Datenaustauschformat (NDEF) beschrieben.


NFC-Unterstützung in einer App hinzufügen

Wir beginnen mit einem neuen Projekt und einer leeren Aktivität. Es ist wichtig, eine Mindest-SDK-Version von Level 10 auszuwählen, da NFC nur nach Android 2.3.3 unterstützt wird. Denken Sie daran, Ihren eigenen Paketnamen zu wählen. Ich habe gewählt net.vrallev.android.nfc.demo, weil vrallev.net die Domain meiner Website ist und der andere Teil sich auf das Thema dieser Anwendung bezieht.

 

Das von Eclipse generierte Standardlayout reicht für uns fast aus. Ich habe der TextView nur eine ID hinzugefügt und den Text geändert.

 

Um Zugriff auf die NFC-Hardware zu erhalten, müssen Sie die Genehmigung im Manifest beantragen. Wenn die App ohne NFC nicht funktioniert, können Sie die Bedingung mithilfe des Tags "use-feature" angeben. Wenn NFC erforderlich ist, kann die App nicht auf Geräten ohne installiert werden. Google Play zeigt Ihre App nur Benutzern an, die ein NFC-Gerät besitzen.

  

Die MainActivity sollte nur aus der onCreate () -Methode bestehen. Sie können mit der Hardware über die NfcAdapter-Klasse interagieren. Es ist wichtig herauszufinden, ob der NfcAdapter NULL ist. In diesem Fall unterstützt das Android-Gerät NFC nicht.

 Paket net.vrallev.android.nfc.demo; import android.app.Activity; import android.nfc.NfcAdapter; import android.os.Bundle; import android.widget.TextView; import android.widget.Toast; / ** * Aktivität zum Lesen von Daten aus einem NDEF-Tag. * * @author Ralf Wondratschek * * / public class MainActivity erweitert Aktivität public static final String TAG = "NfcDemo"; private TextView mTextView; privater 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) // Hier stoppen, wir benötigen auf jeden Fall NFC Toast.makeText ("Dieses Gerät unterstützt NFC nicht.", Toast.LENGTH_LONG) .show (); Fertig(); Rückkehr;  if (! mNfcAdapter.isEnabled ()) mTextView.setText ("NFC ist deaktiviert.");  else mTextView.setText (R.String.explanation);  handleIntent (getIntent ());  private void handleIntent (Absichtsabsicht) // TODO: handle Intent

Wenn wir unsere App jetzt starten, sehen wir den Text, ob NFC aktiviert oder deaktiviert ist.

So filtern Sie nach NFC-Tags

Wir haben unsere Beispiel-App und möchten eine Benachrichtigung vom System erhalten, wenn wir ein NFC-Tag an das Gerät anschließen. Wie üblich verwendet Android sein Intent-System, um Tags für die Apps bereitzustellen. Wenn mehrere Apps mit der Absicht umgehen können, wird die Aktivitätsauswahl angezeigt und der Benutzer kann entscheiden, welche App geöffnet wird. Das Öffnen von URLs oder das Teilen von Informationen wird auf dieselbe Weise behandelt.


NFC Intent Filter

Es gibt drei verschiedene Filter für Tags:

  1. ACTION_NDEF_DISCOVERED
  2. ACTION_TECH_DISCOVERED
  3. ACTION_TAG_DISCOVERED

Die Liste ist von der höchsten bis zur niedrigsten Priorität sortiert.

Was passiert nun, wenn ein Tag am Smartphone angebracht ist? Wenn das System ein Tag mit NDEF-Unterstützung erkennt, wird ein Intent ausgelöst. Ein ACTION_TECH_DISCOVERED Intent wird ausgelöst, wenn keine Aktivität von einer App für den NDEF-Intent registriert ist oder wenn der Tag NDEF nicht unterstützt. Wenn wieder keine App für den Intent gefunden wird oder die Chip-Technologie nicht erkannt werden konnte, dann a ACTION_TAG_DISCOVERED Absicht wird ausgelöst. Die folgende Grafik zeigt den Vorgang:


Zusammenfassend bedeutet dies, dass jede App nach dem Intent mit der höchsten Priorität filtern muss. In unserem Fall ist dies die Absicht von NDEF. Wir implementieren die ACTION_TECH_DISCOVERED Sie möchten zunächst den Unterschied zwischen den Prioritäten hervorheben.


Tech entdeckte Absicht

Wir müssen die Technologie angeben, an der wir interessiert sind. Zu diesem Zweck erstellen wir einen Unterordner mit dem Namen xml in dem res Mappe. In diesem Ordner erstellen wir die Datei nfc_tech_filter.xml, in denen wir die Technologien angeben.

    android.nfc.tech.Ndef    

Nun müssen wir im Manifest einen IntentFilter erstellen, und die App wird gestartet, wenn wir ein Tag anhängen.

           

Wenn keine andere App für diese Absicht registriert ist, wird unsere Aktivität sofort gestartet. Auf meinem Gerät werden jedoch andere Apps installiert, sodass die Aktivitätsauswahl angezeigt wird.



NDEF hat die Absicht entdeckt

Wie bereits erwähnt, hat der Tech Discovered Intent die zweithöchste Priorität. Da unsere App jedoch nur NDEF unterstützt, können wir stattdessen den NDEF Discovered Intent verwenden, der eine höhere Priorität hat. Wir können die Technologieliste wieder löschen und den IntentFilter durch den folgenden ersetzen.

     

Wenn wir das Tag jetzt anhängen, wird die App wie zuvor gestartet. Es gibt jedoch einen Unterschied für mich. Die Aktivitätsauswahl wird nicht angezeigt und die App wird sofort gestartet, da der NDEF-Intent eine höhere Priorität hat und die anderen Apps nur für die niedrigeren Prioritäten registriert sind. Genau das wollen wir.


Vordergrund-Versand

Beachten Sie, dass ein Problem bestehen bleibt. Wenn unsere App bereits geöffnet ist und wir das Tag erneut anfügen, wird die App ein zweites Mal geöffnet, anstatt das Tag direkt zuzustellen. Dies ist nicht unser beabsichtigtes Verhalten. Sie können das Problem umgehen, indem Sie einen Vordergrund-Dispatch verwenden.

Anstatt dass das System die Absicht verteilt hat, können Sie Ihre Aktivität registrieren, um das Tag direkt zu erhalten. Dies ist wichtig für einen bestimmten Workflow, bei dem es nicht sinnvoll ist, eine andere App zu öffnen.

Ich habe die Erklärungen an den entsprechenden Stellen in den Code eingefügt.

 Paket net.vrallev.android.nfc.demo; import android.app.Activity; import android.app.PendingIntent; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentFilter.MalformedMimeTypeException; import android.nfc.NfcAdapter; import android.os.Bundle; import android.widget.TextView; import android.widget.Toast; / ** * Aktivität zum Lesen von Daten aus einem NDEF-Tag. * * @author Ralf Wondratschek * * / public class MainActivity erweitert Aktivität public static final String MIME_TEXT_PLAIN = "text / plain"; public static final String TAG = "NfcDemo"; private TextView mTextView; privater 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) // Hier stoppen, wir benötigen auf jeden Fall NFC Toast.makeText ("Dieses Gerät unterstützt NFC nicht.", Toast.LENGTH_LONG) .show (); Fertig(); Rückkehr;  if (! mNfcAdapter.isEnabled ()) mTextView.setText ("NFC ist deaktiviert.");  else mTextView.setText (R.String.explanation);  handleIntent (getIntent ());  @Override protected void onResume () super.onResume (); / ** * Es ist wichtig, dass die Aktivität im Vordergrund steht (wieder aufgenommen). Andernfalls wird eine IllegalStateException ausgelöst. * / setupForegroundDispatch (this, mNfcAdapter);  @Override protected void onPause () / ** * Rufe dies vor onPause auf, andernfalls wird auch eine IllegalArgumentException ausgelöst. * / stopForegroundDispatch (this, mNfcAdapter); super.onPause ();  @Override protected void onNewIntent (Intent Intent) / ** * Diese Methode wird aufgerufen, wenn ein neuer Intent mit der aktuellen Aktivitätsinstanz verknüpft wird. * Anstatt eine neue Aktivität zu erstellen, wird onNewIntent aufgerufen. Weitere Informationen finden Sie in der Dokumentation *. * * In unserem Fall wird diese Methode aufgerufen, wenn der Benutzer ein Tag an das Gerät anfügt. * / handleIntent (Absicht);  private void handleIntent (Absichtsabsicht) // TODO: handle Intent / ** * @param activity Die entsprechende @link-Aktivität, die die Vordergrundausgabe anfordert. * @param adapter Der @link NfcAdapter, der für die Vordergrundabfertigung verwendet wird. * / public static void setupForegroundDispatch (abschließende Activity-Aktivität, NfcAdapter-Adapter) intent.setFlags (Intent.FLAG_ACTIVITY_SINGLE_TOP); final PendingIntent pendingIntent = PendingIntent.getActivity (activity.getApplicationContext (), 0, Absicht, 0); IntentFilter [] Filter = neuer IntentFilter [1]; String [] [] techList = neuer String [] [] ; // Beachten Sie, dass dies der gleiche Filter ist wie in unserem Manifest. filters [0] = new IntentFilter (); filters [0] .addAction (NfcAdapter.ACTION_NDEF_DISCOVERED); filters [0] .addCategory (Intent.CATEGORY_DEFAULT); try filters [0] .addDataType (MIME_TEXT_PLAIN);  catch (MalformedMimeTypeException e) Neue RuntimeException werfen ("Überprüfen Sie Ihren Mimetyp.");  adapter.enableForegroundDispatch (Aktivität, pendingIntent, Filter, TechList);  / ** * @param activity Die entsprechende @link BaseActivity -Anforderung, die Vordergrundabgabe zu stoppen. * @param adapter Der @link NfcAdapter, der für die Vordergrundabfertigung verwendet wird. * / public static void stopForegroundDispatch (letzte Aktivitätsaktivität, NfcAdapter-Adapter) adapter.disableForegroundDispatch (activity); 

Wenn Sie nun ein Tag anhängen und unsere App bereits geöffnet ist, wird onNewIntent aufgerufen, und es wird keine neue Aktivität erstellt.


Daten aus einem NDEF-Tag lesen

Der letzte Schritt ist das Lesen der Daten aus dem Tag. Die Erläuterungen werden erneut an den entsprechenden Stellen im Code eingefügt. Die NdefReaderTask ist eine private innere Klasse.

 Paket net.vrallev.android.nfc.demo; import java.io.UnsupportedEncodingException; import java.util.Arrays; import android.app.Activity; import 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; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import android.widget.Toast; / * *… Andere Codeteile * / private void handleIntent (Absichtsabsicht) 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); new NdefReaderTask (). execute (tag);  else Log.d (TAG, "Falscher Mime-Typ:" + Typ);  else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals (action)) // Falls das Tech Discovered Intent-Tag noch verwendet wird tag = intent.getParcelableExtra (NfcAdapter.EXTRA_TAG); String [] techList = tag.getTechList (); Zeichenfolge searchTech = Ndef.class.getName (); for (String tech: techList) if (gesuchteTech.equals (tech)) neue NdefReaderTask (). execute (tag); brechen; 
 / ** * Hintergrundaufgabe zum Lesen der Daten. Blockieren Sie den UI-Thread nicht während des Lesens. * * @author Ralf Wondratschek * * / private Klasse NdefReaderTask erweitert AsyncTask @Override protected String doInBackground (Tag… params) Tag tag = params [0]; Ndef ndef = Ndef.get (Tag); if (ndef == null) // NDEF wird von diesem Tag nicht unterstützt. null zurückgeben;  NdefMessage ndefMessage = ndef.getCachedNdefMessage (); NdefRecord [] records = ndefMessage.getRecords (); for (NdefRecord ndefRecord: records) if (ndefRecord.getTnf () == NdefRecord.TNF_WELL_KNOWN && Arrays.equals (ndefRecord.getType (), NdefRecord.RTD_TEXT)) try return readText ()  catch (UnsupportedEncodingException e) Log.e (TAG, "Unsupported Encoding", e);  NULL zurückgeben;  private String readText (NdefRecord-Datensatz) wirft UnsupportedEncodingException / * * Weitere Informationen finden Sie in der NFC-Forumspezifikation für "Textdatentyp-Definition" unter 3.2.1. * http://www.nfc-forum.org/specs/ * bit_6 ist für die spätere Verwendung reserviert und muss 0 sein. * bit_5… 0 Länge des IANA-Sprachcodes * / byte [] payload = record.getPayload (); // Holen Sie sich den Text Encoding String textEncoding = ((payload [0] & 128) == 0)? "UTF-8": "UTF-16"; // Den Sprachcode abrufen int languageCodeLength = payload [0] & 0063; // String languageCode = new String (Nutzlast, 1, languageCodeLength, "US-ASCII"); // z.B. "de" // Holen Sie sich den Text und geben Sie den neuen String zurück (payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);  @Override protected void onPostExecute (String result) if (result! = Null) mTextView.setText ("Read content:" + result); 

Die App liest den Inhalt jetzt erfolgreich.



Nützliche Apps

Um zu prüfen, ob Daten richtig gelesen und geschrieben werden, benutze ich persönlich folgende Apps:

  • NFC TagInfo vom NFC Research Lab zum Lesen von Daten
  • TagInfo von NXP SEMICONDUCTORS zum Lesen von Daten
  • TagWriter von NXP SEMICONDUCTORS zum Schreiben von Daten

Fazit

In diesem Tutorial habe ich Ihnen gezeigt, wie die Daten eines NDEF-Tags extrahiert werden können. Sie können das Beispiel auf andere Mime-Typen und Chip-Technologien erweitern. Eine Funktion zum Schreiben von Daten wäre ebenfalls nützlich. Der erste Schritt zur Arbeit mit NFC wurde gemacht. Das Android SDK bietet jedoch viel mehr Möglichkeiten, beispielsweise einen einfachen Datenaustausch (auch als "Android Beam" bezeichnet)..

Wenn Sie Ihre Android-Entwicklung weiterentwickeln möchten, sehen Sie sich die zahlreichen nützlichen Android-App-Vorlagen auf Envato Market an. Oder stellen Sie einen Android-Entwickler in Envato Studio ein.


Über den Autor

Ralf Wondratschek ist ein Informatikstudent aus Deutschland. Neben seinem Studium arbeitet Ralf freiberuflich im Bereich Mobile Computing. In den letzten Jahren hat er mit Java, XML, HTML, JSP, JSF, Eclipse, Google App Engine und natürlich Android gearbeitet. Er hat bisher zwei Android-Apps veröffentlicht, die hier zu finden sind.

Mehr über das Werk des Autors erfahren Sie auf seiner Homepage vrallev.net.


Quellen

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