Signatur
Beschreibung
Das reading-Ereignis der Schnittstelle NDEFReader wird jedes Mal ausgelöst, wenn ein kompatibles NFC-Gerät (z. B. ein NDEF-Tag oder ein anderes Smartphone) in den Lesebereich des Geräts gebracht wird und eine neue NDEF-Nachricht vorliegt. Voraussetzung ist, dass vorher NDEFReader.prototype.scan() aufgerufen und die Berechtigung erteilt wurde.
Der Handler erhält ein NDEFReadingEvent mit zwei wichtigen Eigenschaften: serialNumber (die Seriennummer des Tags als hexadezimaler String, z. B. "04:a2:3b:…") und message (ein NDEFMessage-Objekt mit einem Array records aus NDEFRecord-Einträgen). Jeder Datensatz hat einen recordType (z. B. "text", "url", "mime"), optional mediaType, encoding, lang sowie die eigentlichen Nutzdaten in data als DataView.
Man kann den Handler per addEventListener("reading", handler) oder über die Eigenschaft ndefReader.onreading = handler registrieren. Typische Einsatzzwecke sind Inventarverwaltung, Check-in-Systeme, Museumsführer oder das Auslesen von URLs und Texten aus Tags. Fehlerhafte oder nicht lesbare Tags lösen statt reading das Ereignis readingerror aus.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "reading". |
|
| $handler Pflicht | (event: NDEFReadingEvent) => void | Callback, der bei jedem gelesenen Tag aufgerufen wird. Erhält ein NDEFReadingEvent mit serialNumber und message. |
|
| $options | boolean|AddEventListenerOptions | false | Optionale Listener-Optionen wie once oder signal (zum Entfernen per AbortController). |
Rückgabewert
addEventListener gibt nichts zurück. Die Daten stehen im übergebenen NDEFReadingEvent zur Verfügung.Beispiele
Tags scannen und Text-/URL-Datensätze ausgeben
const startScan = async () => {
if (!('NDEFReader' in window)) {
console.log('Web NFC wird nicht unterstützt.');
return;
}
const reader = new NDEFReader();
await reader.scan(); // muss durch Nutzergeste ausgelöst werden
reader.addEventListener('reading', ({ serialNumber, message }) => {
console.log(`Tag erkannt: ${serialNumber}`);
for (const record of message.records) {
if (record.recordType === 'text') {
const decoder = new TextDecoder(record.encoding ?? 'utf-8');
console.log(`Text (${record.lang}): ${decoder.decode(record.data)}`);
} else if (record.recordType === 'url') {
console.log(`URL: ${new TextDecoder().decode(record.data)}`);
} else {
console.log(`Anderer Typ: ${record.recordType}`);
}
}
});
reader.addEventListener('readingerror', () => {
console.log('Tag konnte nicht gelesen werden.');
});
};
document.querySelector('#scan').addEventListener('click', startScan);
on-Property und Beenden des Scans per AbortController
const controller = new AbortController();
const reader = new NDEFReader();
document.querySelector('#scan').addEventListener('click', async () => {
try {
await reader.scan({ signal: controller.signal });
reader.onreading = (event) => {
console.log('Seriennummer:', event.serialNumber);
console.log('Anzahl Datensätze:', event.message.records.length);
};
} catch (err) {
console.log(`Scan fehlgeschlagen: ${err.name}`);
}
});
document.querySelector('#stop').addEventListener('click', () => {
controller.abort(); // beendet den Scan, keine weiteren reading-Events
reader.onreading = null;
});
Nur ein einziges Tag lesen (once) und JSON-MIME-Daten auswerten
const readOnce = async () => {
const reader = new NDEFReader();
const controller = new AbortController();
await reader.scan({ signal: controller.signal });
return new Promise((resolve) => {
reader.addEventListener('reading', ({ message }) => {
const record = message.records.find(
(r) => r.recordType === 'mime' && r.mediaType === 'application/json'
);
controller.abort();
resolve(record ? JSON.parse(new TextDecoder().decode(record.data)) : null);
}, { once: true });
});
};
document.querySelector('#scan').addEventListener('click', async () => {
const data = await readOnce();
console.log(data);
});
// Wichtig · Fallstricke
- Kompatibilität: Web NFC ist experimentell und derzeit nur in Chrome für Android (ab Version 89) verfügbar. Desktop-Browser, Firefox und Safari/iOS unterstützen die API nicht – immer per
'NDEFReader' in windowprüfen. - Sicherer Kontext & Nutzergeste: Die API funktioniert nur über HTTPS, nur im obersten Browsing-Kontext (nicht in iframes) und
scan()muss beim ersten Mal durch eine Nutzeraktion (z. B. Klick) ausgelöst werden, sonst wird einNotAllowedErrorgeworfen. - Listener vor dem Tag registrieren: Wird ein Tag gelesen, bevor ein
reading-Handler existiert, geht das Ereignis verloren. Handler am besten direkt nach (oder vor) dem Aufruf vonscan()setzen. - Die Ereignisse feuern nur, solange die Seite sichtbar ist und der Bildschirm entsperrt ist; beim Wechsel in den Hintergrund wird das Scannen pausiert.
- Das Ereignis kann bei gleichem Tag mehrfach feuern, wenn es erneut angenähert wird – ggf. per
serialNumberentprellen. - Sicherheit: Tag-Inhalte sind nicht vertrauenswürdige Eingaben. Gelesene Texte/URLs niemals ungeprüft per
innerHTMLeinfügen oder automatisch aufrufen (XSS, Phishing). DieserialNumberist nicht fälschungssicher und taugt nicht zur Authentifizierung. - Fehlerhafte Tags lösen
readingerrorstattreadingaus – diesen Fall immer mitbehandeln.