Mit NFC-Geräten in Chrome für Android interagieren

Es ist jetzt möglich, in NFC-Tags zu lesen und zu schreiben.

François Beaufort
François Beaufort

Was ist Web-NFC?

NFC steht für „Near Field Communications“, eine Technologie für kurze Reichweite mit 13,56 MHz.Sie ermöglicht die Kommunikation zwischen Geräten in einer Entfernung von weniger als 10 cm und einer Übertragungsrate von bis zu 424 kbit/s.

Web-NFC bietet Websites die Möglichkeit, NFC-Tags zu lesen und zu schreiben, wenn sie sich in unmittelbarer Nähe zum Gerät des Nutzers befinden (in der Regel 5–10 cm, 2–4 Zoll). Der aktuelle Bereich ist auf das NFC Data Exchange Format (NDEF) beschränkt. Dieses einfache binäre Nachrichtenformat funktioniert mit verschiedenen Tag-Formaten.

Smartphone schaltet ein NFC-Tag zum Austausch von Daten ein
Diagramm eines NFC-Vorgangs

Empfohlene Anwendungsfälle

Web-NFC ist auf NDEF beschränkt, da die Sicherheitseigenschaften des Lesens und Schreibens von NDEF-Daten einfacher quantifizierbar sind. Low-Level-E/A-Vorgänge (z.B. ISO-DEP, NFC-A/B, NFC-F), der Peer-to-Peer-Kommunikationsmodus und die Host-based Card Emulation (HCE) werden nicht unterstützt.

Beispiele für Websites, die Web-NFC verwenden können:

  • Museen und Kunstgalerien können zusätzliche Informationen zu einer Ausstellung anzeigen, wenn der Nutzer sein Gerät an eine NFC-Karte in der Nähe der Ausstellung hält.
  • Websites zur Inventarverwaltung können Daten in das NFC-Tag eines Containers lesen oder in das Tag schreiben, um Informationen über seinen Inhalt zu aktualisieren.
  • Konferenzwebsites können damit NFC-Abzeichen während der Veranstaltung scannen und dafür sorgen, dass sie gesperrt sind, um weitere Änderungen an den auf ihnen geschriebenen Informationen zu verhindern.
  • Websites können damit die anfänglichen Secrets teilen, die für Szenarien der Geräte- oder Dienstbereitstellung erforderlich sind, und auch Konfigurationsdaten im Betriebsmodus bereitstellen.
Smartphone scannt mehrere NFC-Tags
Abbildung zur NFC-Inventarverwaltung

Aktueller Status

Step Status
1. Erklärende Erklärung erstellen Abschließen
2. Ersten Entwurf der Spezifikation erstellen Abschließen
3. Feedback einholen und Design iterieren Abschließen
4. Ursprungstest Abschließen
5. Starten Abschließen

Web-NFC verwenden

Funktionserkennung

Die Funktionserkennung für Hardware unterscheidet sich von dem, was Sie wahrscheinlich gewohnt sind. Wenn NDEFReader vorhanden ist, erkennen Sie, dass der Browser Web-NFC unterstützt, aber nicht, ob die erforderliche Hardware vorhanden ist. Insbesondere, wenn die Hardware fehlt, wird das von bestimmten Aufrufen zurückgegebene Versprechen abgelehnt. Wenn ich NDEFReader beschreibe, gebe ich nähere Einzelheiten an.

if ('NDEFReader' in window) { /* Scan and write NFC tags */ }

Terminologie

Ein NFC-Tag ist ein passives NFC-Gerät, das durch magnetische Induktion betrieben wird, wenn sich ein aktives NFC-Gerät (z. B. ein Smartphone) in der Nähe befindet. NFC-Tags gibt es in vielen Formen und Formen, z. B. Aufkleber, Kreditkarten, Handgelenke und mehr.

Foto eines transparenten NFC-Tags
Ein transparentes NFC-Tag

Das NDEFReader-Objekt ist der Einstiegspunkt in Web-NFC, das die Funktionen zum Vorbereiten von Lese- und/oder Schreibaktionen zur Verfügung stellt, die ausgeführt werden, wenn sich ein NDEF-Tag in der Nähe befindet. NDEF in NDEFReader steht für NFC Data Exchange Format, ein einfaches Binärnachrichtenformat, das vom NFC-Forum standardisiert wurde.

Das NDEFReader-Objekt dient dazu, eingehende NDEF-Nachrichten von NFC-Tags zu verarbeiten und NDEF-Nachrichten in NFC-Tags in Reichweite zu schreiben.

Ein NFC-Tag, das NDEF unterstützt, ist wie eine Haftnotiz. Jeder kann sie lesen, und wenn er nicht schreibgeschützt ist, kann jeder darin schreiben. Sie enthält eine einzelne NDEF-Nachricht, die einen oder mehrere NDEF-Einträge enthält. Jeder NDEF-Eintrag ist eine binäre Struktur, die eine Datennutzlast und zugehörige Typinformationen enthält. Web NFC unterstützt die folgenden standardisierten Eintragstypen des NFC-Forums: leer, Text, URL, Smartposter, MIME-Typ, absolute URL, externer Typ, unbekannt und lokaler Typ.

Diagramm einer NDEF-Nachricht
Diagramm einer NDEF-Nachricht

NFC-Tags scannen

Zum Scannen von NFC-Tags müssen Sie zuerst ein neues NDEFReader-Objekt instanziieren. Durch das Aufrufen von scan() wird ein Promise zurückgegeben. Der Nutzer wird möglicherweise aufgefordert, zuvor Zugriff zu gewähren. Das Promise wird aufgelöst, wenn die folgenden Bedingungen erfüllt sind:

  • Sie wurde nur als Reaktion auf eine Nutzergeste aufgerufen, z. B. eine Touch-Geste oder ein Mausklick.
  • Der Nutzer hat der Website die Interaktion mit NFC-Geräten erlaubt.
  • Das Smartphone des Nutzers unterstützt NFC.
  • Der Nutzer hat NFC auf seinem Smartphone aktiviert.

Nachdem das Promise aufgelöst wurde, sind eingehende NDEF-Nachrichten durch Abonnieren von reading-Ereignissen über einen Event-Listener verfügbar. Sie sollten auch readingerror-Ereignisse abonnieren, um benachrichtigt zu werden, wenn sich inkompatible NFC-Tags in der Nähe befinden.

const ndef = new NDEFReader();
ndef.scan().then(() => {
  console.log("Scan started successfully.");
  ndef.onreadingerror = () => {
    console.log("Cannot read data from the NFC tag. Try another one?");
  };
  ndef.onreading = event => {
    console.log("NDEF message read.");
  };
}).catch(error => {
  console.log(`Error! Scan failed to start: ${error}.`);
});

Wenn sich ein NFC-Tag in der Nähe befindet, wird ein NDEFReadingEvent-Ereignis ausgelöst. Es enthält zwei eindeutige Eigenschaften:

  • serialNumber steht für die Seriennummer des Geräts (z. B.00-11-22-33-44-55-66) oder ist ein leerer String, wenn keine vorhanden ist.
  • message steht für die im NFC-Tag gespeicherte NDEF-Nachricht.

Zum Lesen des Inhalts der NDEF-Nachricht führen Sie message.records durch und verarbeiten die data-Mitglieder entsprechend anhand ihrer recordType. Das data-Mitglied wird als DataView bereitgestellt, da es die Verarbeitung von Fällen erlaubt, in denen Daten in UTF-16 codiert sind.

ndef.onreading = event => {
  const message = event.message;
  for (const record of message.records) {
    console.log("Record type:  " + record.recordType);
    console.log("MIME type:    " + record.mediaType);
    console.log("Record id:    " + record.id);
    switch (record.recordType) {
      case "text":
        // TODO: Read text record with record data, lang, and encoding.
        break;
      case "url":
        // TODO: Read URL record with record data.
        break;
      default:
        // TODO: Handle other records with record data.
    }
  }
};

NFC-Tags schreiben

Zum Schreiben von NFC-Tags müssen Sie zuerst ein neues NDEFReader-Objekt instanziieren. Der Aufruf von write() gibt ein Promise zurück. Falls der Zugriff zuvor noch nicht gewährt wurde, wird der Nutzer möglicherweise aufgefordert, ihn zu verwenden. An diesem Punkt ist eine NDEF-Nachricht „vorbereitet“ und das Versprechen wird aufgelöst, wenn die folgenden Bedingungen erfüllt sind:

  • Sie wurde nur als Reaktion auf eine Nutzergeste aufgerufen, z. B. eine Touch-Geste oder ein Mausklick.
  • Der Nutzer hat der Website die Interaktion mit NFC-Geräten erlaubt.
  • Das Smartphone des Nutzers unterstützt NFC.
  • Der Nutzer hat NFC auf seinem Smartphone aktiviert.
  • Der Nutzer hat auf ein NFC-Tag getippt und eine NDEF-Nachricht wurde geschrieben.

Um Text in ein NFC-Tag zu schreiben, übergeben Sie einen String an die Methode write().

const ndef = new NDEFReader();
ndef.write(
  "Hello World"
).then(() => {
  console.log("Message written.");
}).catch(error => {
  console.log(`Write failed :-( try again: ${error}.`);
});

Wenn Sie einen URL-Eintrag in ein NFC-Tag schreiben möchten, übergeben Sie ein Wörterbuch, das eine NDEF-Nachricht darstellt, an write(). Im folgenden Beispiel ist die NDEF-Nachricht ein Wörterbuch mit einem records-Schlüssel. Sein Wert ist ein Array von Datensätzen – in diesem Fall ein URL-Eintrag, der als Objekt definiert ist, wobei der recordType-Schlüssel auf "url" und ein data-Schlüssel auf den URL-String festgelegt ist.

const ndef = new NDEFReader();
ndef.write({
  records: [{ recordType: "url", data: "https://w3c.github.io/web-nfc/" }]
}).then(() => {
  console.log("Message written.");
}).catch(error => {
  console.log(`Write failed :-( try again: ${error}.`);
});

Es ist auch möglich, mehrere Datensätze in ein NFC-Tag zu schreiben.

const ndef = new NDEFReader();
ndef.write({ records: [
    { recordType: "url", data: "https://w3c.github.io/web-nfc/" },
    { recordType: "url", data: "https://web.dev/nfc/" }
]}).then(() => {
  console.log("Message written.");
}).catch(error => {
  console.log(`Write failed :-( try again: ${error}.`);
});

Wenn das NFC-Tag eine NDEF-Nachricht enthält, die nicht überschrieben werden soll, setzen Sie das Attribut overwrite in den Optionen, die an die Methode write() übergeben werden, auf false. In diesem Fall wird das zurückgegebene Promise abgelehnt, wenn eine NDEF-Nachricht bereits im NFC-Tag gespeichert ist.

const ndef = new NDEFReader();
ndef.write("Writing data on an empty NFC tag is fun!", { overwrite: false })
.then(() => {
  console.log("Message written.");
}).catch(error => {
  console.log(`Write failed :-( try again: ${error}.`);
});

NFC-Tags schreibgeschützt machen

Um zu verhindern, dass böswillige Nutzer den Inhalt eines NFC-Tags überschreiben, können Sie NFC-Tags dauerhaft schreibgeschützt machen. Dieser Vorgang ist nur in eine Richtung möglich und kann nicht rückgängig gemacht werden. Sobald ein NFC-Tag schreibgeschützt ist, kann es nicht mehr darauf geschrieben werden.

Um NFC-Tags schreibgeschützt zu machen, instanziieren Sie zuerst ein neues NDEFReader-Objekt. Der Aufruf von makeReadOnly() gibt ein Promise zurück. Falls der Zugriff zuvor noch nicht gewährt wurde, wird der Nutzer möglicherweise aufgefordert, ihn zu verwenden. Das Promise wird aufgelöst, wenn die folgenden Bedingungen erfüllt sind:

  • Sie wurde nur als Reaktion auf eine Nutzergeste aufgerufen, z. B. eine Touch-Geste oder ein Mausklick.
  • Der Nutzer hat der Website die Interaktion mit NFC-Geräten erlaubt.
  • Das Smartphone des Nutzers unterstützt NFC.
  • Der Nutzer hat NFC auf seinem Smartphone aktiviert.
  • Der Nutzer hat auf ein NFC-Tag getippt und das NFC-Tag wurde schreibgeschützt.
const ndef = new NDEFReader();
ndef.makeReadOnly()
.then(() => {
  console.log("NFC tag has been made permanently read-only.");
}).catch(error => {
  console.log(`Operation failed: ${error}`);
});

Im Folgenden wird beschrieben, wie Sie ein NFC-Tag dauerhaft schreibgeschützt machen, nachdem Sie darauf geschrieben haben.

const ndef = new NDEFReader();
try {
  await ndef.write("Hello world");
  console.log("Message written.");
  await ndef.makeReadOnly();
  console.log("NFC tag has been made permanently read-only after writing to it.");
} catch (error) {
  console.log(`Operation failed: ${error}`);
}

Da makeReadOnly() unter Android ab Chrome 100 verfügbar ist, prüfen Sie folgendermaßen, ob diese Funktion unterstützt wird:

if ("NDEFReader" in window && "makeReadOnly" in NDEFReader.prototype) {
  // makeReadOnly() is supported.
}

Sicherheit und Berechtigungen

Das Chrome-Team hat Web-NFC anhand der unter Zugriff auf leistungsstarke Webplattformfunktionen steuern definierten Grundprinzipien wie Nutzersteuerung, Transparenz und Ergonomie entwickelt und implementiert.

Da NFC die Domain der Informationen erweitert, die potenziell schädlichen Websites zur Verfügung stehen, ist die Verfügbarkeit von NFC eingeschränkt, um die Erkennung und Kontrolle der Nutzung von NFC für Nutzer zu maximieren.

Screenshot einer Web-NFC-Aufforderung auf einer Website
Web-NFC-Nutzeraufforderung

Web-NFC ist nur für Frames der obersten Ebene und sichere Browserkontexte (nur HTTPS) verfügbar. Der Ursprung muss zuerst die Berechtigung "nfc" anfordern, wenn eine Nutzergeste (z. B. ein Klick auf eine Schaltfläche) ausgeführt wird. Die Methoden NDEFReader scan(), write() und makeReadOnly() lösen eine Nutzeraufforderung aus, wenn zuvor kein Zugriff gewährt wurde.

  document.querySelector("#scanButton").onclick = async () => {
    const ndef = new NDEFReader();
    // Prompt user to allow website to interact with NFC devices.
    await ndef.scan();
    ndef.onreading = event => {
      // TODO: Handle incoming NDEF messages.
    };
  };

Die Kombination aus einer vom Nutzer initiierten Berechtigungsaufforderung und einer realen, physischen Bewegung, bei der das Gerät über ein Ziel-NFC-Tag geführt wird, spiegelt das Auswahlmuster der anderen Datei- und Gerätezugriffs-APIs wider.

Zum Ausführen eines Scans oder Schreibens muss die Webseite sichtbar sein, wenn der Nutzer ein NFC-Tag mit seinem Gerät berührt. Der Browser weist auf haptisches Feedback hin. Der Zugriff auf das NFC-Funkgerät wird blockiert, wenn das Display ausgeschaltet oder das Gerät gesperrt ist. Bei nicht sichtbaren Webseiten wird der Empfang und das Senden von NFC-Inhalten angehalten und fortgesetzt, wenn eine Webseite wieder sichtbar wird.

Mithilfe der Page visibility API lässt sich verfolgen, wann sich die Sichtbarkeit von Dokumenten ändert.

document.onvisibilitychange = event => {
  if (document.hidden) {
    // All NFC operations are automatically suspended when document is hidden.
  } else {
    // All NFC operations are resumed, if needed.
  }
};

Kochbuch

Hier sind einige Codebeispiele für den Einstieg.

Berechtigungsprüfung

Mit der Permissions API kann geprüft werden, ob die Berechtigung "nfc" gewährt wurde. In diesem Beispiel wird gezeigt, wie NFC-Tags ohne Nutzerinteraktion gescannt werden, wenn zuvor Zugriff gewährt wurde. Andernfalls wird eine Schaltfläche angezeigt. Beachten Sie, dass der gleiche Mechanismus zum Schreiben von NFC-Tags funktioniert, wie er dieselbe Berechtigung im Hintergrund verwendet.

const ndef = new NDEFReader();

async function startScanning() {
  await ndef.scan();
  ndef.onreading = event => {
    /* handle NDEF messages */
  };
}

const nfcPermissionStatus = await navigator.permissions.query({ name: "nfc" });
if (nfcPermissionStatus.state === "granted") {
  // NFC access was previously granted, so we can start NFC scanning now.
  startScanning();
} else {
  // Show a "scan" button.
  document.querySelector("#scanButton").style.display = "block";
  document.querySelector("#scanButton").onclick = event => {
    // Prompt user to allow UA to send and receive info when they tap NFC devices.
    startScanning();
  };
}

NFC-Vorgänge abbrechen

Mit der Primitive AbortController lassen sich NFC-Vorgänge ganz einfach abbrechen. Das folgende Beispiel zeigt, wie Sie den signal einer AbortController über die Optionen der NDEFReader-Methoden scan(), makeReadOnly() und write() übergeben und beide NFC-Vorgänge gleichzeitig abbrechen.

const abortController = new AbortController();
abortController.signal.onabort = event => {
  // All NFC operations have been aborted.
};

const ndef = new NDEFReader();
await ndef.scan({ signal: abortController.signal });

await ndef.write("Hello world", { signal: abortController.signal });
await ndef.makeReadOnly({ signal: abortController.signal });

document.querySelector("#abortButton").onclick = event => {
  abortController.abort();
};

Lesen nach Schreiben

Wenn Sie write() und dann scan() mit der Primitive AbortController verwenden, kann ein NFC-Tag gelesen werden, nachdem eine Nachricht darauf geschrieben wurde. Das folgende Beispiel zeigt, wie Sie eine Textnachricht an ein NFC-Tag schreiben und die neue Nachricht im NFC-Tag lesen. Der Scanvorgang wird nach drei Sekunden beendet.

// Waiting for user to tap NFC tag to write to it...
const ndef = new NDEFReader();
await ndef.write("Hello world");
// Success! Message has been written.

// Now scanning for 3 seconds...
const abortController = new AbortController();
await ndef.scan({ signal: abortController.signal });
const message = await new Promise((resolve) => {
  ndef.onreading = (event) => resolve(event.message);
});
// Success! Message has been read.

await new Promise((r) => setTimeout(r, 3000));
abortController.abort();
// Scanning is now stopped.

Textdatensatz lesen und schreiben

Der Texteintrag data kann mit einem TextDecoder decodiert werden, das mit dem Attribut encoding des Eintrags instanziiert wird. Die Sprache des Texteintrags ist über die Eigenschaft lang verfügbar.

function readTextRecord(record) {
  console.assert(record.recordType === "text");
  const textDecoder = new TextDecoder(record.encoding);
  console.log(`Text: ${textDecoder.decode(record.data)} (${record.lang})`);
}

Übergeben Sie einen String an die NDEFReader-Methode write(), um einen einfachen Texteintrag zu schreiben.

const ndef = new NDEFReader();
await ndef.write("Hello World");

Texteinträge sind standardmäßig UTF-8 und gehen von der Sprache des aktuellen Dokuments aus. Beide Attribute (encoding und lang) können jedoch mit der vollständigen Syntax zum Erstellen eines benutzerdefinierten NDEF-Eintrags angegeben werden.

function a2utf16(string) {
  let result = new Uint16Array(string.length);
  for (let i = 0; i < string.length; i++) {
    result[i] = string.codePointAt(i);
  }
  return result;
}

const textRecord = {
  recordType: "text",
  lang: "fr",
  encoding: "utf-16",
  data: a2utf16("Bonjour, François !")
};

const ndef = new NDEFReader();
await ndef.write({ records: [textRecord] });

URL-Eintrag lesen und schreiben

Verwenden Sie TextDecoder, um data des Eintrags zu decodieren.

function readUrlRecord(record) {
  console.assert(record.recordType === "url");
  const textDecoder = new TextDecoder();
  console.log(`URL: ${textDecoder.decode(record.data)}`);
}

Wenn Sie einen URL-Eintrag schreiben möchten, übergeben Sie ein NDEF-Nachrichtenwörterbuch an die NDEFReader-Methode write(). Der in der NDEF-Nachricht enthaltene URL-Eintrag ist als Objekt definiert, bei dem ein recordType-Schlüssel auf "url" und ein data-Schlüssel auf den URL-String festgelegt ist.

const urlRecord = {
  recordType: "url",
  data:"https://w3c.github.io/web-nfc/"
};

const ndef = new NDEFReader();
await ndef.write({ records: [urlRecord] });

MIME-Typ-Eintrag lesen und schreiben

Das Attribut mediaType eines MIME-Typ-Eintrags stellt den MIME-Typ der Nutzlast des NDEF-Eintrags dar, damit data ordnungsgemäß decodiert werden kann. Verwenden Sie beispielsweise JSON.parse, um JSON-Text zu decodieren, und ein Bildelement, um Bilddaten zu decodieren.

function readMimeRecord(record) {
  console.assert(record.recordType === "mime");
  if (record.mediaType === "application/json") {
    const textDecoder = new TextDecoder();
    console.log(`JSON: ${JSON.parse(decoder.decode(record.data))}`);
  }
  else if (record.mediaType.startsWith('image/')) {
    const blob = new Blob([record.data], { type: record.mediaType });
    const img = new Image();
    img.src = URL.createObjectURL(blob);
    document.body.appendChild(img);
  }
  else {
    // TODO: Handle other MIME types.
  }
}

Wenn Sie einen MIME-Typ-Eintrag schreiben möchten, übergeben Sie ein NDEF-Nachrichtenwörterbuch an die NDEFReader-Methode write(). Der in der NDEF-Nachricht enthaltene MIME-Typ-Eintrag ist definiert als ein Objekt mit einem recordType-Schlüssel, der auf "mime" gesetzt ist, einem mediaType-Schlüssel, der auf den tatsächlichen MIME-Typ des Inhalts festgelegt ist, und einem data-Schlüssel, der auf ein Objekt festgelegt ist, das entweder ein ArrayBuffer sein kann oder eine Ansicht für ein ArrayBuffer (z.B. Uint8Array, DataView) bietet.

const encoder = new TextEncoder();
const data = {
  firstname: "François",
  lastname: "Beaufort"
};
const jsonRecord = {
  recordType: "mime",
  mediaType: "application/json",
  data: encoder.encode(JSON.stringify(data))
};

const imageRecord = {
  recordType: "mime",
  mediaType: "image/png",
  data: await (await fetch("icon1.png")).arrayBuffer()
};

const ndef = new NDEFReader();
await ndef.write({ records: [jsonRecord, imageRecord] });

Absolute URL-Einträge lesen und schreiben

Der absolute URL-Eintrag data kann mit einem einfachen TextDecoder decodiert werden.

function readAbsoluteUrlRecord(record) {
  console.assert(record.recordType === "absolute-url");
  const textDecoder = new TextDecoder();
  console.log(`Absolute URL: ${textDecoder.decode(record.data)}`);
}

Wenn Sie einen absoluten URL-Eintrag schreiben möchten, übergeben Sie ein NDEF-Nachrichtenwörterbuch an die NDEFReader-Methode write(). Der in der NDEF-Nachricht enthaltene absolute URL-Eintrag ist als Objekt mit einem recordType-Schlüssel auf "absolute-url" und einem data-Schlüssel auf den URL-String definiert.

const absoluteUrlRecord = {
  recordType: "absolute-url",
  data:"https://w3c.github.io/web-nfc/"
};

const ndef = new NDEFReader();
await ndef.write({ records: [absoluteUrlRecord] });

Intelligente Posterdaten lesen und schreiben

Ein intelligenter Postereintrag, der in Zeitschriftenwerbung, Flyern, Billboards usw. verwendet wird, beschreibt einige Webinhalte als NDEF-Eintrag, der eine NDEF-Nachricht als Nutzlast enthält. Rufen Sie record.toRecords() auf, um data in eine Liste von Einträgen zu transformieren, die im Smart Poster-Eintrag enthalten sind. Es sollte einen URL-Eintrag, einen Texteintrag für den Titel, einen MIME-Typ-Eintrag für das Bild und einige benutzerdefinierte lokale Datensätze wie ":t", ":act" und ":s" für den Typ, die Aktion und die Größe des Eintrags für das intelligente Poster enthalten.

Einträge vom lokalen Typ sind nur innerhalb des lokalen Kontexts des enthaltenden NDEF-Eintrags eindeutig. Verwenden Sie sie, wenn die Bedeutung der Typen außerhalb des lokalen Kontexts des enthaltenen Eintrags keine Rolle spielt und die Speichernutzung eine harte Einschränkung darstellt. Namen lokaler Datensätze beginnen in Web-NFC immer mit : (z.B. ":t", ":s", ":act"). Dadurch wird beispielsweise ein Texteintrag von einem lokalen Texteintrag unterschieden.

function readSmartPosterRecord(smartPosterRecord) {
  console.assert(record.recordType === "smart-poster");
  let action, text, url;

  for (const record of smartPosterRecord.toRecords()) {
    if (record.recordType == "text") {
      const decoder = new TextDecoder(record.encoding);
      text = decoder.decode(record.data);
    } else if (record.recordType == "url") {
      const decoder = new TextDecoder();
      url = decoder.decode(record.data);
    } else if (record.recordType == ":act") {
      action = record.data.getUint8(0);
    } else {
      // TODO: Handle other type of records such as `:t`, `:s`.
    }
  }

  switch (action) {
    case 0:
      // Do the action
      break;
    case 1:
      // Save for later
      break;
    case 2:
      // Open for editing
      break;
  }
}

Wenn Sie einen Eintrag für ein intelligentes Poster schreiben möchten, übergeben Sie eine NDEF-Nachricht an die NDEFReader-Methode write(). Der in der NDEF-Nachricht enthaltene Smart-Poster-Eintrag ist als Objekt mit einem recordType-Schlüssel definiert, der auf "smart-poster" gesetzt ist, und einem data-Schlüssel, der auf ein Objekt gesetzt ist, das (wieder) eine NDEF-Nachricht im Smart-Poster-Eintrag darstellt.

const encoder = new TextEncoder();
const smartPosterRecord = {
  recordType: "smart-poster",
  data: {
    records: [
      {
        recordType: "url", // URL record for smart poster content
        data: "https://my.org/content/19911"
      },
      {
        recordType: "text", // title record for smart poster content
        data: "Funny dance"
      },
      {
        recordType: ":t", // type record, a local type to smart poster
        data: encoder.encode("image/gif") // MIME type of smart poster content
      },
      {
        recordType: ":s", // size record, a local type to smart poster
        data: new Uint32Array([4096]) // byte size of smart poster content
      },
      {
        recordType: ":act", // action record, a local type to smart poster
        // do the action, in this case open in the browser
        data: new Uint8Array([0])
      },
      {
        recordType: "mime", // icon record, a MIME type record
        mediaType: "image/png",
        data: await (await fetch("icon1.png")).arrayBuffer()
      },
      {
        recordType: "mime", // another icon record
        mediaType: "image/jpg",
        data: await (await fetch("icon2.jpg")).arrayBuffer()
      }
    ]
  }
};

const ndef = new NDEFReader();
await ndef.write({ records: [smartPosterRecord] });

Externen Eintrag lesen und schreiben

Verwenden Sie Datensätze des externen Typs, um anwendungsdefinierte Datensätze zu erstellen. Diese können eine NDEF-Nachricht als Nutzlast enthalten, auf die mit toRecords() zugegriffen werden kann. Der Name enthält den Domainnamen der ausstellenden Organisation, einen Doppelpunkt und einen Typnamen, der mindestens ein Zeichen lang ist, z. B. "example.com:foo".

function readExternalTypeRecord(externalTypeRecord) {
  for (const record of externalTypeRecord.toRecords()) {
    if (record.recordType == "text") {
      const decoder = new TextDecoder(record.encoding);
      console.log(`Text: ${textDecoder.decode(record.data)} (${record.lang})`);
    } else if (record.recordType == "url") {
      const decoder = new TextDecoder();
      console.log(`URL: ${decoder.decode(record.data)}`);
    } else {
      // TODO: Handle other type of records.
    }
  }
}

Wenn Sie einen Eintrag eines externen Typs schreiben möchten, übergeben Sie ein NDEF-Nachrichtenwörterbuch an die NDEFReader-Methode write(). Der in der NDEF-Nachricht enthaltene Eintrag eines externen Typs ist als Objekt mit einem recordType-Schlüssel definiert, der auf den Namen des externen Typs festgelegt ist, und einem data-Schlüssel, der auf ein Objekt festgelegt ist, das eine NDEF-Nachricht darstellt, die im Eintrag des externen Typs enthalten ist. Der data-Schlüssel kann auch ein ArrayBuffer sein oder eine Ansicht für ein ArrayBuffer bereitstellen (z.B. Uint8Array, DataView).

const externalTypeRecord = {
  recordType: "example.game:a",
  data: {
    records: [
      {
        recordType: "url",
        data: "https://example.game/42"
      },
      {
        recordType: "text",
        data: "Game context given here"
      },
      {
        recordType: "mime",
        mediaType: "image/png",
        data: await (await fetch("image.png")).arrayBuffer()
      }
    ]
  }
};

const ndef = new NDEFReader();
ndef.write({ records: [externalTypeRecord] });

Leeren Eintrag lesen und schreiben

Ein leerer Datensatz hat keine Nutzlast.

Wenn Sie einen leeren Eintrag schreiben möchten, übergeben Sie ein NDEF-Nachrichtenwörterbuch an die NDEFReader-Methode write(). Der leere Eintrag in der NDEF-Nachricht ist als Objekt definiert, dessen recordType-Schlüssel auf "empty" gesetzt ist.

const emptyRecord = {
  recordType: "empty"
};

const ndef = new NDEFReader();
await ndef.write({ records: [emptyRecord] });

Unterstützte Browser

Web NFC ist unter Android in Chrome 89 verfügbar.

Entwicklertipps

Hier ist eine Liste von Dingen, die ich zu Beginn meiner Arbeit mit Web NFC gewusst hätte:

  • Android verarbeitet NFC-Tags auf Betriebssystemebene, bevor Web NFC funktionsfähig ist.
  • Ein NFC-Symbol finden Sie auf material.io.
  • Verwenden Sie den NDEF-Eintrag id, um einen Eintrag bei Bedarf einfach zu identifizieren.
  • Ein unformatiertes NFC-Tag, das NDEF unterstützt, enthält einen einzelnen Eintrag des leeren Typs.
  • Das Schreiben eines Android-Anwendungseintrags ist einfach, wie unten gezeigt.
const encoder = new TextEncoder();
const aarRecord = {
  recordType: "android.com:pkg",
  data: encoder.encode("com.example.myapp")
};

const ndef = new NDEFReader();
await ndef.write({ records: [aarRecord] });

Demos

Sehen Sie sich das offizielle Beispiel und einige coole Web-NFC-Demos an:

Demo von Web-NFC-Karten auf dem Chrome Dev Summit 2019

Feedback

Die Web NFC Community Group und das Chrome-Team würden gerne Ihre Meinung zu Web NFC erfahren.

Informationen zum API-Design

Gibt es etwas an der API, das nicht wie erwartet funktioniert? Oder fehlen Methoden oder Eigenschaften, die Sie zur Implementierung Ihrer Idee benötigen?

Melden Sie ein Spezifikationsproblem im Web NFC GitHub-Repository oder fügen Sie Ihre Gedanken zu einem bestehenden Problem hinzu.

Problem mit der Implementierung melden

Haben Sie einen Fehler bei der Implementierung in Chrome gefunden? Oder unterscheidet sich die Implementierung von der Spezifikation?

Melde einen Fehler unter https://new.crbug.com. Gib so viele Details wie möglich an, stelle eine einfache Anleitung zum Reproduzieren des Fehlers bereit und setze Komponenten auf Blink>NFC. Mit Glitch lassen sich schnelle und einfache Reproduktionen teilen.

Support zeigen

Möchten Sie Web-NFC verwenden? Ihre öffentliche Unterstützung hilft dem Chrome-Team, Funktionen zu priorisieren und anderen Browseranbietern zu zeigen, wie wichtig es ist, sie zu unterstützen.

Sende einen Tweet mit dem Hashtag #WebNFC an @ChromiumDev und teile uns mit, wo und wie du es verwendest.

Nützliche Links

Danksagungen

Vielen Dank an die Mitarbeiter bei Intel für die Implementierung von Web-NFC. Für Google Chrome ist eine Community aus Committern erforderlich, die das Chromium-Projekt gemeinsam voranbringen. Nicht jeder Chromium-Committer ist Google-Mitarbeiter, und diese Mitwirkende verdienen eine besondere Anerkennung!