Tương tác với thiết bị NFC trên Chrome dành cho Android

Giờ đây, bạn có thể đọc và ghi vào thẻ NFC.

François Beaufort
François Beaufort

NFC trên web là gì?

NFC là viết tắt của giao thức truyền thông gần trường, một công nghệ không dây tầm ngắn hoạt động ở tần số 13,56 MHz cho phép giao tiếp giữa các thiết bị ở khoảng cách dưới 10 cm và tốc độ truyền lên đến 424 kbit/giây.

NFC trên web cung cấp cho các trang web khả năng đọc và ghi vào thẻ NFC khi các thẻ này ở gần thiết bị của người dùng (thường là 5-10 cm, 2-4 inch). Phạm vi hiện tại giới hạn ở Định dạng trao đổi dữ liệu NFC (NDEF), một định dạng thông báo nhị phân gọn nhẹ, hoạt động trên nhiều định dạng thẻ.

Điện thoại kích hoạt thẻ NFC để trao đổi dữ liệu
Sơ đồ hoạt động NFC

Trường hợp sử dụng được đề xuất

NFC trên web chỉ giới hạn ở NDEF vì các thuộc tính bảo mật của việc đọc và ghi dữ liệu NDEF dễ định lượng hơn. Các thao tác I/O cấp thấp (ví dụ: ISO-DEP, NFC-A/B, NFC-F), chế độ giao tiếp ngang hàng và Mô phỏng thẻ dựa trên máy chủ (HCE) không được hỗ trợ.

Ví dụ về những trang web có thể sử dụng NFC trên web bao gồm:

  • Bảo tàng và phòng trưng bày nghệ thuật có thể hiển thị thêm thông tin về màn hình khi người dùng chạm thiết bị của họ vào thẻ NFC gần khu trưng bày.
  • Các trang web quản lý khoảng không quảng cáo có thể đọc hoặc ghi dữ liệu vào thẻ NFC trên vùng chứa để cập nhật thông tin về nội dung của vùng chứa đó.
  • Các trang web hội nghị có thể sử dụng thẻ này để quét huy hiệu NFC trong suốt sự kiện và đảm bảo rằng các huy hiệu này đã được khoá để ngăn những thay đổi khác đối với thông tin được ghi trên thẻ.
  • Các trang web có thể dùng dữ liệu này để chia sẻ mã thông báo bí mật ban đầu cần thiết cho các tình huống cấp phép thiết bị hoặc dịch vụ, cũng như để triển khai dữ liệu cấu hình ở chế độ hoạt động.
Điện thoại đang quét nhiều thẻ NFC
Minh hoạ tính năng quản lý khoảng không quảng cáo qua NFC

Trạng thái hiện tại

Bước Trạng thái
1. Tạo thông báo giải thích Hoàn tất
2. Tạo bản nháp ban đầu của quy cách Hoàn tất
3. Thu thập ý kiến phản hồi và cải tiến thiết kế Hoàn tất
4. Bản dùng thử theo nguyên gốc Hoàn tất
5. Ra mắt Hoàn tất

Sử dụng NFC cho web

Phát hiện tính năng

Tính năng phát hiện tính năng cho phần cứng khác với tính năng mà có thể bạn đã quen thuộc. Sự hiện diện của NDEFReader cho bạn biết rằng trình duyệt có hỗ trợ NFC trên web, nhưng không cho biết phần cứng được yêu cầu có hỗ trợ hay không. Cụ thể, nếu phần cứng bị thiếu, thì lời hứa mà một số lệnh gọi nhất định trả về sẽ bị từ chối. Tôi sẽ cung cấp thông tin chi tiết khi mô tả NDEFReader.

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

Thuật ngữ

Thẻ NFC là một thiết bị NFC thụ động, nghĩa là được cấp nguồn bởi cảm ứng từ khi có một thiết bị NFC đang hoạt động (chẳng hạn như điện thoại) ở gần. Thẻ NFC có nhiều dạng và nhiều cách thức, chẳng hạn như hình dán, thẻ tín dụng, vòng tay đeo tay và nhiều dạng khác.

Ảnh thẻ NFC trong suốt
Thẻ NFC trong suốt

Đối tượng NDEFReader là điểm truy cập trong NFC trên web hiển thị chức năng để chuẩn bị các thao tác đọc và/hoặc ghi được thực hiện khi thẻ NDEF đến gần. NDEF trong NDEFReader là viết tắt của Định dạng trao đổi dữ liệu NFC, một định dạng thông báo nhị phân nhẹ được Diễn đàn NFC chuẩn hoá.

Đối tượng NDEFReader dùng để thao tác trên các tin nhắn NDEF đến từ thẻ NFC và để ghi thông báo NDEF tới thẻ NFC trong phạm vi.

Thẻ NFC hỗ trợ NDEF giống như một thẻ ghi chú sau. Bất kỳ ai cũng có thể đọc và trừ phi ở chế độ chỉ đọc thì ai cũng có thể ghi vào đó. Tệp này chứa một thông báo NDEF duy nhất đóng gói một hoặc nhiều bản ghi NDEF. Mỗi bản ghi NDEF là một cấu trúc nhị phân chứa tải trọng dữ liệu và thông tin loại liên quan. NFC trên web hỗ trợ các loại bản ghi chuẩn sau của Diễn đàn NFC: trống, văn bản, URL, áp phích thông minh, loại MIME, URL tuyệt đối, loại bên ngoài, không xác định và loại cục bộ.

Sơ đồ thông báo NDEF
Biểu đồ thông báo NDEF

Quét thẻ NFC

Để quét thẻ NFC, trước tiên, hãy tạo thực thể cho đối tượng NDEFReader mới. Việc gọi scan() sẽ trả về một lời hứa. Người dùng có thể được nhắc nếu quyền truy cập chưa được cấp trước đó. Lời hứa sẽ được giải quyết nếu tất cả các điều kiện sau được đáp ứng:

  • Lệnh này chỉ được gọi để phản hồi một cử chỉ của người dùng, chẳng hạn như cử chỉ chạm hoặc nhấp chuột.
  • Người dùng đã cho phép trang web tương tác với thiết bị NFC.
  • Điện thoại của người dùng hỗ trợ NFC.
  • Người dùng đã bật NFC trên điện thoại của họ.

Sau khi lời hứa được giải quyết, bạn có thể nhận được thông báo NDEF bằng cách đăng ký các sự kiện reading thông qua trình nghe sự kiện. Bạn cũng nên đăng ký các sự kiện readingerror để nhận thông báo khi các thẻ NFC không tương thích xuất hiện ở gần.

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

Khi một thẻ NFC ở gần, sự kiện NDEFReadingEvent sẽ được kích hoạt. Lớp này có hai thuộc tính riêng biệt:

  • serialNumber thể hiện số sê-ri của thiết bị (ví dụ: 00-11-22-33-44-55-66) hoặc một chuỗi trống nếu không có.
  • message đại diện cho thông báo NDEF được lưu trữ trong thẻ NFC.

Để đọc nội dung của thông báo NDEF, hãy lặp lại message.records và xử lý các thành phần data một cách phù hợp dựa trên recordType. Thành phần data được biểu thị dưới dạng DataView vì cho phép xử lý các trường hợp dữ liệu được mã hoá theo 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.
    }
  }
};

Ghi thẻ NFC

Để ghi thẻ NFC, trước tiên, hãy tạo thực thể cho đối tượng NDEFReader mới. Việc gọi write() sẽ trả về một lời hứa. Người dùng có thể được nhắc nếu trước đó chưa được cấp quyền truy cập. Tại thời điểm này, thông báo NDEF được "chuẩn bị" và hứa hẹn sẽ được giải quyết nếu tất cả các điều kiện sau đều được đáp ứng:

  • Lệnh này chỉ được gọi để phản hồi một cử chỉ của người dùng, chẳng hạn như cử chỉ chạm hoặc nhấp chuột.
  • Người dùng đã cho phép trang web tương tác với thiết bị NFC.
  • Điện thoại của người dùng hỗ trợ NFC.
  • Người dùng đã bật NFC trên điện thoại của họ.
  • Người dùng đã nhấn vào thẻ NFC và thông báo NDEF đã được ghi thành công.

Để ghi văn bản vào thẻ NFC, hãy truyền một chuỗi vào phương thức write().

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

Để ghi một bản ghi URL vào thẻ NFC, hãy truyền một từ điển biểu thị thông báo NDEF đến write(). Trong ví dụ bên dưới, thông báo NDEF là một từ điển có khoá records. Giá trị của lớp này là một mảng các bản ghi – trong trường hợp này, bản ghi URL được xác định là một đối tượng với khoá recordType được đặt thành "url" và khoá data được đặt thành chuỗi 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}.`);
});

Bạn cũng có thể ghi nhiều bản ghi vào một thẻ 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}.`);
});

Nếu thẻ NFC chứa thông báo NDEF không được ghi đè, hãy đặt thuộc tính overwrite thành false trong các tuỳ chọn được chuyển đến phương thức write(). Trong trường hợp đó, lời hứa được trả về sẽ từ chối nếu thông báo NDEF đã được lưu trữ trong thẻ NFC.

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

Đặt thẻ NFC ở chế độ chỉ đọc

Để ngăn người dùng độc hại ghi đè nội dung của thẻ NFC, bạn có thể đặt thẻ NFC vĩnh viễn ở chế độ chỉ đọc. Thao tác này là quá trình một chiều và không thể đảo ngược. Sau khi đặt thẻ NFC ở chế độ chỉ đọc, bạn không thể ghi thẻ vào đó nữa.

Để thiết lập thẻ NFC ở chế độ chỉ đọc, trước tiên, hãy tạo thực thể cho đối tượng NDEFReader mới. Việc gọi makeReadOnly() sẽ trả về một lời hứa. Người dùng có thể được nhắc nếu trước đó chưa được cấp quyền truy cập. Lời hứa sẽ được giải quyết nếu tất cả các điều kiện sau đây đều được đáp ứng:

  • Lệnh này chỉ được gọi để phản hồi một cử chỉ của người dùng, chẳng hạn như cử chỉ chạm hoặc nhấp chuột.
  • Người dùng đã cho phép trang web tương tác với thiết bị NFC.
  • Điện thoại của người dùng hỗ trợ NFC.
  • Người dùng đã bật NFC trên điện thoại của họ.
  • Người dùng đã nhấn vào thẻ NFC và thẻ NFC đã được chuyển thành chế độ chỉ đọc.
const ndef = new NDEFReader();
ndef.makeReadOnly()
.then(() => {
  console.log("NFC tag has been made permanently read-only.");
}).catch(error => {
  console.log(`Operation failed: ${error}`);
});

Dưới đây là cách đặt vĩnh viễn thẻ NFC ở chế độ chỉ đọc sau khi ghi vào thẻ.

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() có trên Android với Chrome 100 trở lên, hãy kiểm tra xem tính năng này có được hỗ trợ hay không bằng cách:

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

Tính bảo mật và quyền

Nhóm Chrome đã thiết kế và triển khai NFC trên web theo các nguyên tắc cốt lõi nêu trong bài viết Kiểm soát quyền truy cập vào các tính năng nền tảng web mạnh mẽ, bao gồm cả quyền kiểm soát của người dùng, độ trong suốt và hiệu quả công thái học.

Vì NFC mở rộng miền thông tin có thể có sẵn cho các trang web độc hại, nên phạm vi cung cấp NFC sẽ bị hạn chế để tối đa hoá khả năng nhận biết và kiểm soát của người dùng đối với việc sử dụng NFC.

Ảnh chụp màn hình lời nhắc NFC trên web trên một trang web
Lời nhắc dành cho người dùng NFC trên web

NFC trên web chỉ có sẵn cho các khung cấp cao nhất và ngữ cảnh duyệt web an toàn (chỉ HTTPS). Trước tiên, các nguồn gốc phải yêu cầu quyền "nfc" trong khi xử lý cử chỉ của người dùng (ví dụ: nhấp vào nút). Các phương thức NDEFReader scan(), write()makeReadOnly() sẽ kích hoạt lời nhắc cho người dùng nếu trước đó quyền truy cập chưa được cấp.

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

Sự kết hợp giữa lời nhắc cấp quyền do người dùng khởi tạo và thao tác thực tế trong việc đưa thiết bị qua thẻ NFC mục tiêu phản ánh mẫu bộ chọn trong các API truy cập thiết bị và tệp khác.

Để quét hoặc ghi, trang web phải hiển thị khi người dùng chạm vào thẻ NFC bằng thiết bị của họ. Trình duyệt sử dụng phản hồi xúc giác để cho biết một lần nhấn. Quyền truy cập vào đài NFC sẽ bị chặn nếu màn hình đang tắt hoặc thiết bị bị khoá. Đối với các trang web không hiển thị, việc nhận và đẩy nội dung NFC sẽ bị tạm ngưng và tiếp tục khi trang web hiển thị lại.

Nhờ có API Chế độ hiển thị trang, bạn có thể theo dõi thời điểm chế độ hiển thị tài liệu thay đổi.

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

Sổ tay nấu ăn

Dưới đây là một số mã mẫu để giúp bạn bắt đầu.

Kiểm tra quyền

Permissions API (API Quyền) cho phép kiểm tra xem quyền "nfc" đã được cấp hay chưa. Ví dụ này cho biết cách quét thẻ NFC mà không cần tương tác của người dùng nếu quyền truy cập đã được cấp trước đó hoặc hiển thị một nút trong trường hợp khác. Xin lưu ý rằng cơ chế này hoạt động để ghi thẻ NFC vì cơ chế này sử dụng cùng một quyền.

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

Huỷ các hoạt động NFC

Việc sử dụng dữ liệu gốc AbortController giúp bạn dễ dàng huỷ các thao tác NFC. Ví dụ bên dưới cho bạn biết cách truyền signal của AbortController thông qua các lựa chọn của phương thức NDEFReader scan(), makeReadOnly(), write() và huỷ cả hai hoạt động NFC cùng lúc.

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

Đọc sau khi ghi

Việc sử dụng write() rồi scan() với dữ liệu gốc AbortController giúp bạn có thể đọc thẻ NFC sau khi ghi thông báo vào thẻ đó. Ví dụ bên dưới cho bạn biết cách ghi tin nhắn văn bản vào thẻ NFC và đọc tin nhắn mới trong thẻ NFC. Máy sẽ ngừng quét sau 3 giây.

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

Đọc và ghi bản ghi văn bản

Bạn có thể giải mã bản ghi văn bản data bằng TextDecoder được tạo bản sao thông qua thuộc tính bản ghi encoding. Xin lưu ý rằng ngôn ngữ của bản ghi văn bản có sẵn thông qua thuộc tính lang.

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

Để ghi một bản ghi văn bản đơn giản, hãy truyền một chuỗi vào phương thức write() của NDEFReader.

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

Theo mặc định, các bản ghi văn bản đều sử dụng UTF-8 và giả định ngôn ngữ của tài liệu hiện tại, nhưng bạn có thể chỉ định cả hai thuộc tính (encodinglang) bằng cú pháp đầy đủ để tạo bản ghi NDEF tuỳ chỉnh.

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

Đọc và ghi một bản ghi URL

Sử dụng TextDecoder để giải mã data của bản ghi.

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

Để ghi một bản ghi URL, hãy chuyển từ điển thông báo NDEF vào phương thức write() của NDEFReader. Bản ghi URL trong thông báo NDEF được định nghĩa là một đối tượng có khoá recordType được đặt thành "url" và khoá data được đặt thành chuỗi URL.

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

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

Đọc và ghi bản ghi loại MIME

Thuộc tính mediaType của bản ghi loại MIME đại diện cho loại MIME của tải trọng bản ghi NDEF để có thể giải mã data đúng cách. Ví dụ: sử dụng JSON.parse để giải mã văn bản JSON và một phần tử Hình ảnh để giải mã dữ liệu hình ảnh.

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

Để ghi một bản ghi loại MIME, hãy truyền một từ điển thông báo NDEF vào phương thức write() của NDEFReader. Bản ghi loại MIME có trong thông báo NDEF được định nghĩa là một đối tượng có khoá recordType được đặt thành "mime", khoá mediaType được đặt thành loại MIME thực tế của nội dung và khoá data được đặt thành đối tượng có thể là ArrayBuffer hoặc cung cấp chế độ xem trên ArrayBuffer (ví dụ: Uint8Array, DataView).

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

Đọc và ghi bản ghi URL tuyệt đối

Bạn có thể giải mã bản ghi URL tuyệt đối data bằng một TextDecoder đơn giản.

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

Để ghi một bản ghi URL tuyệt đối, hãy truyền từ điển thông báo NDEFReader vào phương thức write() của NDEFReader. Bản ghi URL tuyệt đối có trong thông báo NDEF được định nghĩa là một đối tượng có khoá recordType được đặt thành "absolute-url" và khoá data được đặt thành chuỗi URL.

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

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

Đọc và viết một bản ghi áp phích thông minh

Bản ghi áp phích thông minh (dùng trong quảng cáo trên tạp chí, tờ rơi, biển quảng cáo, v.v.), mô tả một số nội dung trên web dưới dạng bản ghi NDEF chứa thông báo NDEF dưới dạng tải trọng. Gọi record.toRecords() để chuyển đổi data thành danh sách các bản ghi có trong bản ghi áp phích thông minh. Tệp này phải có một bản ghi URL, một bản ghi văn bản cho tiêu đề, một bản ghi loại MIME cho hình ảnh và một số bản ghi loại cục bộ tuỳ chỉnh, chẳng hạn như ":t", ":act"":s" tương ứng cho loại, hành động và kích thước của bản ghi áp phích thông minh.

Các bản ghi loại cục bộ chỉ là bản ghi duy nhất trong ngữ cảnh cục bộ của bản ghi NDEF chứa. Sử dụng chúng khi ý nghĩa của các kiểu không quan trọng bên ngoài ngữ cảnh cục bộ của bản ghi chứa, và khi mức sử dụng bộ nhớ là một hạn chế khó khăn. Tên bản ghi loại cục bộ luôn bắt đầu bằng : trong API Web (ví dụ: ":t", ":s", ":act"). Tên này dùng để phân biệt bản ghi văn bản với bản ghi văn bản loại cục bộ.

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

Để ghi một bản ghi áp phích thông minh, hãy truyền thông báo NDEF đến phương thức write() của NDEFReader. Bản ghi áp phích thông minh có trong thông báo NDEF được định nghĩa là một đối tượng có khoá recordType được đặt thành "smart-poster" và khoá data được đặt thành đối tượng đại diện (một lần nữa) thông báo NDEF có trong bản ghi áp phích thông minh.

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

Đọc và ghi một bản ghi loại bên ngoài

Để tạo bản ghi do ứng dụng xác định, hãy sử dụng bản ghi loại bên ngoài. Các đối tượng này có thể chứa thông báo NDEF dưới dạng tải trọng có thể truy cập được bằng toRecords(). Tên thư chứa tên miền của tổ chức phát hành, dấu hai chấm và tên loại có ít nhất 1 ký tự, ví dụ: "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.
    }
  }
}

Để ghi một bản ghi loại bên ngoài, hãy truyền từ điển thông báo NDEF vào phương thức write() của NDEFReader. Bản ghi loại bên ngoài có trong thông báo NDEF được định nghĩa là một đối tượng có khoá recordType được đặt thành tên của loại bên ngoài và khoá data được đặt thành đối tượng đại diện cho thông báo NDEF có trong bản ghi loại bên ngoài. Xin lưu ý rằng khoá data cũng có thể là ArrayBuffer hoặc cung cấp khung hiển thị trên ArrayBuffer (ví dụ: 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] });

Đọc và ghi một bản ghi trống

Bản ghi trống không có tải trọng.

Để ghi một bản ghi trống, hãy truyền một từ điển thông báo NDEF vào phương thức write() của NDEFReader. Bản ghi trống trong thông báo NDEF được định nghĩa là một đối tượng có khoá recordType được đặt thành "empty".

const emptyRecord = {
  recordType: "empty"
};

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

Hỗ trợ trình duyệt

NFC trên web đã có trên Android trong Chrome 89.

Mẹo cho nhà phát triển

Sau đây là danh sách những điều tôi ước rằng tôi đã biết khi bắt đầu chơi với NFC trên web:

  • Android xử lý các thẻ NFC ở cấp hệ điều hành trước khi NFC trên web hoạt động.
  • Bạn có thể tìm thấy biểu tượng NFC trên material.io.
  • Dùng bản ghi NDEF id để dễ dàng xác định bản ghi khi cần.
  • Thẻ NFC chưa được định dạng hỗ trợ NDEF chứa một bản ghi thuộc loại trống.
  • Việc viết một bản ghi ứng dụng Android rất dễ dàng, như minh hoạ dưới đây.
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] });

Bản thu thử

Hãy dùng thử mẫu chính thức và xem một số bản minh hoạ NFC Web thú vị:

Bản minh hoạ thẻ NFC trên web tại Hội nghị Nhà phát triển Chrome năm 2019

Ý kiến phản hồi

Nhóm cộng đồng NFC trên web và nhóm Chrome rất muốn biết ý kiến cũng như trải nghiệm của bạn với NFC trên web.

Cho chúng tôi biết về thiết kế của API

Có vấn đề nào về API không hoạt động như mong đợi không? Hay có phương thức hoặc thuộc tính nào bị thiếu mà bạn cần triển khai ý tưởng của mình không?

Gửi vấn đề về thông số kỹ thuật trên kho lưu trữ GitHub về NFC hoặc thêm ý kiến vào vấn đề hiện tại.

Báo cáo sự cố với quá trình triển khai

Bạn có phát hiện thấy lỗi khi triển khai Chrome không? Hay cách triển khai có khác với thông số kỹ thuật không?

Gửi lỗi tại https://new.crbug.com. Hãy nhớ cung cấp nhiều chi tiết nhất có thể, cung cấp hướng dẫn đơn giản để tái tạo lỗi và đặt Thành phần thành Blink>NFC. Sự kiện không mong muốn hoạt động hiệu quả để chia sẻ các bản sửa lại nhanh chóng và dễ dàng.

Hiển thị sự ủng hộ

Bạn có định sử dụng NFC trên web không? Sự hỗ trợ công khai của bạn giúp nhóm Chrome ưu tiên các tính năng và cho các nhà cung cấp trình duyệt khác biết tầm quan trọng của việc hỗ trợ các tính năng đó.

Hãy gửi một bài đăng trên Twitter tới @ChromiumDev kèm theo hashtag #WebNFC và cho chúng tôi biết vị trí cũng như cách bạn sử dụng bài đăng này.

Các đường liên kết hữu ích

Xác nhận

Cảm ơn những người dùng tại Intel đã triển khai NFC trên web. Google Chrome dựa vào một cộng đồng gồm những người cam kết làm việc cùng nhau để thúc đẩy dự án Chromium phát triển. Không phải người cam kết nào của Chromium cũng là một nhân viên của Google và những người đóng góp này xứng đáng được ghi nhận đặc biệt!