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

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

François Beaufort
François Beaufort

Web NFC คืออะไร

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

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

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

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

Web NFC จำกัดไว้ที่ NDEF เนื่องจากคุณสมบัติด้านความปลอดภัยของการอ่านและเขียนข้อมูล NDEF สามารถวัดผลได้ง่ายกว่า ไม่รองรับการดำเนินการ I/O ระดับต่ำ (เช่น ISO-DEP, NFC-A/B, NFC-F), โหมดการสื่อสารแบบ Peer-to-Peer และโหมดการจําลองบัตรบนอุปกรณ์ (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 คือจุดแรกเข้าใน Web NFC ที่แสดงฟังก์ชันการทำงานสำหรับการเตรียมการอ่านและ/หรือการเขียนที่จะดำเนินการเมื่อแท็ก NDEF อยู่ใกล้ๆ NDEF ใน NDEFReader ย่อมาจาก NFC Data Exchange Format ซึ่งเป็นรูปแบบข้อความฐานสองที่มีน้ำหนักเบาซึ่ง NFC Forum กำหนดมาตรฐานไว้

ออบเจ็กต์ 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 เป็นอ่านอย่างเดียว ให้สร้างอินสแตนซ์ของออบเจ็กต์ 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() ระเบียน absolute-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 ไม่ได้เป็นพนักงาน Google ทุกคน และเราก็อยากมอบการยกย่องเป็นพิเศษให้แก่ผู้ร่วมเขียนโค้ดเหล่านี้