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 cho web là gì?

NFC là viết tắt của Near Field Communications, 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 xa dưới 10 cm và tốc độ truyền lên đến 424 kbit/s.

NFC dành cho web cung cấp cho các trang web khả năng đọc và ghi vào thẻ NFC khi chúng để 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 được 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 hoạt động trên các định dạng thẻ khác nhau.

Điện thoại đang cấp nguồn cho thẻ NFC để trao đổi dữ liệu
Biểu đồ hoạt động NFC

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

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

Ví dụ về các 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ể trình bày thêm thông tin về một nơi trưng bày khi người dùng chạm thiết bị của họ vào thẻ NFC ở gần khu trưng bày.
  • 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 trong đó.
  • Các trang web hội nghị có thể dùng mã này để quét huy hiệu NFC trong suốt sự kiện và đảm bảo chúng sẽ bị khoá để ngăn chặn các thay đổi khác đối với thông tin được ghi trên chúng.
  • Các trang web có thể dùng danh sách này để chia sẻ các khoá bí mật ban đầu cần thiết cho thiết bị hoặc dịch vụ các tình huống cấp phép cũng như để triển khai dữ liệu cấu hình trong quá trình vận hành .
Điện thoại quét một số thẻ NFC
Hình minh hoạ hoạt độ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 thông số kỹ thuật Hoàn tất
3. Thu thập ý kiến phản hồi và lặp lại 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 trên 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à bạn có thể đã 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 phải là có phần cứng được yêu cầu hay không. Đặc biệt, nếu phần cứng bị thiếu, lời hứa do một số cuộc gọi trả về sẽ bị từ chối. Tôi sẽ cung cấp khi tôi 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, có nghĩa là thiết bị này hoạt động bằng từ tính cảm ứng khi 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 hình thức và kiểu dáng, chẳng hạn như hình dán, thẻ tín dụng, đeo tay và 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 để cho thấy chức năng để chuẩn bị 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 NFC Data Exchange (Trao đổi dữ liệu NFC) Định dạng là một định dạng tin nhắn nhị phân gọn nhẹ do Diễn đàn NFC chuẩn hóa.

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

Thẻ NFC hỗ trợ NDEF giống như một ghi chú. Mọi người đều có thể đọc dữ liệu này và trừ phi tệp đó ở chế độ chỉ đọc, mọi người đều có thể ghi vào tệp đó. Chiến dịch này chứa một NDEF thông báo đó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 kiểu được liên kết. NFC của web hỗ trợ các loại bản ghi chuẩn hóa Diễn đàn NFC sau đây: 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à cục bộ loại.

Sơ đồ về một 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 một đối tượng NDEFReader mới. Đang gọi cho scan() trả về một lời hứa. Người dùng có thể được nhắc nếu quyền truy cập không phải trước đó đã được cấp. Lời hứa sẽ được thực hiện nếu đáp ứng tất cả các điều kiện sau:

  • Phương thức 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, tin nhắn NDEF đến sẽ có sẵn chậm nhất vào đă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ý vào readingerror sự kiện để nhận thông báo khi có thẻ NFC không tương thích lân cậ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. Nó chứa hai thuộc tính riêng biệt:

  • serialNumber là 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ó sẵn.
  • message biểu thị thông báo NDEF được lưu trữ trong thẻ NFC.

Để đọc nội dung thông báo NDEF, hãy lặp qua message.records và xử lý thành viên data một cách phù hợp dựa trên recordType của họ. Thành phần data được hiển thị dưới dạng DataView vì thành phần này 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. Gọi điện write() trả về một lời hứa. Người dùng có thể được nhắc nếu quyền truy cập không phải là đã cấp trước đó. Lúc này, thông báo NDEF đang "đã chuẩn bị" và hứa sẽ được phân giải nếu đáp ứng tất cả các điều kiện sau:

  • Phương thức 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 một thẻ NFC và thông báo NDEF đã được viết 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 đại diện cho NDEF nhắn tin cho write(). Trong ví dụ bên dưới, thông báo NDEF là từ điển bằng khoá records. Giá trị của lớp này là một mảng bản ghi - trong trường hợp này, là một URL bản ghi được xác định là một đối tượng có khoá recordType được đặt thành "url"data khóa đượ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 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 cho false trong các tuỳ chọn được truyền đến 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, có thể đặt thẻ NFC vĩnh viễn ở chế độ chỉ đọc. Đây là quy trình một chiều và không thể huỷ được. Sau khi đặt thẻ NFC ở chế độ chỉ đọc, bạn không thể ghi thẻ nữa.

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

  • Phương thức 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 công sang 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ạo thẻ NFC vĩnh viễn ở chế độ chỉ đọc sau khi ghi.

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 trong Chrome 100 trở lên, hãy kiểm tra nếu tính năng này được hỗ trợ như sau:

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

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

Nhóm Chrome đã thiết kế và triển khai NFC trên web bằng cách sử dụng các nguyên tắc cốt lõi được xác định trong phần Kiểm soát quyền truy cập vào nền tảng web mạnh mẽ Các tính năng, bao gồm cả quyền kiểm soát của người dùng, tính minh bạch và công thái học.

Vì NFC mở rộng miền thông tin có thể khả dụng thành các phần mềm độc hại các trang web, khả năng sử dụng NFC bị hạn chế để tăng tối đa khả năng mức độ nhận biết và quyền kiểm soát 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ỉ khả dụng cho các khung cấp cao nhất và ngữ cảnh duyệt web an toàn (HTTPS ). Trước tiên, nguồn gốc phải yêu cầu quyền "nfc" trong khi xử lý một cử chỉ của người dùng (ví dụ: nhấp vào nút). NDEFReader scan(), write() và Các phương thức makeReadOnly() sẽ kích hoạt lời nhắc của người dùng, nếu trước đó bạn chưa có quyền truy cập đã đượ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 đưa ra và thực tế chuyển động mang thiết bị lên trên thẻ NFC mục tiêu phản ánh trình chọn mẫu tìm thấy trong các API truy cập thiết bị và tệp khác.

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

Nhờ API Chế độ hiển thị trang, chúng tôi có thể theo dõi thời điểm các thay đổi về chế độ hiển thị.

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 thiết kế

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

Kiểm tra quyền

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

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 thao tác NFC

Sử dụng kiểu gốc AbortController để dễ dàng huỷ bỏ NFC các toán tử. Ví dụ bên dưới cho bạn biết cách chuyển signal của một AbortController thông qua các tuỳ chọn của NDEFReader scan(), makeReadOnly(), write() và huỷ cả hai thao tác 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

Sử dụng write(), sau đó là scan() với AbortController gốc giúp bạn có thể đọc thẻ NFC sau khi viết thông báo. Ví dụ bên dưới cho bạn biết cách gửi tin nhắn văn bản tới thẻ NFC và đọc tin nhắn mới trong thẻ NFC. Thiết bị 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 ghi văn bản data có thể được giải mã bằng TextDecoder được tạo thực thể với ghi lại thuộc tính encoding. Xin lưu ý rằng ngôn ngữ của bản ghi văn bản là 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() NDEFReader.

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

Theo mặc định, bản ghi văn bản 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 một 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 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 truyền một từ điển thông báo NDEF đến NDEFReader write(). Bản ghi URL có 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 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 một 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ụ: hãy 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 đến NDEFReader write(). Bản ghi loại MIME có trong thông báo NDEF đã được xác định dưới dạng đố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 một đối tượng có thể là ArrayBuffer hoặc cung cấp khung hiển thị trên một 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 ghi URL tuyệt đối data có thể được giải mã bằng 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 bản ghi URL tuyệt đối, hãy truyền từ điển thông báo NDEF vào Phương thức write() NDEFReader. Bản ghi URL tuyệt đối có trong NDEF thông báo được định nghĩa là một đối tượng có khoá recordType được đặt thành "absolute-url" và một 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à ghi bản ghi áp phích thông minh

Bản ghi áp phích thông minh (được sử dụng trong quảng cáo 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 có chứa NDEF làm tải trọng của nó. Gọi record.toRecords() để chuyển đổi data thành danh sách các bản ghi có trong bản ghi thông minh áp phích. URL nên có bản ghi URL, 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 tuỳ chỉnh các bản ghi kiểu cục bộ như ":t", ":act"":s" tương ứng cho thuộc tính loại, hành động và kích thước của bản ghi áp phích thông minh.

Bản ghi loại cục bộ là duy nhất trong ngữ cảnh cục bộ của vùng chứa Bản ghi NDEF. Sử dụng chúng khi ý nghĩa của các loại không quan trọng bên ngoài của ngữ cảnh cục bộ của bản ghi chứa và khi việc sử dụng bộ nhớ gặp khó khăn quy tắc ràng buộc. Tên bản ghi loại cục bộ luôn bắt đầu bằng : trong giao thức NFC trên web (ví dụ: ":t", ":s", ":act"). Mã này nhằm phân biệt bản ghi văn bản với bản ghi nhập bản ghi văn bản.

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 bản ghi áp phích thông minh, hãy truyền thông báo NDEF đến NDEFReader write() . 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 một đối tượng đại diện cho (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 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. Những thông tin 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 chứa tên miền của tổ chức phát hành, dấu hai chấm và loại tên dài ít nhất một 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 bản ghi loại bên ngoài, hãy truyền từ điển thông báo NDEF vào hàm Phương thức write() NDEFReader. Bản ghi loại bên ngoài có trong NDEF thông báo đượ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 một đố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 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 từ điển thông báo NDEF vào NDEFReader write(). 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 cho web có sẵn trên Android trong Chrome 89.

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

Sau đây là danh sách những điều tôi ước gì mình biết khi bắt đầu chơi với Web NFC:

  • Android xử lý 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.
  • Sử 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 có hỗ trợ NDEF chứa một bản ghi duy nhất thuộc loại trống.
  • Việc viết bản ghi ứng dụng Android rất đơn giản, 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 thử mẫu chính thức và xem một số bản minh hoạ NFC trên web thú vị:

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

Phản hồi

Nhóm cộng đồng NFC trên web và Nhóm Chrome rất muốn biết suy nghĩ và 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ế API

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

Gửi vấn đề về thông số kỹ thuật trên kho lưu trữ GitHub dành cho web NFC hoặc bổ sung ý kiến của bạn vào vấn đề hiện có.

Báo cáo sự cố về triển khai

Bạn có phát hiện lỗi trong quá trình triển khai Chrome không? Hoặc là triển khai khác với thông số kỹ thuật không?

Báo cáo lỗi tại https://new.crbug.com. Hãy nhớ bao gồm 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. Lỗi trục phù hợp với chia sẻ các bản ghi lại nhanh chóng và dễ dàng.

Thể hiện sự ủng hộ

Bạn có định sử dụng NFC cho web không? Sự hỗ trợ công khai của bạn giúp ích cho 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 này hỗ trợ họ.

Gửi một bài đăng đến @ChromiumDev kèm theo hashtag #WebNFC đồng thời cho chúng tôi biết bạn đang sử dụng ở đâu và như thế nào.

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

Xác nhận

Rất cảm ơn những thành viên tại Intel đã triển khai NFC cho web. Google Chrome phụ thuộc vào một cộng đồng người uỷ quyền làm việc cùng nhau để di chuyển Chromium dự án tiếp theo. Không phải người dùng Chromium nào cũng là nhân viên của Google và những người đóng góp xứng đáng được ghi nhận đặc biệt!