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

NFC-Tags können jetzt gelesen und beschrieben werden.

François Beaufort
François Beaufort

Was ist Web NFC?

NFC steht für Nahfeldkommunikation, eine drahtlose Technologie mit kurzer Reichweite, die bei 13,56 MHz arbeitet und die Kommunikation zwischen Geräten in einem Abstand von weniger als 10 cm und einer Übertragungsrate von bis zu 424 kbit/s ermöglicht.

Mit Web NFC können Websites NFC-Tags lesen und beschreiben, wenn sie sich in unmittelbarer Nähe des Geräts des Nutzers befinden (in der Regel 5–10 cm). Der aktuelle Umfang beschränkt sich auf das NFC-Datenaustauschformat (NDEF), ein einfaches binäres Nachrichtenformat, das für verschiedene Tag-Formate funktioniert.

Smartphone, das ein NFC-Tag mit Strom versorgt, um Daten auszutauschen
Diagramm eines NFC-Vorgangs

Empfohlene Anwendungsfälle

Web NFC ist auf NDEF beschränkt, da die Sicherheitseigenschaften des Lesens und Schreibens von NDEF-Daten leichter quantifizierbar sind. Low-Level-I/O-Vorgänge (z.B. ISO-DEP, NFC-A/B, NFC-F), der Peer-to-Peer-Kommunikationsmodus und die hostbasierte Kartenemulation (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 einem Ausstellungsstück anzeigen, wenn der Nutzer sein Gerät an eine NFC-Karte in der Nähe des Ausstellungsstücks hält.
  • Inventarverwaltungssysteme können Daten auf den NFC-Tag eines Containers lesen oder schreiben, um Informationen zu seinem Inhalt zu aktualisieren.
  • Konferenzveranstalter können damit NFC-Badges während der Veranstaltung scannen und sicherstellen, dass sie gesperrt sind, um weitere Änderungen an den darauf geschriebenen Informationen zu verhindern.
  • Websites können damit erste Secrets für die Bereitstellung von Geräten oder Diensten freigeben und Konfigurationsdaten im Betriebsmodus bereitstellen.
Smartphone scannt mehrere NFC-Tags
NFC-Bestandsverwaltung

Aktueller Status

Schritt Status
1. 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. Das Vorhandensein von NDEFReader gibt an, 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 Promise abgelehnt. Ich werde Details angeben, wenn ich NDEFReader beschreibe.

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

Terminologie

Ein NFC-Tag ist ein passives NFC-Gerät. Das bedeutet, dass es durch magnetische Induktion mit Strom versorgt wird, wenn sich ein aktives NFC-Gerät (z. B. ein Smartphone) in der Nähe befindet. NFC-Tags gibt es in vielen Formen, z. B. als Sticker, Kreditkarten oder Armbänder.

Foto eines transparenten NFC-Tags
Ein transparenter NFC-Tag

Das NDEFReader-Objekt ist der Einstiegspunkt in Web NFC, der Funktionen zum Vorbereiten von Lese- und/oder Schreibvorgängen bereitstellt, die ausgeführt werden, wenn sich ein NDEF-Tag in der Nähe befindet. Das NDEF in NDEFReader steht für NFC Data Exchange Format (NFC-Datenaustauschformat), ein schlankes binäres Nachrichtenformat, das vom NFC-Forum standardisiert wurde.

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

Ein NFC-Tag, das NDEF unterstützt, ist wie ein Post-it. Jeder kann sie lesen und, sofern sie nicht schreibgeschützt ist, auch bearbeiten. Sie enthält eine einzelne NDEF-Nachricht, die einen oder mehrere NDEF-Einträge kapselt. Jeder NDEF-Datensatz ist eine binäre Struktur, die eine Daten-Payload und zugehörige Typinformationen enthält. Web NFC unterstützt die folgenden vom NFC-Forum standardisierten Datensatztypen: „empty“, „text“, „URL“, „smart poster“, „MIME type“, „absolute URL“, „external type“, „unknown“ und „local type“.

Diagramm einer NDEF-Nachricht
Diagramm einer NDEF-Nachricht

NFC-Tags scannen

Um NFC-Tags zu scannen, müssen Sie zuerst ein neues NDEFReader-Objekt instanziieren. Der Aufruf von scan() gibt ein Promise zurück. Der Nutzer wird möglicherweise aufgefordert, den Zugriff zu gewähren, wenn dies nicht bereits geschehen ist. Das Promise wird aufgelöst, wenn alle folgenden Bedingungen erfüllt sind:

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

Sobald das Promise aufgelöst wurde, sind eingehende NDEF-Nachrichten verfügbar, indem Sie über einen Event-Listener reading-Ereignisse abonnieren. 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 spezifische Attribute:

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

Um den Inhalt der NDEF-Nachricht zu lesen, durchlaufen Sie message.records und verarbeiten Sie die data-Elemente entsprechend basierend auf ihrem recordType. Das data-Element wird als DataView verfügbar gemacht, da es die Verarbeitung von Fällen ermöglicht, 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

Um NFC-Tags zu schreiben, müssen Sie zuerst ein neues NDEFReader-Objekt instanziieren. Der Aufruf von write() gibt ein Promise zurück. Der Nutzer wird möglicherweise aufgefordert, den Zugriff zu gewähren, wenn er dies nicht bereits getan hat. An diesem Punkt wird eine NDEF-Nachricht „vorbereitet“ und das Promise wird aufgelöst, wenn alle folgenden Bedingungen erfüllt sind:

  • Sie wurde nur als Reaktion auf eine Nutzergeste wie eine Touch-Geste oder einen Mausklick aufgerufen.
  • Der Nutzer hat der Website erlaubt, mit NFC-Geräten zu interagieren.
  • Das Smartphone des Nutzers unterstützt NFC.
  • Der Nutzer hat NFC auf seinem Smartphone aktiviert.
  • Der Nutzer hat ein NFC-Tag berührt und eine NDEF-Nachricht wurde erfolgreich geschrieben.

Wenn Sie Text in ein NFC-Tag schreiben möchten, ü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-Datensatz in ein NFC-Tag schreiben möchten, übergeben Sie ein Dictionary, das eine NDEF-Nachricht darstellt, an write(). Im folgenden Beispiel ist die NDEF-Nachricht ein Dictionary mit dem Schlüssel records. Sein Wert ist ein Array von Datensätzen. In diesem Fall ist es ein URL-Datensatz, der als Objekt mit einem recordType-Schlüssel, der auf "url" festgelegt ist, und einem data-Schlüssel, der auf den URL-String festgelegt ist, definiert wird.

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 die overwrite-Eigenschaft in den an die write()-Methode übergebenen Optionen auf false. In diesem Fall wird das zurückgegebene Promise abgelehnt, wenn bereits eine NDEF-Nachricht 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 ein Einbahnprozess und kann nicht rückgängig gemacht werden. Sobald ein NFC-Tag schreibgeschützt ist, kann es nicht mehr beschrieben werden.

Um NFC-Tags schreibgeschützt zu machen, instanziieren Sie zuerst ein neues NDEFReader-Objekt. Der Aufruf von makeReadOnly() gibt ein Promise zurück. Der Nutzer wird möglicherweise aufgefordert, den Zugriff zu gewähren, wenn er dies nicht bereits getan hat. Das Promise wird aufgelöst, wenn alle folgenden Bedingungen erfüllt sind:

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

So machen Sie ein NFC-Tag nach dem Beschreiben dauerhaft schreibgeschützt.

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() in Chrome 100 oder höher für Android verfügbar ist, können Sie prüfen, ob diese Funktion mit Folgendem unterstützt wird:

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

Sicherheit und Berechtigungen

Das Chrome-Team hat Web NFC gemäß den in Controlling Access to Powerful Web Platform Features definierten Grundsätzen entwickelt und implementiert, darunter Nutzerkontrolle, Transparenz und Ergonomie.

Da NFC den Bereich der Informationen erweitert, die potenziell für schädliche Websites verfügbar sind, ist die Verfügbarkeit von NFC eingeschränkt, um das Bewusstsein der Nutzer für die Verwendung von NFC zu maximieren und ihnen mehr Kontrolle darüber zu geben.

Screenshot eines Web-NFC-Prompts auf einer Website
Web-NFC-Aufforderung

Web NFC ist nur für Frames der obersten Ebene und sichere Browserkontexte (nur HTTPS) verfügbar. Ursprünge müssen zuerst die "nfc"-Berechtigung anfordern, während eine Nutzeraktion (z. B. ein Klick auf eine Schaltfläche) verarbeitet wird. Die Methoden NDEFReader scan(), write() und makeReadOnly() lösen eine Nutzeraufforderung aus, wenn der Zugriff nicht zuvor 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 der physischen Bewegung des Geräts über ein NFC-Tag entspricht dem Auswahlmuster, das in den anderen APIs für den Datei- und Gerätezugriff verwendet wird.

Damit ein Scan oder Schreibvorgang ausgeführt werden kann, muss die Webseite sichtbar sein, wenn der Nutzer mit seinem Gerät ein NFC-Tag berührt. Der Browser verwendet haptisches Feedback, um einen Tippvorgang anzuzeigen. Der Zugriff auf das NFC-Funkmodul ist blockiert, wenn das Display ausgeschaltet oder das Gerät gesperrt ist. Bei nicht sichtbaren Webseiten werden der Empfang und das Senden von NFC-Inhalten unterbrochen und fortgesetzt, wenn eine Webseite wieder sichtbar wird.

Mithilfe der Page Visibility API lässt sich nachverfolgen, wann sich die Sichtbarkeit eines Dokuments ä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.

Berechtigung prüfen

Mit der Permissions API lässt sich prüfen, ob die Berechtigung "nfc" erteilt wurde. In diesem Beispiel wird gezeigt, wie NFC-Tags ohne Nutzerinteraktion gescannt werden, wenn der Zugriff zuvor gewährt wurde, oder wie andernfalls eine Schaltfläche angezeigt wird. Derselbe Mechanismus funktioniert auch für das Schreiben von NFC-Tags, da er dieselbe Berechtigung 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 dem AbortController-Primitive lassen sich NFC-Vorgänge ganz einfach abbrechen. Im folgenden Beispiel wird gezeigt, wie Sie die signal eines 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 dem AbortController-Primitive verwenden, können Sie ein NFC-Tag lesen, nachdem Sie eine Nachricht darauf geschrieben haben. Das folgende Beispiel zeigt, wie Sie eine SMS auf einen NFC-Tag schreiben und die neue Nachricht auf dem NFC-Tag lesen. Nach drei Sekunden wird der Scan 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.

TXT-Eintrag lesen und schreiben

Der Textdatensatz data kann mit einem TextDecoder decodiert werden, das mit dem Attribut encoding des Datensatzes instanziiert wird. Die Sprache des Textdatensatzes ist über das Attribut 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})`);
}

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

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

Texteinträge sind standardmäßig UTF-8-codiert und verwenden die Sprache des aktuellen Dokuments. Beide Eigenschaften (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-Datensatz lesen und schreiben

Verwenden Sie TextDecoder, um die data des Datensatzes zu decodieren.

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

Um einen URL-Eintrag zu schreiben, übergeben Sie ein NDEF-Nachrichtendictionary an die Methode write() von NDEFReader. Der in der NDEF-Nachricht enthaltene URL-Datensatz wird als Objekt mit einem recordType-Schlüssel definiert, der auf "url" gesetzt ist, und einem data-Schlüssel, der auf den URL-String gesetzt 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

Die Eigenschaft mediaType eines MIME-Typ-Datensatzes stellt den MIME-Typ der NDEF-Datensatznutzlast dar, damit data richtig decodiert werden kann. Verwenden Sie beispielsweise JSON.parse, um JSON-Text zu decodieren, und ein Image-Element, 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.
  }
}

Um einen MIME-Typ-Eintrag zu schreiben, übergeben Sie ein NDEF-Nachrichtendictionary an die NDEFReader-Methode write(). Der in der NDEF-Nachricht enthaltene MIME-Typ-Eintrag wird als Objekt mit dem Schlüssel recordType, der auf "mime" gesetzt ist, dem Schlüssel mediaType, der auf den tatsächlichen MIME-Typ des Inhalts gesetzt ist, und dem Schlüssel data, der auf ein Objekt gesetzt ist, das entweder ein ArrayBuffer ist oder eine Ansicht auf ein ArrayBuffer bietet (z.B. Uint8Array, DataView), definiert.

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] });

Einen Datensatz mit absoluter URL lesen und schreiben

Der Datensatz mit der absoluten URL 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-Nachrichtendictionary an die NDEFReader-Methode write(). Der in der NDEF-Nachricht enthaltene Datensatz mit der absoluten URL wird als Objekt mit einem recordType-Schlüssel definiert, der auf "absolute-url" festgelegt ist, und einem data-Schlüssel, der auf den URL-String festgelegt ist.

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

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

Einen Smart Poster-Datensatz lesen und schreiben

Ein Smartposter-Datensatz (für Zeitschriftenanzeigen, Flyer, Plakate usw.) beschreibt Web-Inhalte als NDEF-Datensatz, dessen Nutzlast eine NDEF-Nachricht ist. Rufen Sie record.toRecords() auf, um data in eine Liste von Datensätzen umzuwandeln, die im Smartposter-Datensatz enthalten sind. Er sollte einen URL-Eintrag, einen Texteintrag für den Titel, einen MIME-Typeintrag für das Bild und einige benutzerdefinierte lokale Typeinträge wie ":t", ":act" und ":s" für Typ, Aktion und Größe des Smart-Poster-Eintrags enthalten.

Lokale Typdatensätze sind nur im lokalen Kontext des enthaltenden NDEF-Datensatzes eindeutig. Verwenden Sie sie, wenn die Bedeutung der Typen außerhalb des lokalen Kontexts des enthaltenden Datensatzes keine Rolle spielt und die Speichernutzung eine wichtige Einschränkung darstellt. Namen von lokalen Typdatensätzen beginnen in Web NFC immer mit : (z.B. ":t", ":s", ":act"). So wird beispielsweise ein Textdatensatz von einem lokalen Typdatensatz 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;
  }
}

Um einen Smart Poster-Eintrag zu schreiben, übergeben Sie eine NDEF-Nachricht an die NDEFReader-Methode write(). Der im NDEF-Datensatz enthaltene Smartposter-Datensatz wird 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 (noch einmal) eine im Smartposter-Datensatz enthaltene NDEF-Nachricht 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 Typdatensatz lesen und schreiben

Verwenden Sie externe Typdatensätze, um anwendungsdefinierte Datensätze zu erstellen. Diese können eine NDEF-Nachricht als Nutzlast enthalten, auf die mit toRecords() zugegriffen werden kann. Ihr 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.
    }
  }
}

Um einen externen Typdatensatz zu schreiben, übergeben Sie ein NDEF-Nachrichtendictionary an die NDEFReader-Methode write(). Der im NDEF-Datensatz enthaltene externe Typ wird 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 im externen Typdatensatz enthaltene NDEF-Nachricht darstellt. Der Schlüssel data kann entweder ein ArrayBuffer sein oder eine Ansicht auf ein ArrayBuffer bieten (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 Datensatz lesen und schreiben

Ein leerer Datensatz hat keine Nutzlast.

Wenn Sie einen leeren Eintrag schreiben möchten, übergeben Sie ein NDEF-Nachrichtendictionary an die Methode NDEFReaderwrite(). Der leere Datensatz in der NDEF-Nachricht wird als Objekt mit dem auf "empty" gesetzten recordType-Schlüssel definiert.

const emptyRecord = {
  recordType: "empty"
};

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

Unterstützte Browser

Web NFC ist in Chrome 89 für Android verfügbar.

Tipps für Entwickler

Hier ist eine Liste mit Dingen, die ich gerne gewusst hätte, als ich mit Web NFC angefangen habe:

  • Android verarbeitet NFC-Tags auf Betriebssystemebene, bevor Web NFC aktiv ist.
  • Ein NFC-Symbol finden Sie auf material.io.
  • Verwenden Sie den NDEF-Eintrag id, um einen Eintrag bei Bedarf leicht zu identifizieren.
  • Ein unformatiertes NFC-Tag, das NDEF unterstützt, enthält einen einzelnen Datensatz des leeren Typs.
  • Wie unten gezeigt, ist es ganz einfach, einen Android-Anwendungsdatensatz zu erstellen.
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

Probieren Sie das offizielle Beispiel aus und sehen Sie sich einige coole Web NFC-Demos an:

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

Feedback

Die Web NFC Community Group und das Chrome-Team würden sich freuen, mehr über Ihre Gedanken und Erfahrungen mit Web NFC zu erfahren.

Informationen zum API-Design

Gibt es etwas an der API, das nicht wie erwartet funktioniert? Oder fehlen Methoden oder Properties, die Sie für die Umsetzung 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 in der Chrome-Implementierung gefunden? Oder weicht die Implementierung von der Spezifikation ab?

Melden Sie einen Fehler unter https://new.crbug.com. Geben Sie so viele Details wie möglich an, stellen Sie eine einfache Anleitung zum Reproduzieren des Fehlers bereit und legen Sie Components auf Blink>NFC fest.

Unterstützung zeigen

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

Senden Sie einen Tweet an @ChromiumDev mit dem Hashtag #WebNFC und teilen Sie uns mit, wo und wie Sie die Funktion verwenden.

Nützliche Links

Danksagungen

Vielen Dank an die Mitarbeiter von Intel für die Implementierung von Web NFC. Google Chrome ist auf eine Community von Committern angewiesen, die gemeinsam das Chromium-Projekt vorantreiben. Nicht jeder Chromium-Committer ist ein Google-Mitarbeiter. Diese Mitwirkenden verdienen besondere Anerkennung.