Chrome for Android で NFC デバイスを操作する

NFC タグの読み取りと書き込みを行えるようになりました。

François Beaufort
François Beaufort

NFC は近距離無線通信の略です。近距離無線通信は 13.56 MHz で動作する短距離無線技術で、10 cm 以内の距離でデバイス間の通信を可能にし、最大 424 kbit/s の伝送速度を実現します。

ウェブ NFC を使用すると、サイトはユーザーのデバイスに近づいた NFC タグの読み取りと書き込みを行うことができます(通常は 5 ~ 10 cm)。現在のスコープは NFC Data Exchange Format(NDEF)に限定されています。NDEF は、さまざまなタグ形式で機能する軽量のバイナリ メッセージ形式です。

スマートフォンが NFC タグを電源に接続してデータを交換している
NFC オペレーションの図

推奨されるユースケース

NDEF データの読み取りと書き込みのセキュリティ特性をより簡単に定量化できるため、ウェブ NFC は NDEF に限定されています。低レベルの I/O オペレーション(ISO-DEP、NFC-A/B、NFC-F など)、ピアツーピア通信モード、ホストベースのカード エミュレーション(HCE)はサポートされていません。

Web NFC を使用する可能性のあるサイトの例としては、次のようなものがあります。

  • 美術館やアート ギャラリーでは、展示物の近くにある NFC カードにデバイスをタップすると、展示物に関する追加情報が表示されます。
  • 在庫管理サイトは、コンテナの NFC タグにデータを読み書きして、コンテナの内容に関する情報を更新できます。
  • 会議サイトでは、イベント中に NFC バッジをスキャンし、バッジに書き込まれた情報を変更できないようにロックできます。
  • サイトは、デバイスやサービスのプロビジョニング シナリオに必要な初期シークレットの共有や、運用モードでの構成データのデプロイに使用できます。
複数の NFC タグをスキャンしているスマートフォン
NFC 在庫管理の例

現在のステータス

ステップ ステータス
1. 説明を作成する 完了
2. 仕様の初期ドラフトを作成する 完了
3. フィードバックを収集してデザインを反復する 完了
4. オリジン トライアル 完了
5. リリース 完了

ウェブ NFC を使用する

機能検出

ハードウェアの機能検出は、なじみのあるものとは異なります。NDEFReader はブラウザがウェブ NFC をサポートしていることを示しますが、必要なハードウェアが存在するかどうかはわかりません。特に、ハードウェアが不足している場合、特定の呼び出しによって返される Promise は拒否されます。NDEFReader の説明で詳しく説明します。

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

用語

NFC タグはパッシブ NFC デバイスです。つまり、アクティブな NFC デバイス(スマートフォンなど)が近くにある場合に磁気誘導によって給電されます。NFC タグには、ステッカー、クレジット カード、リストバンドなど、さまざまな形状とデザインがあります。

透明な NFC タグの画像
透明な NFC タグ

NDEFReader オブジェクトは、NFC タグが近づいたときに実行される読み取り/書き込みアクションの準備機能を公開する、Web NFC のエントリ ポイントです。NDEFReaderNDEF は、NFC フォーラムで標準化された軽量なバイナリ メッセージ形式である NFC データ交換形式を表します。

NDEFReader オブジェクトは、NFC タグからの受信 NDEF メッセージに対してアクションを実行し、範囲内の NFC タグに NDEF メッセージを書き込むためのものです。

NDEF をサポートする NFC タグは、付箋のようなものです。誰でも読み取り可能で、読み取り専用でない限り、誰でも書き込み可能です。1 つ以上の NDEF レコードをカプセル化する単一の NDEF メッセージが含まれています。各 NDEF レコードは、データ ペイロードと関連するタイプ情報を含んだバイナリ構造です。Web NFC は、空、テキスト、URL、スマートポスター、MIME タイプ、絶対 URL、外部タイプ、不明、ローカルタイプの NFC フォーラム標準化されたレコードタイプをサポートしています。

NDEF メッセージの図
NDEF メッセージの図

NFC タグをスキャンする

NFC タグをスキャンするには、まず新しい NDEFReader オブジェクトをインスタンス化します。scan() を呼び出すと、Promise が返されます。アクセスが以前に許可されていない場合は、ユーザーにプロンプトが表示されることがあります。次の条件がすべて満たされると、Promise は解決します。

  • タップ操作やマウスクリックなどのユーザー操作に応じてのみ呼び出されていました。
  • ユーザーが、ウェブサイトが NFC デバイスを操作することを許可している。
  • お客様のスマートフォンが NFC に対応している。
  • お客様がスマートフォンで NFC を有効にしている。

プロミスが解決されると、イベント リスナーを介して reading イベントをサブスクライブすることで、受信した NDEF メッセージを利用できるようになります。また、互換性のない NFC タグが近くにあるときに通知を受け取るために、readingerror イベントをサブスクライブする必要があります。

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}.`);
});

NFC タグが近くにあると、NDEFReadingEvent イベントが発生します。これに固有の 2 つのプロパティがあります。

  • serialNumber は、デバイスのシリアル番号(00-11-22-33-44-55-66 など)を表します。取得できるものがない場合は空の文字列になります。
  • message は、NFC タグに保存されている NDEF メッセージを表します。

NDEF メッセージのコンテンツを読み取るには、message.records をループし、recordType に基づいて data メンバーを適切に処理します。data メンバーは DataView として公開されます。これは、データが UTF-16 でエンコードされているケースを処理できるためです。

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 タグに書き込む

NFC タグを書き込むには、まず新しい NDEFReader オブジェクトをインスタンス化します。write() を呼び出すと Promise が返されます。アクセス権が以前に付与されていない場合は、ユーザーにプロンプトが表示されることがあります。この時点で、NDEF メッセージが「準備」され、次の条件がすべて満たされると、Promise が解決します。

  • タップ操作やマウスクリックなどのユーザー操作に応じてのみ呼び出されていました。
  • ユーザーが、ウェブサイトが NFC デバイスを操作することを許可している。
  • お客様のスマートフォンが NFC に対応している。
  • ユーザーがスマートフォンで NFC を有効にしている。
  • ユーザーが NFC タグをタップし、NDEF メッセージが正常に書き込まれた。

NFC タグにテキストを書き込むには、write() メソッドに文字列を渡します。

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

URL レコードを NFC タグに書き込むには、NDEF メッセージを表す辞書を write() に渡します。次の例では、NDEF メッセージは records キーを持つ辞書です。その値はレコードの配列です。この場合は、recordType キーが "url" に設定され、data キーが URL 文字列に設定されたオブジェクトとして定義された URL レコードです。

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}.`);
});

複数のレコードを NFC タグに書き込むこともできます。

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}.`);
});

NFC タグに上書き対象ではない NDEF メッセージが含まれている場合は、write() メソッドに渡されるオプションで overwrite プロパティを false に設定します。その場合、NFC タグに NDEF メッセージがすでに保存されていると、返された Promise は拒否されます。

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 タグを読み取り専用にする

悪意のあるユーザーが NFC タグのコンテンツを上書きできないようにするには、NFC タグを永続的に読み取り専用にすることができます。このオペレーションは一方通行のプロセスであり、元に戻すことはできません。NFC タグを読み取り専用にすると、書き込みできなくなります。

NFC タグを読み取り専用にするには、まず新しい NDEFReader オブジェクトをインスタンス化します。makeReadOnly() を呼び出すと Promise が返されます。アクセス権が付与されていない場合は、ユーザーにメッセージが表示されることがあります。次の条件がすべて満たされた場合、Promise は解決されます。

  • タップ操作やマウスクリックなどのユーザー操作に応じてのみ呼び出されていました。
  • ユーザーが、ウェブサイトが NFC デバイスを操作することを許可している。
  • お客様のスマートフォンが NFC に対応している。
  • お客様がスマートフォンで NFC を有効にしている。
  • ユーザーが NFC タグをタップし、NFC タグが読み取り専用に正常に設定されました。
const ndef = new NDEFReader();
ndef.makeReadOnly()
.then(() => {
  console.log("NFC tag has been made permanently read-only.");
}).catch(error => {
  console.log(`Operation failed: ${error}`);
});

NFC タグに書き込んだ後、そのタグを読み取り専用にするには、次の手順を行います。

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

makeReadOnly() は Android 版 Chrome 100 以降で利用できる機能であるため、この機能が次の環境でサポートされているかどうかを確認します。

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

セキュリティと権限

Chrome チームは、強力なウェブ プラットフォーム機能へのアクセスを制御するで定義されているコア プリンシプル(ユーザー制御、透明性、人間工学など)を使用して、Web NFC を設計して実装しました。

NFC は、悪意のあるウェブサイトが利用できる情報のドメインを拡大するため、NFC の使用についてユーザーの認識と制御を最大限に高めるために、NFC の使用は制限されています。

ウェブサイトのウェブ NFC プロンプトのスクリーンショット
Web NFC ユーザー プロンプト

Web NFC は、トップレベルのフレームと安全なブラウジング コンテキスト(HTTPS のみ)でのみ使用できます。オリジンは、ユーザー ジェスチャー(ボタンのクリックなど)を処理する際に、まず "nfc"権限をリクエストする必要があります。NDEFReaderscan()write()makeReadOnly() の各メソッドは、アクセスが以前に許可されていない場合に、ユーザー プロンプトをトリガーします。

  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.
    };
  };

ユーザーが開始した権限プロンプトと、デバイスを対象の NFC タグに近づける実際の物理的な動きを組み合わせることで、他のファイルおよびデバイス アクセス API にある選択ツール パターンをミラーリングできます。

スキャンまたは書き込みを行うには、ユーザーがデバイスで NFC タグをタップしたときにウェブページが表示されている必要があります。ブラウザはハプティクス フィードバックを使用してタップを示します。ディスプレイがオフの場合や、デバイスがロックされている場合、NFC 無線へのアクセスはブロックされます。表示されていないウェブページでは、NFC コンテンツの受信とプッシュが一時停止され、ウェブページが再び表示されたときに再開されます。

Page Visibility API を使用すると、ドキュメントの公開設定が変更されたタイミングを追跡できます。

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

レシピ

以下に、すぐに利用できるコードサンプルを示します。

権限を確認する

Permissions API を使用すると、"nfc" 権限が付与されているかどうかを確認できます。この例では、以前にアクセス権が付与されている場合はユーザーの操作なしで NFC タグをスキャンし、そうでない場合はボタンを表示する方法を示します。内部で同じ権限を使用するため、NFC タグの書き込みにも同じメカニズムが機能します。

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 オペレーションを中止する

AbortController プリミティブを使用すると、NFC オペレーションを簡単に中止できます。次の例は、NDEFReader の scan()makeReadOnly()write() メソッドのオプションを使用して AbortControllersignal を渡し、両方の NFC オペレーションを同時に中止する方法を示しています。

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

書き込み後に読み取る

AbortController プリミティブで write()scan() を使用すると、メッセージの書き込み後に NFC タグを読み取ることができます。次の例は、テキスト メッセージを NFC タグに書き込み、NFC タグ内の新しいメッセージを読み取る方法を示しています。3 秒後にスキャンが停止します。

// 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.

テキスト レコードの読み取りと書き込み

テキスト レコード data は、レコード encoding プロパティでインスタンス化された TextDecoder でデコードできます。テキスト レコードの言語は、lang プロパティで確認できます。

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

シンプルなテキスト レコードを書き込むには、NDEFReader の write() メソッドに文字列を渡します。

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

テキスト レコードはデフォルトで UTF-8 で、現在のドキュメントの言語を前提としていますが、カスタム NDEF レコードを作成するための完全な構文を使用して、両方のプロパティ(encodinglang)を指定できます。

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 レコードの読み取りと書き込み

TextDecoder を使用して、レコードの data をデコードします。

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

URL レコードを書き込むには、NDEF メッセージ ディクショナリを NDEFReader の write() メソッドに渡します。NDEF メッセージに含まれる URL レコードは、recordType キーが "url" に、data キーが URL 文字列に設定されたオブジェクトとして定義されます。

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

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

MIME タイプ レコードの読み取りと書き込み

MIME タイプ レコードの mediaType プロパティは、data を適切にデコードできるように、NDEF レコード ペイロードの MIME タイプを表します。たとえば、JSON.parse を使用して JSON テキストをデコードし、Image 要素を使用して画像データをデコードします。

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.
  }
}

MIME タイプ レコードを書き込むには、NDEF メッセージ ディクショナリを NDEFReader の write() メソッドに渡します。NDEF メッセージに含まれる MIME タイプ レコードは、recordType キーが "mime" に設定され、mediaType キーがコンテンツの実際の MIME タイプに設定され、data キーが ArrayBuffer であるか、ArrayBuffer へのビューを提供するオブジェクト(Uint8ArrayDataView など)に設定されたオブジェクトとして定義されます。

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

絶対 URL レコードの読み取りと書き込み

絶対 URL レコード data は、単純な TextDecoder でデコードできます。

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

絶対 URL レコードを書き込むには、NDEF メッセージ ディクショナリを NDEFReader の write() メソッドに渡します。NDEF メッセージに含まれる絶対 URL レコードは、recordType キーが "absolute-url" に設定され、data キーが URL 文字列に設定されたオブジェクトとして定義されます。

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

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

スマート ポスター レコードの読み取りと書き込み

スマートポスター レコード(雑誌広告、チラシ、ビルボードなどで使用)は、ペイロードとして NDEF メッセージを含む NDEF レコードとしてウェブ コンテンツを記述します。record.toRecords() を呼び出して、data をスマート ポスター レコードに含まれるレコードのリストに変換します。URL レコード、タイトルのテキスト レコード、画像の MIME タイプ レコード、スマート ポスター レコードのタイプ、アクション、サイズのカスタム ローカル タイプ レコード":t"":act"":s" など)をそれぞれ含める必要があります。

ローカル型のレコードは、含まれる NDEF レコードのローカル コンテキスト内でのみ一意になります。型の意味は、包含レコードのローカル コンテキストの外部では重要ではなく、ストレージ使用量が厳しい制約である場合に使用します。Web NFC では、ローカルタイプのレコード名は常に : で始まります(例: ":t"":s"":act")。これは、テキスト レコードとローカルタイプのテキスト レコードを区別するためです。

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

スマートポスター レコードを書き込むには、NDEF メッセージを NDEFReader の write() メソッドに渡します。NDEF メッセージに含まれるスマートポスター レコードは、recordType キーが "smart-poster" に設定され、data キーがスマートポスター レコードに含まれる NDEF メッセージを表すオブジェクトに設定されたオブジェクトとして定義されます。

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

外部タイプのレコードの読み取りと書き込み

アプリケーション定義レコードを作成するには、外部タイプのレコードを使用します。これらには、toRecords() でアクセスできるペイロードとして NDEF メッセージが含まれている場合があります。名前には、発行元の組織のドメイン名、コロン、1 文字以上の型名(例: "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.
    }
  }
}

外部型のレコードを書き込むには、NDEF メッセージ ディクショナリを NDEFReader write() メソッドに渡します。NDEF メッセージに含まれる外部タイプ レコードは、recordType キーが外部タイプの名前に設定され、data キーが外部タイプ レコードに含まれる NDEF メッセージを表すオブジェクトに設定されたオブジェクトとして定義されます。data キーは ArrayBuffer である場合や、ArrayBuffer へのビューを提供する場合があります(Uint8ArrayDataView など)。

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

空のレコードの読み取りと書き込み

空のレコードにはペイロードがありません。

空のレコードを書き込むには、NDEF メッセージ ディクショナリを NDEFReader の write() メソッドに渡します。NDEF メッセージに含まれる空のレコードは、recordType キーが "empty" に設定されたオブジェクトとして定義されます。

const emptyRecord = {
  recordType: "empty"
};

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

ブラウザ サポート

Web NFC は、Android 版 Chrome 89 で利用できます。

開発のヒント

ウェブ NFC を使い始めたときに知っておきたかったことを以下に示します。

  • Android では、Web NFC が動作する前に OS レベルで NFC タグを処理します。
  • NFC アイコンは material.io で確認できます。
  • NDEF レコード id を使用して、必要に応じてレコードを簡単に識別します。
  • NDEF をサポートする未フォーマット NFC タグには、空のタイプのレコードが 1 つ含まれています。
  • 以下に示すように、Android アプリのレコードは簡単に書き込めます。
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] });

デモ

公式サンプルを試し、クールなウェブ NFC デモをチェックしてください。

Chrome Dev Summit 2019 でのウェブ NFC カードのデモ

フィードバック

ウェブ NFC コミュニティ グループと Chrome チームより、ウェブ NFC に関するご意見やご感想をぜひお聞かせください。

API 設計について

API が想定どおりに機能していない点はありますか?あるいは、アイデアを実装するために不足しているメソッドやプロパティがあるでしょうか。

ウェブ NFC GitHub リポジトリで仕様の問題を提出するか、既存の問題に意見を追加します。

実装に関する問題を報告する

Chrome の実装にバグが見つかりましたか?それとも実装が仕様と異なるのでしょうか?

https://new.crbug.com でバグを報告します。できるだけ詳細な情報を含め、バグを再現するための簡単な手順を提示してください。また、[Components] は Blink>NFC に設定します。Glitch は、簡単な再現手順をすばやく共有するのに適しています。

クリエイターを応援する

ウェブ NFC を使用する予定はありますか?一般公開されている機能へのサポートは、Chrome チームが機能の優先順位を決める際に役立ちます。また、他のブラウザ ベンダーに、その機能のサポートがどれほど重要であるかを示します。

ハッシュタグ #WebNFC を使用して @ChromiumDev にツイートを送信し、どこでどのように使用しているかをお知らせください。

関連情報

謝辞

Web NFC を実装していただいた Intel の皆様に心より感謝いたします。Google Chrome は、Chromium プロジェクトを前進させるために協力しているコントリビューターのコミュニティに依存しています。Chromium のコントリビューターはすべて Google 社員ではありません。こうしたコントリビューターは特別な称賛に値します。