Signatur
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 einPromise<void>zurück. Gefundene Tags lösen das Ereignisreadingaus.write(message, options): schreibt eine NDEF-Nachricht (String,ArrayBuffer,DataViewoder ein Objekt mitrecords) 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(TypNDEFReadingEventmitserialNumberundmessage) undreadingerror. Beide lassen sich mitaddEventListener()oder überonreadingbzw.onreadingerrorabonnieren.
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
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}`);
}
});
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);
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 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}`);
}
});
// 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
NotAllowedErrorabgelehnt. Den Status der Berechtigung liest man mitnavigator.permissions.query({ name: 'nfc' }). scan()undwrite()reagieren gleichzeitig auf dasselbe Tag. Wer schreiben will, ohne dassreading-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
readingerroraus. - Sicherheit: Daten von NFC-Tags sind nicht vertrauenswürdig. URLs und Texte vor der Verwendung prüfen, niemals ungefiltert per
innerHTMLeinfügen (XSS) und nicht automatisch öffnen. DieserialNumbereignet sich nicht als sicheres Merkmal zur Authentifizierung, weil sie gefälscht werden kann.