Erweiterte NFC – Übersicht

In diesem Dokument werden erweiterte NFC-Themen wie das Arbeiten mit verschiedenen Tag-Technologien, das Schreiben in NFC-Tags und die Weiterleitung im Vordergrund beschrieben, die es einer Anwendung im Vordergrund ermöglicht, Intents auch dann zu verarbeiten, wenn andere Anwendungen nach denselben filtern.

Mit unterstützten Tag-Technologien arbeiten

Bei der Arbeit mit NFC-Tags und Android-Geräten ist NDEF zum Lesen und Schreiben von Daten in Tags das Hauptformat. Wenn ein Gerät ein Tag mit NDEF-Daten scannt, unterstützt Android das Parsen der Nachricht und die Übermittlung der Nachricht in einem NdefMessage, sofern dies möglich ist. Es kann jedoch vorkommen, dass Sie ein Tag scannen, das keine NDEF-Daten enthält, oder wenn die NDEF-Daten keinem MIME-Typ oder -URI zugeordnet werden konnten. In diesen Fällen müssen Sie die Kommunikation direkt mit dem Tag öffnen und mit Ihrem eigenen Protokoll (in Rohbyte) lesen und schreiben. Android bietet allgemeine Unterstützung für diese Anwendungsfälle mit dem Paket android.nfc.tech, das in Tabelle 1 beschrieben wird. Sie können die Methode getTechList() verwenden, um die vom Tag unterstützten Technologien zu ermitteln und das entsprechende TagTechnology-Objekt mit einer der von android.nfc.tech bereitgestellten Klassen zu erstellen.

Tabelle 1 Unterstützte Tag-Technologien

Klasse Beschreibung
TagTechnology Die Schnittstelle, die alle Tag-Technologieklassen implementieren müssen.
NfcA Bietet Zugriff auf NFC-A-Eigenschaften (ISO 14443-3A) und auf E/A-Vorgänge.
NfcB Ermöglicht Zugriff auf NFC-B-Eigenschaften (ISO 14443-3B) und auf E/A-Vorgänge.
NfcF Bietet Zugriff auf NFC-F-Eigenschaften (JIS 6319-4) und E/A-Vorgänge.
NfcV Bietet Zugriff auf NFC-V-Eigenschaften (ISO 15693) und E/A-Vorgänge.
IsoDep Bietet Zugriff auf die Eigenschaften ISO-DEP (ISO 14443-4) und E/A-Vorgänge.
Ndef Bietet Zugriff auf NDEF-Daten und Vorgänge für NFC-Tags, die als NDEF formatiert wurden.
NdefFormatable Stellt Formatvorgänge für Tags bereit, die möglicherweise NDEF-formatierbar sind.

Die folgenden Tag-Technologien müssen von Android-Mobilgeräten nicht unterstützt werden.

Tabelle 2 Optionale unterstützte Tag-Technologien

Klasse Beschreibung
MifareClassic Bietet Zugriff auf MIFARE Classic-Attribute und E/A-Vorgänge, wenn dieses Android-Gerät MIFARE unterstützt.
MifareUltralight Bietet Zugriff auf MIFARE Ultralight-Eigenschaften und E/A-Vorgänge, sofern dieses Android-Gerät MIFARE unterstützt.

Mit Tag-Technologien und dem Intent ACTION_TECH_DISCOVERED arbeiten

Wenn ein Gerät ein Tag mit NDEF-Daten scannt, das aber keinem MIME oder URI zugeordnet werden konnte, versucht das System zur Tag-Weiterleitung, eine Aktivität mit dem Intent ACTION_TECH_DISCOVERED zu starten. Der ACTION_TECH_DISCOVERED wird auch verwendet, wenn ein Tag mit Nicht-NDEF-Daten gescannt wird. Mit diesem Fallback können Sie direkt mit den Daten im Tag arbeiten, wenn das Tag-Weiterleitungssystem diese nicht für Sie parsen konnte. Wenn Sie mit Tag-Technologien arbeiten, sind folgende grundlegende Schritte erforderlich:

  1. Filtern Sie nach einem ACTION_TECH_DISCOVERED-Intent, der die Tag-Technologien angibt, die Sie verarbeiten möchten. Weitere Informationen finden Sie unter Nach NFC-Intents filtern. Im Allgemeinen versucht das System zur Tag-Weiterleitung, einen ACTION_TECH_DISCOVERED-Intent zu starten, wenn eine NDEF-Nachricht keinem MIME-Typ oder URI zugeordnet werden kann oder das gescannte Tag keine NDEF-Daten enthält. Weitere Informationen dazu, wie dies bestimmt wird, finden Sie unter Tag Dispatch-System.
  2. Wenn die Anwendung den Intent empfängt, rufen Sie das Objekt Tag vom Intent ab:

    Kotlin

    var tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
    

    Java

    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    
  3. Rufen Sie eine Instanz eines TagTechnology ab, indem Sie eine der get-Factory-Methoden der Klassen im android.nfc.tech-Paket aufrufen. Sie können die unterstützten Technologien des Tags auflisten, indem Sie getTechList() aufrufen, bevor Sie eine get-Factory-Methode aufrufen. So rufen Sie beispielsweise eine Instanz von MifareUltralight aus einem Tag ab:

    Kotlin

    MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))
    

    Java

    MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
    

In Tags lesen und schreiben

Zum Lesen und Schreiben in ein NFC-Tag wird das Tag vom Intent abgerufen und die Kommunikation mit dem Tag gestartet. Sie müssen einen eigenen Protokollstack definieren, um Daten in das Tag zu lesen und in das Tag zu schreiben. Beachten Sie jedoch, dass Sie NDEF-Daten weiterhin lesen und schreiben können, wenn Sie direkt mit einem Tag arbeiten. Es liegt an Ihnen, wie Sie die Dinge strukturieren möchten. Das folgende Beispiel zeigt, wie Sie mit einem MIFARE-Ultralight-Tag arbeiten.

Kotlin

package com.example.android.nfc
import android.nfc.Tag
import android.nfc.tech.MifareUltralight
import java.io.IOException
import java.nio.charset.Charset

class MifareUltralightTagTester {

    fun writeTag(tag: Tag, tagText: String) {
        MifareUltralight.get(tag)?.use { ultralight ->
            ultralight.connect()
            Charset.forName("US-ASCII").also { usAscii ->
                ultralight.writePage(4, "abcd".toByteArray(usAscii))
                ultralight.writePage(5, "efgh".toByteArray(usAscii))
                ultralight.writePage(6, "ijkl".toByteArray(usAscii))
                ultralight.writePage(7, "mnop".toByteArray(usAscii))
            }
        }
    }

    fun readTag(tag: Tag): String? {
        return MifareUltralight.get(tag)?.use { mifare ->
            mifare.connect()
            val payload = mifare.readPages(4)
            String(payload, Charset.forName("US-ASCII"))
        }
    }
}

Java

package com.example.android.nfc;

import android.nfc.Tag;
import android.nfc.tech.MifareUltralight;
import android.util.Log;
import java.io.IOException;
import java.nio.charset.Charset;

public class MifareUltralightTagTester {

    private static final String TAG = MifareUltralightTagTester.class.getSimpleName();

    public void writeTag(Tag tag, String tagText) {
        MifareUltralight ultralight = MifareUltralight.get(tag);
        try {
            ultralight.connect();
            ultralight.writePage(4, "abcd".getBytes(Charset.forName("US-ASCII")));
            ultralight.writePage(5, "efgh".getBytes(Charset.forName("US-ASCII")));
            ultralight.writePage(6, "ijkl".getBytes(Charset.forName("US-ASCII")));
            ultralight.writePage(7, "mnop".getBytes(Charset.forName("US-ASCII")));
        } catch (IOException e) {
            Log.e(TAG, "IOException while writing MifareUltralight...", e);
        } finally {
            try {
                ultralight.close();
            } catch (IOException e) {
                Log.e(TAG, "IOException while closing MifareUltralight...", e);
            }
        }
    }

    public String readTag(Tag tag) {
        MifareUltralight mifare = MifareUltralight.get(tag);
        try {
            mifare.connect();
            byte[] payload = mifare.readPages(4);
            return new String(payload, Charset.forName("US-ASCII"));
        } catch (IOException e) {
            Log.e(TAG, "IOException while reading MifareUltralight message...", e);
        } finally {
            if (mifare != null) {
               try {
                   mifare.close();
               }
               catch (IOException e) {
                   Log.e(TAG, "Error closing tag...", e);
               }
            }
        }
        return null;
    }
}

Weiterleitungssystem im Vordergrund verwenden

Das Weiterleitungssystem im Vordergrund ermöglicht es einer Aktivität, einen Intent abzufangen und Priorität gegenüber anderen Aktivitäten zu beanspruchen, die denselben Intent verarbeiten. Für die Verwendung dieses Systems müssen einige Datenstrukturen konstruiert werden, damit das Android-System die entsprechenden Intents an Ihre Anwendung senden kann. So aktivieren Sie das Weiterleitungssystem im Vordergrund:

  1. Fügen Sie der Methode onCreate() Ihrer Aktivität den folgenden Code hinzu:
    1. Erstellen Sie ein änderbares PendingIntent-Objekt, damit das Android-System die Details des Tags beim Scannen in dieses Objekt übernehmen kann.

      Kotlin

      val intent = Intent(this, javaClass).apply {
          addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
      }
      var pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent,
              PendingIntent.FLAG_MUTABLE)
      

      Java

      PendingIntent pendingIntent = PendingIntent.getActivity(
          this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
          PendingIntent.FLAG_MUTABLE);
      
    2. Deklarieren Sie Intent-Filter für die Verarbeitung der Intents, die Sie abfangen möchten. Das Weiterleitungssystem im Vordergrund prüft die angegebenen Intent-Filter mit dem Intent, der empfangen wird, wenn das Gerät ein Tag scannt. Bei Übereinstimmung verarbeitet die Anwendung den Intent. Wenn sie nicht übereinstimmt, greift das Weiterleitungssystem im Vordergrund auf das Intent-Weiterleitungssystem zurück. Wenn Sie ein null-Array von Intent- und Technologiefiltern angeben, wird damit festgelegt, dass nach allen Tags gefiltert werden soll, die auf den TAG_DISCOVERED-Intent zurückgreifen. Mit dem folgenden Code-Snippet werden alle MIME-Typen für NDEF_DISCOVERED verarbeitet. Sie sollten nur solche verarbeiten, die Sie benötigen.

      Kotlin

      val ndef = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED).apply {
          try {
              addDataType("*/*")    /* Handles all MIME based dispatches.
                                       You should specify only the ones that you need. */
          } catch (e: IntentFilter.MalformedMimeTypeException) {
              throw RuntimeException("fail", e)
          }
      }
      
      intentFiltersArray = arrayOf(ndef)
      

      Java

      IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
          try {
              ndef.addDataType("*/*");    /* Handles all MIME based dispatches.
                                             You should specify only the ones that you need. */
          }
          catch (MalformedMimeTypeException e) {
              throw new RuntimeException("fail", e);
          }
         intentFiltersArray = new IntentFilter[] {ndef, };
      
    3. Richten Sie eine Reihe von Tag-Technologien ein, die von Ihrer Anwendung verarbeitet werden sollen. Rufen Sie die Methode Object.class.getName() auf, um die Klasse der Technologie zu ermitteln, die unterstützt werden soll.

      Kotlin

      techListsArray = arrayOf(arrayOf<String>(NfcF::class.java.name))
      

      Java

      techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
      
  2. Überschreiben Sie die folgenden Callbacks für den Aktivitätslebenszyklus und fügen Sie Logik hinzu, um die Weiterleitung im Vordergrund zu aktivieren und zu deaktivieren, wenn die Aktivität den Fokus verliert (onPause()) und wiedererlangt (onResume()). enableForegroundDispatch() muss aus dem Hauptthread aufgerufen werden, und nur, wenn die Aktivität im Vordergrund ausgeführt wird (der Aufruf in onResume() garantiert dies). Außerdem musst du den onNewIntent-Callback implementieren, um die Daten aus dem gescannten NFC-Tag zu verarbeiten.
  3. Kotlin

    public override fun onPause() {
        super.onPause()
        adapter.disableForegroundDispatch(this)
    }
    
    public override fun onResume() {
        super.onResume()
        adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray)
    }
    
    public override fun onNewIntent(intent: Intent) {
        val tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
        // do something with tagFromIntent
    }
    

    Java

    public void onPause() {
        super.onPause();
        adapter.disableForegroundDispatch(this);
    }
    
    public void onResume() {
        super.onResume();
        adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
    }
    
    public void onNewIntent(Intent intent) {
        Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        // do something with tagFromIntent
    }