Start · Sprachen · JavaScript · Referenz · NDEFReader

NDEFReader

Schnittstelle

Die Schnittstelle <code>NDEFReader</code> der Web NFC API liest und schreibt NDEF-Nachrichten auf NFC-Tags in Reichweite, z. B. auf NFC-Aufkleber oder -Karten.

seit JavaScript Experimentell: Chrome für Android 89+ (kein Deskto Kategorie: webapi

Signatur

interface NDEFReader extends EventTarget

Beschreibung

NDEFReader ist der zentrale Einstiegspunkt der Web NFC API. Über ein Objekt dieser Schnittstelle kann eine Webseite NFC-Tags im NDEF-Format (NFC Data Exchange Format) lesen, beschreiben und dauerhaft schreibschützen. Typische Einsatzfälle sind Inventur und Lagerverwaltung, Check-ins bei Veranstaltungen, Museumsführer oder das Konfigurieren von Geräten per NFC-Aufkleber.

Die Schnittstelle erbt von EventTarget und hat folgende Bestandteile:

  • new NDEFReader(): erzeugt einen neuen Leser, der Argumente nicht benötigt.
  • scan(options): startet den Lesevorgang und gibt ein Promise<void> zurück. Gefundene Tags lösen das Ereignis reading aus.
  • write(message, options): schreibt eine NDEF-Nachricht (String, ArrayBuffer, DataView oder ein Objekt mit records) auf das nächste Tag, das in Reichweite kommt.
  • makeReadOnly(options): macht ein Tag dauerhaft schreibgeschützt. Das lässt sich nicht rückgängig machen.
  • Ereignisse reading (Typ NDEFReadingEvent mit serialNumber und message) und readingerror. Beide lassen sich mit addEventListener() oder über onreading bzw. onreadingerror abonnieren.

Alle Operationen brauchen einen sicheren Kontext (HTTPS), eine sichtbare Seite im Vordergrund und die Berechtigung "nfc". Der erste Aufruf von scan() oder write() muss durch eine Nutzeraktion wie einen Klick ausgelöst werden, damit der Browser um Erlaubnis fragen kann. Laufende Scans und Schreibvorgänge lassen sich mit einem AbortSignal abbrechen.

Parameter

Name Typ Default Beschreibung
$options.signal AbortSignal Optional für scan(), write() und makeReadOnly(). Damit wird der Vorgang abgebrochen, das Promise wird dann mit AbortError abgelehnt.
$message Pflicht string | ArrayBuffer | TypedArray | DataView | NDEFMessageInit Nur bei write(): die zu schreibenden Daten. Ein String wird als einzelner text-Record geschrieben. Für mehrere Records übergibt man { records: [...] } mit recordType, data, optional mediaType, lang und encoding.
$options.overwrite boolean true Nur bei write(): Bei false wird ein Tag, das schon NDEF-Daten enthält, nicht überschrieben. Das Promise wird dann abgelehnt.

Rückgabewert

Typ
NDEFReader
Beschreibung
Der Konstruktor liefert eine neue NDEFReader-Instanz. scan(), write() und makeReadOnly() geben jeweils ein Promise<void> zurück.

Beispiele

NFC-Tags scannen und Text-Records auslesen

const scanButton = document.querySelector('#scan');

scanButton.addEventListener('click', async () => {
  if (!('NDEFReader' in window)) {
    console.log('Web NFC wird nicht unterstützt.');
    return;
  }

  const reader = new NDEFReader();
  try {
    await reader.scan(); // löst beim ersten Mal die Berechtigungsabfrage aus
    console.log('Scan gestartet – Tag an das Gerät halten.');

    reader.addEventListener('readingerror', () => {
      console.log('Tag erkannt, aber nicht lesbar (kein NDEF?).');
    });

    reader.addEventListener('reading', ({ serialNumber, message }) => {
      console.log(`Seriennummer: ${serialNumber}`);
      for (const record of message.records) {
        if (record.recordType === 'text') {
          const decoder = new TextDecoder(record.encoding);
          console.log(`Text (${record.lang}): ${decoder.decode(record.data)}`);
        } else if (record.recordType === 'url') {
          console.log(`URL: ${new TextDecoder().decode(record.data)}`);
        }
      }
    });
  } catch (err) {
    console.log(`Fehler: ${err.name} – ${err.message}`);
  }
});
Scan gestartet – Tag an das Gerät halten. Seriennummer: 04:a2:5c:1a:7f:61:80 Text (de): Regal B-12

Mehrere Records auf ein Tag schreiben, ohne zu überschreiben

const writeTag = async () => {
  const reader = new NDEFReader();
  try {
    await reader.write(
      {
        records: [
          { recordType: 'text', data: 'Raum 204 – Besprechung', lang: 'de' },
          { recordType: 'url', data: 'https://example.com/raum/204' }
        ]
      },
      { overwrite: false }
    );
    console.log('Tag erfolgreich beschrieben.');
  } catch (err) {
    console.log(`Schreiben fehlgeschlagen: ${err.name}`);
  }
};

document.querySelector('#write').addEventListener('click', writeTag);
Tag erfolgreich beschrieben.

Scan mit AbortController nach Zeitlimit beenden

const scanWithTimeout = async (ms = 10000) => {
  const reader = new NDEFReader();
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), ms);

  controller.signal.addEventListener('abort', () => {
    console.log('Scan beendet.');
  });

  reader.onreading = (event) => {
    console.log(`Tag gelesen: ${event.serialNumber}`);
    clearTimeout(timer);
    controller.abort(); // nach dem ersten Treffer aufhören
  };

  await reader.scan({ signal: controller.signal });
};

document.querySelector('#scan').addEventListener('click', () => scanWithTimeout(5000));
Tag gelesen: 04:a2:5c:1a:7f:61:80 Scan beendet.

Tag dauerhaft schreibschützen

document.querySelector('#lock').addEventListener('click', async () => {
  const reader = new NDEFReader();
  try {
    await reader.makeReadOnly();
    console.log('Tag ist jetzt dauerhaft schreibgeschützt.');
  } catch (err) {
    console.log(`Nicht möglich: ${err.name}`);
  }
});
Tag ist jetzt dauerhaft schreibgeschützt.

// Wichtig · Fallstricke

Kompatibilität: Web NFC ist experimentell und funktioniert derzeit nur in Chrome für Android (ab Version 89) auf Geräten mit NFC-Hardware. Desktop-Browser, Firefox und Safari (auch unter iOS) unterstützen die API nicht. Prüfe deshalb immer vorher mit 'NDEFReader' in window.

  • Die API funktioniert nur in einem sicheren Kontext (HTTPS), nur im Hauptframe und nur, solange die Seite sichtbar ist. Wechselt der Nutzer den Tab, werden Scans angehalten.
  • Der erste Aufruf braucht eine Nutzeraktion. Ohne sie wird das Promise mit NotAllowedError abgelehnt. Den Status der Berechtigung liest man mit navigator.permissions.query({ name: 'nfc' }).
  • scan() und write() reagieren gleichzeitig auf dasselbe Tag. Wer schreiben will, ohne dass reading-Ereignisse stören, sollte den Scan vorher abbrechen oder die Ereignisse vorübergehend ignorieren.
  • makeReadOnly() lässt sich nicht rückgängig machen. Vor dem Aufruf unbedingt eine Bestätigung vom Nutzer einholen.
  • Es werden nur NDEF-Daten unterstützt. Low-Level-Zugriffe wie ISO-DEP, APDU oder MIFARE-Sektoren sind nicht möglich. Tags ohne NDEF lösen readingerror aus.
  • Sicherheit: Daten von NFC-Tags sind nicht vertrauenswürdig. URLs und Texte vor der Verwendung prüfen, niemals ungefiltert per innerHTML einfügen (XSS) und nicht automatisch öffnen. Die serialNumber eignet sich nicht als sicheres Merkmal zur Authentifizierung, weil sie gefälscht werden kann.