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

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

François Beaufort
François Beaufort

Web NFC คืออะไร

NFC ย่อมาจาก Near Field Communications ซึ่งเป็นเทคโนโลยีไร้สายระยะสั้น ที่ทำงานที่ความถี่ 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), โหมดการสื่อสารแบบเพียร์ทูเพียร์ และการจำลองบัตรที่อิงตามโฮสต์ (HCE)

ตัวอย่างเว็บไซต์ที่อาจใช้ Web NFC ได้แก่

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

สถานะปัจจุบัน

ขั้นตอน สถานะ
1. สร้างวิดีโออธิบาย เสร็จสมบูรณ์
2. สร้างร่างข้อกำหนดเบื้องต้น เสร็จสมบูรณ์
3. รวบรวมความคิดเห็นและทำซ้ำการออกแบบ เสร็จสมบูรณ์
4. ช่วงทดลองใช้จากต้นทาง เสร็จสมบูรณ์
5. เปิดตัว เสร็จสมบูรณ์

ใช้ Web NFC

การตรวจหาฟีเจอร์

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

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

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

  • โดยจะเรียกใช้เมื่อมีการตอบสนองต่อท่าทางของผู้ใช้เท่านั้น เช่น ท่าทางสัมผัสหรือ การคลิกเมาส์
  • ผู้ใช้ได้อนุญาตให้เว็บไซต์โต้ตอบกับอุปกรณ์ NFC
  • โทรศัพท์ของผู้ใช้รองรับ NFC
  • ผู้ใช้ได้เปิดใช้ NFC ในโทรศัพท์แล้ว
  • ผู้ใช้แตะแท็ก NFC และตั้งค่าแท็ก NFC เป็นแบบอ่านอย่างเดียวเรียบร้อยแล้ว
const ndef = new NDEFReader();
ndef.makeReadOnly()
.then(() => {
  console.log("NFC tag has been made permanently read-only.");
}).catch(error => {
  console.log(`Operation failed: ${error}`);
});

วิธีทำให้แท็ก NFC เป็นแบบอ่านอย่างเดียวถาวรหลังจากเขียนข้อมูลลงในแท็กมีดังนี้

const ndef = new NDEFReader();
try {
  await ndef.write("Hello world");
  console.log("Message written.");
  await ndef.makeReadOnly();
  console.log("NFC tag has been made permanently read-only after writing to it.");
} catch (error) {
  console.log(`Operation failed: ${error}`);
}

เนื่องจาก makeReadOnly() พร้อมใช้งานใน Android ใน Chrome 100 ขึ้นไป ให้ตรวจสอบว่าฟีเจอร์นี้รองรับสิ่งต่อไปนี้หรือไม่

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

ความปลอดภัยและสิทธิ์

ทีม Chrome ได้ออกแบบและใช้ Web NFC ตามหลักการพื้นฐาน ที่ระบุไว้ในการควบคุมการเข้าถึงฟีเจอร์ที่มีประสิทธิภาพของแพลตฟอร์มเว็บ ซึ่งรวมถึงการควบคุมของผู้ใช้ ความโปร่งใส และการยศาสตร์

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

ภาพหน้าจอของข้อความแจ้ง Web NFC ในเว็บไซต์
ข้อความแจ้งผู้ใช้ Web NFC

Web NFC ใช้ได้เฉพาะกับเฟรมระดับบนสุดและบริบทการท่องเว็บที่ปลอดภัย (HTTPS เท่านั้น) โดยต้นทางต้องขอ"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

การใช้ Primitive AbortController จะช่วยให้ยกเลิกการดำเนินการ 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 Primitive จะช่วยให้อ่านแท็ก 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 ที่สมบูรณ์

คุณถอดรหัสระเบียน 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 เป็นเรื่องง่าย ดังที่แสดงด้านล่าง
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 ที่น่าสนใจ

การสาธิตการ์ด Web NFC ที่ Chrome Dev Summit 2019

ความคิดเห็น

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

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

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

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

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

หากพบข้อบกพร่องในการใช้งาน Chrome หรือการติดตั้งใช้งาน แตกต่างจากข้อกำหนด

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

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

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

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

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

การรับทราบ

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