โต้ตอบกับอุปกรณ์ NFC ใน Chrome สำหรับ Android

ตอนนี้สามารถอ่านและเขียนไปยังแท็ก NFC ได้แล้ว

François Beaufort
François Beaufort

Web NFC คืออะไร

NFC ย่อมาจาก Near Field Communications ซึ่งเป็นเทคโนโลยีไร้สายระยะสั้นที่ทำงานด้วยความเร็ว 13.56 MHz ที่ทำให้สามารถสื่อสารระหว่างอุปกรณ์ได้ในระยะห่างไม่เกิน 10 ซม. และมีอัตราการส่งข้อมูลสูงสุด 424 กิโลบิต/วินาที

Web NFC ช่วยให้เว็บไซต์อ่านและเขียนลงในแท็ก NFC ได้เมื่ออยู่ใกล้กับอุปกรณ์ของผู้ใช้ (โดยปกติคือ 5-10 ซม. หรือ 2-4 นิ้ว) ขอบเขตปัจจุบันจำกัดอยู่ที่รูปแบบการแลกเปลี่ยนข้อมูล NFC (NDEF) ซึ่งเป็นรูปแบบข้อความไบนารีที่มีน้ำหนักเบาซึ่งใช้ได้กับแท็กรูปแบบต่างๆ

โทรศัพท์เปิดแท็ก NFC เพื่อแลกเปลี่ยนข้อมูล
แผนภาพการทำงานของ NFC

กรณีการใช้งานที่แนะนํา

Web NFC จำกัดไว้ที่ NDEF เนื่องจากคุณสมบัติด้านความปลอดภัยของการอ่านและเขียนข้อมูล 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 บ่งบอกว่าเบราว์เซอร์รองรับ Web NFC แต่ไม่ได้บอกว่ามีฮาร์ดแวร์ที่จำเป็นหรือไม่ โดยเฉพาะอย่างยิ่ง หากฮาร์ดแวร์ขาดหายไป คำสัญญาที่ส่งคืนโดยการเรียกบางรายการจะถูกปฏิเสธ เราจะให้รายละเอียดเมื่ออธิบาย NDEFReader

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

คำศัพท์

แท็ก NFC เป็นอุปกรณ์ NFC แบบพาสซีฟ ซึ่งหมายความว่าใช้พลังงานจากการเหนี่ยวนำแม่เหล็กเมื่อมีอุปกรณ์ NFC ที่ใช้งานอยู่ (เช่น โทรศัพท์) อยู่ใกล้ๆ แท็ก NFC มีหลากหลายรูปแบบและดีไซน์ เช่น สติกเกอร์ บัตรเครดิต สายรัดข้อมือ และอื่นๆ

รูปภาพแท็ก NFC แบบโปร่งใส
แท็ก NFC แบบโปร่งใส

ออบเจ็กต์ NDEFReader คือจุดแรกเข้าในเว็บ NFC ที่แสดงฟังก์ชันการทำงานสำหรับการเตรียมการอ่านและ/หรือการเขียนที่ดำเนินการสำเร็จเมื่อแท็ก NDEF มาอยู่ใกล้กัน NDEF ใน NDEFReader ย่อมาจาก NFC Data Exchange Format ซึ่งเป็นรูปแบบข้อความไบนารีขนาดเล็กที่ได้มาตรฐานตามฟอรัม NFC

ออบเจ็กต์ NDEFReader มีไว้เพื่อดำเนินการกับข้อความ NDEF ขาเข้าจากแท็ก NFC และสำหรับการเขียนข้อความ NDEF ไปยังแท็ก NFC ภายในช่วง

แท็ก NFC ที่รองรับ NDEF เปรียบเสมือนโพสต์อิท ทุกคนอ่านได้ และทุกคนจะเขียนได้ เว้นแต่ว่าจะเป็นโหมดอ่านอย่างเดียว โดยจะมีข้อความ NDEF รายการเดียวซึ่งรวมระเบียน NDEF อย่างน้อย 1 รายการ ระเบียน NDEF แต่ละรายการเป็นโครงสร้างไบนารีที่มีเพย์โหลดข้อมูลและข้อมูลประเภทที่เกี่ยวข้อง Web NFC รองรับประเภทระเบียนมาตรฐานของ NFC Forum ต่อไปนี้ ได้แก่ ว่างเปล่า ข้อความ URL โปสเตอร์อัจฉริยะ ประเภท MIME, URL แบบสัมบูรณ์ ประเภทภายนอก ประเภทที่ไม่รู้จัก และประเภทภายใน

แผนภาพข้อความ NDEF
แผนภาพข้อความ NDEF

สแกนแท็ก NFC

หากต้องการสแกนแท็ก NFC ให้สร้างอินสแตนซ์ของออบเจ็กต์ NDEFReader ใหม่ก่อน การเรียกใช้ scan() จะแสดงผลลัพธ์เป็นสัญญา ระบบอาจแสดงข้อความแจ้งให้ผู้ใช้หากก่อนหน้านี้ไม่ได้ให้สิทธิ์เข้าถึง สัญญาจะได้รับการแก้ไขหากเป็นไปตามเงื่อนไขต่อไปนี้ทั้งหมด

  • เรียกใช้เพื่อตอบสนองต่อท่าทางสัมผัสของผู้ใช้เท่านั้น เช่น ท่าทางสัมผัสหรือการคลิกเมาส์
  • ผู้ใช้อนุญาตให้เว็บไซต์โต้ตอบกับอุปกรณ์ NFC
  • โทรศัพท์ของผู้ใช้รองรับ NFC
  • ผู้ใช้เปิดใช้ NFC ในโทรศัพท์แล้ว

เมื่อการตอบสนองได้รับการแก้ไขแล้ว ข้อความ NDEF ขาเข้าจะพร้อมใช้งานโดยสมัครรับเหตุการณ์ reading ผ่าน Listener เหตุการณ์ นอกจากนี้ คุณควรสมัครรับเหตุการณ์ readingerror เพื่อรับการแจ้งเตือนเมื่อมีแท็ก NFC ที่เข้ากันไม่ได้อยู่ใกล้ๆ

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 แสดงข้อความ NDEF ที่เก็บไว้ในแท็ก NFC

หากต้องการอ่านเนื้อหาของข้อความ NDEF ให้วนซ้ำ message.records และประมวลผลสมาชิก data คนอย่างเหมาะสมตามrecordType ระบบจะแสดงสมาชิก 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() จะแสดงผลลัพธ์เป็นสัญญา ผู้ใช้อาจได้รับข้อความแจ้งหากไม่ได้ให้สิทธิ์เข้าถึงไว้ก่อนหน้านี้ ในขั้นตอนนี้ ข้อความ NDEF จะ "จัดเตรียมแล้ว" และสัญญาจะได้รับการแก้ไขหากเป็นไปตามเงื่อนไขต่อไปนี้ทั้งหมด

  • เรียกใช้เพื่อตอบสนองต่อท่าทางสัมผัสของผู้ใช้เท่านั้น เช่น ท่าทางสัมผัสหรือการคลิกเมาส์
  • ผู้ใช้อนุญาตให้เว็บไซต์โต้ตอบกับอุปกรณ์ 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 ค่าของอาร์เรย์นี้คือระเบียน ซึ่งในกรณีนี้ระเบียน URL ที่กําหนดเป็นออบเจ็กต์ที่มีการตั้งค่าคีย์ recordType เป็น "url" และการตั้งค่าคีย์ data เป็นสตริง 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 ที่ไม่ได้ตั้งใจให้เขียนทับ ให้ตั้งค่าพร็อพเพอร์ตี้ overwrite เป็น false ในตัวเลือกที่ส่งไปยังเมธอด write() ในกรณีนี้ พรอมต์ที่แสดงผลจะปฏิเสธหากมีการจัดเก็บข้อความ NDEF ไว้ในแท็ก 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}.`);
});

ทำให้แท็ก NFC เป็นอ่านอย่างเดียว

หากไม่ต้องการให้ผู้ใช้ที่เป็นอันตรายเขียนทับเนื้อหาของแท็ก NFC คุณอาจกำหนดให้แท็ก NFC เป็นแบบอ่านอย่างเดียวอย่างถาวรได้ การดำเนินการนี้เป็นกระบวนการแบบทางเดียวและย้อนกลับไม่ได้ เมื่อกำหนดแท็ก NFC เป็นแบบอ่านอย่างเดียวแล้ว คุณจะเขียนแท็กนั้นไม่ได้อีก

หากต้องการกำหนดให้แท็ก NFC เป็นแบบอ่านอย่างเดียว ให้สร้างอินสแตนซ์ NDEFReader ใหม่ก่อน การเรียกใช้ makeReadOnly() จะให้คำมั่นสัญญา ผู้ใช้อาจได้รับข้อความแจ้งหากไม่ได้ให้สิทธิ์เข้าถึงไว้ก่อนหน้านี้ คำมั่นสัญญาจะได้รับการแก้ไขหากเป็นไปตามเงื่อนไขต่อไปนี้ทั้งหมด

  • ระบบจะเรียกใช้เพื่อตอบสนองต่อท่าทางสัมผัสของผู้ใช้ เช่น ท่าทางสัมผัสการแตะ หรือการคลิกเมาส์เท่านั้น
  • ผู้ใช้อนุญาตให้เว็บไซต์โต้ตอบกับอุปกรณ์ 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 บนเว็บบนเว็บไซต์
ข้อความแจ้งผู้ใช้เกี่ยวกับ NFC บนเว็บ

Web NFC ใช้ได้กับเฟรมระดับบนสุดและบริบทการท่องเว็บที่ปลอดภัย (HTTPS เท่านั้น) เท่านั้น โดย Origin ต้องขอ"nfc" สิทธิ์ก่อนขณะจัดการท่าทางสัมผัสของผู้ใช้ (เช่น การคลิกปุ่ม) เมธอด NDEFReader scan(), 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 Primitive ช่วยให้ยกเลิกการดำเนินการ NFC ได้ง่ายๆ ตัวอย่างด้านล่างแสดงวิธีส่ง signal ของ AbortController ผ่านตัวเลือกของเมธอด NDEFReader scan(), makeReadOnly() และ write() และยกเลิกการดำเนินการ NFC ทั้ง 2 รายการพร้อมกัน

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

อ่านหลังจากเขียน

การใช้ write() ตามด้วย scan() กับพรอมต์ AbortController ช่วยให้อ่านแท็ก 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 ได้ด้วย TextDecoder ที่สร้างอินสแตนซ์โดยใช้พร็อพเพอร์ตี้ระเบียน encoding โปรดทราบว่าภาษาของระเบียนข้อความจะดูได้จากพร็อพเพอร์ตี้ 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 โดยค่าเริ่มต้นและจะถือว่าใช้ภาษาของเอกสารปัจจุบัน แต่คุณระบุทั้ง 2 พร็อพเพอร์ตี้ (encoding และ lang) ได้โดยใช้ไวยากรณ์แบบเต็มเพื่อสร้างระเบียน NDEF ที่กำหนดเอง

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() ระเบียน URL ที่มีอยู่ในข้อความ NDEF ได้รับการกําหนดให้เป็นออบเจ็กต์ที่มีการตั้งค่าคีย์ 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

พร็อพเพอร์ตี้ mediaType ของระเบียนประเภท MIME แสดงถึงประเภท MIME ของเพย์โหลดระเบียน NDEF เพื่อให้สามารถถอดรหัส data ได้อย่างถูกต้อง เช่น ใช้ JSON.parse เพื่อถอดรหัสข้อความ JSON และองค์ประกอบรูปภาพเพื่อถอดรหัสข้อมูลรูปภาพ

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() ระเบียนประเภท MIME ที่อยู่ในข้อความ NDEF ได้รับการกำหนดเป็นออบเจ็กต์ที่ตั้งค่าคีย์ recordType เป็น "mime" ชุดคีย์ mediaType เป็นประเภท MIME จริงของเนื้อหา และชุดคีย์ data เป็นออบเจ็กต์ที่สามารถเป็น ArrayBuffer หรือให้มุมมองสำหรับ ArrayBuffer (เช่น 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] });

อ่านและเขียนระเบียน URL แบบสัมบูรณ์

ระเบียน absolute-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() ระเบียน URL แบบสัมบูรณ์ที่อยู่ในข้อความ NDEF ได้รับการกำหนดให้เป็นออบเจ็กต์ที่มีการตั้งค่าคีย์ 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 ไปยังwrite() เมธอด NDEFReader ระเบียนโปสเตอร์อัจฉริยะที่อยู่ในข้อความ 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] });

อ่านและเขียนระเบียนประเภทภายนอก

หากต้องการสร้างระเบียนที่กําหนดโดยแอปพลิเคชัน ให้ใช้ระเบียนประเภทภายนอก ซึ่งอาจมีข้อความ NDEF เป็นเพย์โหลดที่เข้าถึงได้ด้วย toRecords() ชื่อของไฟล์จะมีชื่อโดเมนขององค์กรที่ออกใบรับรอง เครื่องหมายโคลอน และชื่อประเภทที่มีความยาวอย่างน้อย 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 ก็ได้ (เช่น 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] });

อ่านและเขียนระเบียนที่ว่างเปล่า

ระเบียนที่ว่างเปล่าจะไม่มีเพย์โหลด

หากต้องการเขียนระเบียนว่าง ให้ส่งพจนานุกรมข้อความ NDEF ไปยังเมธอด NDEFReader write() ระเบียนว่างที่อยู่ในข้อความ NDEF ได้รับการกําหนดว่าเป็นออบเจ็กต์ที่มีการตั้งค่าคีย์ recordType เป็น "empty"

const emptyRecord = {
  recordType: "empty"
};

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

การสนับสนุนเบราว์เซอร์

Web NFC พร้อมใช้งานบน Android ใน Chrome 89

เคล็ดลับสำหรับนักพัฒนาซอฟต์แวร์

ต่อไปนี้คือรายการสิ่งที่ฉันอยากรู้เมื่อเริ่มเล่นกับ Web NFC

  • Android จะจัดการแท็ก NFC ที่ระดับระบบปฏิบัติการก่อนที่ Web NFC จะใช้งานได้
  • คุณดูไอคอน NFC ได้ที่ material.io
  • ใช้ระเบียน NDEF id เพื่อระบุระเบียนได้อย่างง่ายดายเมื่อจำเป็น
  • แท็ก NFC ที่ไม่มีการจัดรูปแบบซึ่งรองรับ NDEF มีระเบียนประเภทว่างเปล่ารายการเดียว
  • การเขียน android application record ทำได้ง่ายดังที่แสดงด้านล่าง
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] });

เดโม

ลองใช้ตัวอย่างอย่างเป็นทางการและดูตัวอย่าง Web NFC เจ๋งๆ ต่อไปนี้

การสาธิตบัตร NFC บนเว็บที่ Chrome Dev Summit 2019

ความคิดเห็น

กลุ่มชุมชน Web NFC และทีม Chrome อยากทราบความคิดเห็นและประสบการณ์ของคุณเกี่ยวกับ Web NFC

บอกเราเกี่ยวกับการออกแบบ API

มีบางอย่างเกี่ยวกับ API ที่ไม่ทำงานตามที่คาดไว้หรือไม่ หรือมีเมธอดหรือพร็อพเพอร์ตี้ที่ขาดหายไปซึ่งคุณต้องนำไปใช้กับไอเดียของคุณ

แจ้งปัญหาเกี่ยวกับข้อกำหนดใน Web NFC GitHub repo หรือแสดงความคิดเห็นในปัญหาที่มีอยู่

รายงานปัญหาเกี่ยวกับการติดตั้งใช้งาน

หากพบข้อบกพร่องในการใช้งาน Chrome หรือการใช้งานแตกต่างจากข้อกําหนดหรือไม่

รายงานข้อบกพร่องที่ https://new.crbug.com อย่าลืมระบุรายละเอียดให้มากที่สุด ระบุวิธีการง่ายๆ ในการทําให้เกิดข้อบกพร่องซ้ำ และตั้งค่าคอมโพเนนต์เป็น Blink>NFC Glitch เหมาะอย่างยิ่งสำหรับการแชร์การจำลองข้อบกพร่องที่รวดเร็วและง่ายดาย

แสดงการสนับสนุน

คุณวางแผนที่จะใช้ Web NFC ไหม การสนับสนุนแบบสาธารณะของคุณช่วยให้ทีม Chrome จัดลําดับความสําคัญของฟีเจอร์ต่างๆ และแสดงให้เห็นว่าการสนับสนุนฟีเจอร์เหล่านี้สำคัญเพียงใดต่อผู้ให้บริการเบราว์เซอร์รายอื่นๆ

ทวีตถึง @ChromiumDev โดยใช้แฮชแท็ก #WebNFC และแจ้งให้เราทราบว่าคุณใช้ฟีเจอร์นี้ที่ไหนและอย่างไร

ลิงก์ที่มีประโยชน์

ขอขอบคุณ

ขอขอบคุณอย่างยิ่งที่ทีม Intel ติดตั้งใช้งาน Web NFC Google Chrome อาศัยชุมชนของเหล่าคอมมิชชันที่ทำงานร่วมกันเพื่อขับเคลื่อนโครงการ Chromium ให้ก้าวไปข้างหน้า คณะกรรมการ Chromium บางคนอาจไม่ได้เป็น Googler และผู้ร่วมให้ข้อมูลเหล่านี้สมควรได้รับการยอมรับเป็นพิเศษ