ข้อมูลพื้นฐานเกี่ยวกับ NFC

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

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

ระบบการเรียกใช้แท็ก

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

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

  1. แยกวิเคราะห์แท็ก NFC และค้นหาประเภท MIME หรือ URI ที่ระบุเพย์โหลดข้อมูล ในแท็ก
  2. การห่อหุ้มประเภท MIME หรือ URI และเพย์โหลดไว้ใน Intent ขั้นตอน 2 ขั้นตอนแรกนี้อธิบายไว้ในวิธีแมปแท็ก NFC กับประเภท MIME และ URI
  3. เริ่มกิจกรรมตามเจตนา ซึ่งอธิบายไว้ใน วิธีส่งแท็ก NFC ไปยังแอปพลิเคชัน

วิธีแมปแท็ก NFC กับประเภท MIME และ URI

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

ข้อมูล NDEF จะห่อหุ้มอยู่ภายในข้อความ (NdefMessage) ซึ่งมีระเบียนอย่างน้อย 1 รายการ (NdefRecord) ระเบียน NDEF แต่ละรายการต้องมีรูปแบบที่ถูกต้องตามข้อกำหนดของประเภทระเบียนที่ต้องการสร้าง Android ยังรองรับแท็กประเภทอื่นๆ ที่ไม่มีข้อมูล NDEF ซึ่งคุณสามารถใช้ได้โดยใช้ คลาสในแพ็กเกจ android.nfc.tech ดูข้อมูลเพิ่มเติม เกี่ยวกับเทคโนโลยีเหล่านี้ได้ที่หัวข้อNFC ขั้นสูง การทำงานกับแท็กประเภทอื่นๆ เหล่านี้เกี่ยวข้องกับการเขียนสแต็กโปรโตคอลของคุณเองเพื่อสื่อสารกับแท็ก ดังนั้นเราขอแนะนำให้ใช้ NDEF เมื่อเป็นไปได้เพื่อความสะดวกในการพัฒนาและรองรับอุปกรณ์ที่ใช้ Android ได้สูงสุด

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

ตอนนี้คุณมีพื้นฐานเกี่ยวกับแท็ก NFC แล้ว ส่วนต่อไปนี้จะอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับวิธีที่ Android จัดการแท็กที่จัดรูปแบบ NDEF เมื่ออุปกรณ์ที่ใช้ Android สแกนแท็ก NFC ที่มีข้อมูลซึ่งจัดรูปแบบ NDEF อุปกรณ์จะแยกวิเคราะห์ข้อความและพยายามหาประเภท MIME หรือ URI ที่ระบุ ของข้อมูล โดยระบบจะอ่าน NdefRecord แรกภายใน NdefMessage เพื่อพิจารณาวิธีตีความข้อความ NDEF ทั้งหมด (ข้อความ NDEF อาจมีระเบียน NDEF หลายรายการ) ในข้อความ NDEF ที่มีรูปแบบถูกต้อง NdefRecord แรกจะมีช่องต่อไปนี้

TNF (รูปแบบชื่อประเภท) 3 บิต
ระบุวิธีตีความฟิลด์ประเภทความยาวของตัวแปร ค่าที่ใช้ได้อธิบายไว้ในตารางที่ 1
ประเภทความยาวตัวแปร
อธิบายประเภทของระเบียน หากใช้ TNF_WELL_KNOWN ให้ใช้ฟิลด์นี้เพื่อระบุคำจำกัดความประเภทระเบียน (RTD) ค่า RTD ที่ใช้ได้อธิบายไว้ในตารางที่ 2
รหัสที่มีความยาวตัวแปร
ตัวระบุที่ไม่ซ้ำกันสำหรับระเบียน ฟิลด์นี้ไม่ค่อยได้ใช้ แต่หากต้องการระบุแท็กที่ไม่ซ้ำ คุณสามารถสร้างรหัสสำหรับแท็กได้
เพย์โหลดที่มีความยาวผันแปร
เพย์โหลดข้อมูลจริงที่คุณต้องการอ่านหรือเขียน ข้อความ NDEF อาจมีระเบียน NDEF หลายรายการ ดังนั้นอย่าคิดว่าเพย์โหลดทั้งหมดอยู่ในระเบียน NDEF แรกของข้อความ NDEF

ระบบการส่งแท็กใช้ฟิลด์ TNF และประเภทเพื่อพยายามแมปประเภท MIME หรือ URI กับข้อความ NDEF หากสำเร็จ ระบบจะห่อหุ้มข้อมูลดังกล่าวไว้ภายใน ACTION_NDEF_DISCOVEREDIntent พร้อมกับเพย์โหลดจริง อย่างไรก็ตาม มีบางกรณีที่ระบบการส่งแท็กไม่สามารถระบุประเภทข้อมูลตามระเบียน NDEF แรกได้ กรณีนี้จะเกิดขึ้นเมื่อระบบจับคู่ข้อมูล NDEF กับประเภท MIME หรือ URI ไม่ได้ หรือเมื่อแท็ก NFC ไม่มีข้อมูล NDEF ตั้งแต่แรก ในกรณีดังกล่าว ระบบจะห่อหุ้มออบเจ็กต์ Tag ที่มีข้อมูลเกี่ยวกับเทคโนโลยีของแท็กและเพย์โหลดไว้ภายในอินเทนต์ ACTION_TECH_DISCOVERED แทน

ตารางที่ 1 อธิบายวิธีที่ระบบการส่งแท็กแมปฟิลด์ TNF และประเภท กับประเภท MIME หรือ URI นอกจากนี้ยังอธิบายว่า TNF ใดที่จับคู่กับประเภท MIME หรือ URI ไม่ได้ ในกรณีเหล่านี้ ระบบการเรียกใช้แท็กจะกลับไปใช้ ACTION_TECH_DISCOVERED

เช่น หากระบบการเรียกใช้แท็กพบระเบียนประเภท TNF_ABSOLUTE_URI ระบบจะแมปฟิลด์ประเภทความยาวตัวแปรของระเบียนนั้น เป็น URI ระบบการส่งแท็กจะแคปซูล URI นั้นในฟิลด์ข้อมูลของACTION_NDEF_DISCOVERED Intent พร้อมกับข้อมูลอื่นๆ เกี่ยวกับแท็ก เช่น เพย์โหลด ในทางกลับกัน หากพบระเบียนประเภท TNF_UNKNOWN ระบบจะสร้าง Intent ที่ห่อหุ้มเทคโนโลยีของแท็กแทน

ตารางที่ 1 TNF ที่รองรับและการแมป

รูปแบบชื่อประเภท (TNF) การแมป
TNF_ABSOLUTE_URI URI ตามช่องประเภท
TNF_EMPTY เปลี่ยนกลับเป็น ACTION_TECH_DISCOVERED
TNF_EXTERNAL_TYPE URI ตาม URN ในช่องประเภท ระบบจะเข้ารหัส URN ลงในฟิลด์ประเภท NDEF ใน รูปแบบย่อ: <domain_name>:<service_name> Android จะแมปค่านี้กับ URI ในรูปแบบต่อไปนี้ vnd.android.nfc://ext/<domain_name>:<service_name>
TNF_MIME_MEDIA ประเภท MIME ตามช่องประเภท
TNF_UNCHANGED ไม่ถูกต้องในระเบียนแรก จึงกลับไปใช้ ACTION_TECH_DISCOVERED
TNF_UNKNOWN เปลี่ยนกลับเป็น ACTION_TECH_DISCOVERED
TNF_WELL_KNOWN ประเภท MIME หรือ URI ขึ้นอยู่กับคำจำกัดความประเภทระเบียน (RTD) ซึ่งคุณตั้งค่าไว้ใน ช่องประเภท ดูข้อมูลเพิ่มเติมเกี่ยวกับ RTD ที่ใช้ได้และการแมปได้ที่ตารางที่ 2

ตารางที่ 2 RTD ที่รองรับสำหรับ TNF_WELL_KNOWN และการ แมป

คำจำกัดความของประเภทระเบียน (RTD) การแมป
RTD_ALTERNATIVE_CARRIER เปลี่ยนกลับเป็น ACTION_TECH_DISCOVERED
RTD_HANDOVER_CARRIER เปลี่ยนกลับเป็น ACTION_TECH_DISCOVERED
RTD_HANDOVER_REQUEST เปลี่ยนกลับเป็น ACTION_TECH_DISCOVERED
RTD_HANDOVER_SELECT เปลี่ยนกลับเป็น ACTION_TECH_DISCOVERED
RTD_SMART_POSTER URI ตามการแยกวิเคราะห์เพย์โหลด
RTD_TEXT ประเภท MIME ของ text/plain
RTD_URI URI ตามเพย์โหลด

วิธีส่งแท็ก NFC ไปยังแอปพลิเคชัน

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

  1. ACTION_NDEF_DISCOVERED: Intent นี้ใช้เพื่อเริ่ม กิจกรรมเมื่อสแกนแท็กที่มีเพย์โหลด NDEF และเป็นประเภทที่ระบบรู้จัก นี่คือ Intent ที่มีลำดับความสำคัญสูงสุด และระบบการส่งแท็กจะพยายามเริ่มกิจกรรมด้วย Intent นี้ ก่อน Intent อื่นๆ ทุกครั้งที่เป็นไปได้

    หมายเหตุ: ตั้งแต่ Android 16 เป็นต้นไป การสแกนแท็ก NFC ที่จัดเก็บลิงก์ URL (เช่น รูปแบบ URI คือ "https://" หรือ "http://") จะทริกเกอร์ ACTION_VIEW Intent แทน ACTION_NDEF_DISCOVERED Intent

  2. ACTION_TECH_DISCOVERED: หากไม่มีกิจกรรมใดลงทะเบียนเพื่อจัดการ Intent ACTION_NDEF_DISCOVERED ระบบการส่งแท็กจะพยายามเริ่มแอปพลิเคชันด้วย Intent นี้ นอกจากนี้ ระบบจะเริ่ม Intent นี้โดยตรง (โดยไม่ต้องเริ่ม ACTION_NDEF_DISCOVERED ก่อน) หากแท็กที่สแกน มีข้อมูล NDEF ที่ไม่สามารถแมปกับประเภท MIME หรือ URI หรือหากแท็กไม่มีข้อมูล NDEF แต่เป็นเทคโนโลยีแท็กที่รู้จัก
  3. ACTION_TAG_DISCOVERED: ระบบจะเริ่มความตั้งใจนี้ หากไม่มีกิจกรรมใดจัดการความตั้งใจ ACTION_NDEF_DISCOVERED หรือ ACTION_TECH_DISCOVERED

ระบบการส่งแท็กทำงานในลักษณะพื้นฐานดังนี้

  1. พยายามเริ่มกิจกรรมด้วย Intent ที่สร้างขึ้นโดยระบบการส่งแท็ก เมื่อแยกวิเคราะห์แท็ก NFC (ไม่ว่าจะเป็น ACTION_NDEF_DISCOVERED หรือ ACTION_TECH_DISCOVERED)
  2. หากไม่มีตัวกรองกิจกรรมสำหรับ Intent นั้น ให้ลองเริ่มกิจกรรมด้วย Intent ที่มีลำดับความสำคัญต่ำที่สุดถัดไป (ACTION_TECH_DISCOVERED หรือ ACTION_TAG_DISCOVERED) จนกว่าแอปพลิเคชันจะกรอง Intent หรือจนกว่าระบบการส่งแท็กจะลอง Intent ที่เป็นไปได้ทั้งหมด
  3. หากไม่มีตัวกรองแอปพลิเคชันสำหรับ Intent ใดๆ ให้ไม่ต้องดำเนินการใดๆ
รูปที่ 1 ระบบการเรียกใช้แท็ก

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

ขอสิทธิ์เข้าถึง NFC ในไฟล์ Manifest ของ Android

ก่อนที่จะเข้าถึงฮาร์ดแวร์ NFC ของอุปกรณ์และจัดการ Intent ของ NFC อย่างถูกต้อง ให้ประกาศรายการต่อไปนี้ในไฟล์ AndroidManifest.xml

  • องค์ประกอบ NFC <uses-permission> สำหรับเข้าถึงฮาร์ดแวร์ NFC
    <uses-permission android:name="android.permission.NFC" />
  • SDK เวอร์ชันขั้นต่ำที่แอปพลิเคชันของคุณรองรับได้ API ระดับ 9 รองรับเฉพาะ การส่งแท็กที่จำกัดผ่าน ACTION_TAG_DISCOVERED และให้สิทธิ์ เข้าถึงข้อความ NDEF ผ่าน EXTRA_NDEF_MESSAGES เท่านั้น คุณจะเข้าถึงพร็อพเพอร์ตี้แท็กหรือการดำเนินการ I/O อื่นๆ ไม่ได้ API ระดับ 10 มีการรองรับการอ่าน/เขียนอย่างครอบคลุม รวมถึงการพุช NDEF ในเบื้องหน้า และ API ระดับ 14 มีเมธอดที่สะดวกเพิ่มเติมในการสร้างระเบียน NDEF
    <uses-sdk android:minSdkVersion="10"/>
  • องค์ประกอบ uses-feature เพื่อให้แอปพลิเคชันของคุณปรากฏใน Google Play เฉพาะสำหรับอุปกรณ์ที่มีฮาร์ดแวร์ NFC เท่านั้น
    <uses-feature android:name="android.hardware.nfc" android:required="true" />

    หากแอปพลิเคชันของคุณใช้ฟังก์ชัน NFC แต่ฟังก์ชันดังกล่าวไม่ได้มีความสำคัญต่อแอปพลิเคชัน คุณสามารถละเว้นองค์ประกอบ uses-feature และตรวจสอบความพร้อมใช้งานของ NFC ที่รันไทม์ได้โดยตรวจสอบว่า getDefaultAdapter() เป็น null หรือไม่

กรอง Intent ของ NFC

หากต้องการเริ่มแอปพลิเคชันเมื่อมีการสแกนแท็ก NFC ที่คุณต้องการจัดการ แอปพลิเคชัน สามารถกรอง Intent NFC อย่างใดอย่างหนึ่ง สองอย่าง หรือทั้งสามอย่างในไฟล์ Manifest ของ Android อย่างไรก็ตาม โดยปกติแล้วคุณ มักจะต้องการกรองACTION_NDEF_DISCOVEREDเจตนาสำหรับ การควบคุมเวลาที่แอปพลิเคชันของคุณเริ่มต้นมากที่สุด ACTION_TECH_DISCOVERED Intent เป็นการสำรองสำหรับ ACTION_NDEF_DISCOVERED เมื่อไม่มีตัวกรองแอปพลิเคชันสำหรับ ACTION_NDEF_DISCOVERED หรือเมื่อเพย์โหลดไม่ใช่ NDEF การกรองสำหรับ ACTION_TAG_DISCOVERED มักจะเป็นหมวดหมู่ทั่วไปเกินไป ที่จะใช้กรอง แอปพลิเคชันจำนวนมากจะกรอง ACTION_NDEF_DISCOVERED หรือ ACTION_TECH_DISCOVERED ก่อน ACTION_TAG_DISCOVERED ดังนั้นแอปพลิเคชันของคุณจึงมีโอกาสต่ำที่จะ เริ่มต้น ACTION_TAG_DISCOVERED จะใช้เป็นทางเลือกสุดท้ายเท่านั้น สำหรับแอปพลิเคชันในการกรองในกรณีที่ไม่มีแอปพลิเคชันอื่นติดตั้งไว้เพื่อจัดการ ACTION_NDEF_DISCOVERED หรือเจตนา ACTION_TECH_DISCOVERED

เนื่องจากการติดตั้งใช้งานแท็ก NFC มีความหลากหลายและหลายครั้งที่อยู่นอกเหนือการควบคุมของคุณ จึงไม่สามารถทำได้เสมอไป ด้วยเหตุนี้ คุณจึงสามารถใช้ 2 Intent อื่นแทนได้เมื่อจำเป็น เมื่อคุณควบคุมประเภทของแท็กและข้อมูลที่เขียนได้ ขอแนะนําให้ใช้ NDEF เพื่อจัดรูปแบบแท็ก ส่วนต่อไปนี้จะอธิบายวิธีกรองตามประเภทความตั้งใจแต่ละประเภท

ACTION_NDEF_DISCOVERED

หากต้องการกรองACTION_NDEF_DISCOVEREDเจตนา ให้ประกาศ ตัวกรองเจตนาพร้อมกับประเภทข้อมูลที่ต้องการกรอง ตัวอย่างต่อไปนี้จะกรอง ACTION_NDEF_DISCOVERED Intent ที่มีประเภท MIME เป็น text/plain

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="text/plain" />
</intent-filter>

ตัวอย่างต่อไปนี้จะกรอง URI ในรูปแบบ https://developer.android.com/index.html

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
   <data android:scheme="https"
              android:host="developer.android.com"
              android:pathPrefix="/index.html" />
</intent-filter>

ACTION_TECH_DISCOVERED

หากตัวกรองกิจกรรมสำหรับเจตนา ACTION_TECH_DISCOVERED คุณต้องสร้างไฟล์ทรัพยากร XML ที่ระบุเทคโนโลยีที่กิจกรรมรองรับ ภายในชุด tech-list ระบบจะพิจารณากิจกรรมของคุณว่าตรงกันหากtech-listชุดเป็นส่วนย่อยของเทคโนโลยีที่แท็กรองรับ ซึ่งคุณจะได้รับโดยการเรียกใช้ getTechList()

เช่น หากแท็กที่สแกนรองรับ MifareClassic, NdefFormatable และ NfcA ชุดtech-listของคุณต้องระบุเทคโนโลยีทั้ง 3 อย่าง 2 อย่าง หรือ 1 อย่าง (และไม่มีอย่างอื่น) เพื่อให้ระบบจับคู่กิจกรรมของคุณได้

ตัวอย่างต่อไปนี้จะกำหนดเทคโนโลยีทั้งหมด คุณต้องนำแท็กที่ไม่รองรับออก โดยแท็ก NFC บันทึกไฟล์นี้ (คุณจะตั้งชื่อไฟล์ว่าอะไรก็ได้) ในโฟลเดอร์ <project-root>/res/xml

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.IsoDep</tech>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.NfcB</tech>
        <tech>android.nfc.tech.NfcF</tech>
        <tech>android.nfc.tech.NfcV</tech>
        <tech>android.nfc.tech.Ndef</tech>
        <tech>android.nfc.tech.NdefFormatable</tech>
        <tech>android.nfc.tech.MifareClassic</tech>
        <tech>android.nfc.tech.MifareUltralight</tech>
    </tech-list>
</resources>

นอกจากนี้ คุณยังระบุชุด tech-list ได้หลายชุดด้วย ระบบจะพิจารณาtech-list แต่ละชุดแยกกัน และจะถือว่ากิจกรรมของคุณตรงกันหากtech-listชุดใดชุดหนึ่ง เป็นส่วนย่อยของเทคโนโลยีที่ getTechList() แสดงผล ซึ่งจะให้ความหมายของ AND และ OR สำหรับการจับคู่เทคโนโลยี ตัวอย่างต่อไปนี้ตรงกับแท็กที่รองรับเทคโนโลยี NfcA และ Ndef หรือรองรับเทคโนโลยี NfcB และ Ndef

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcB</tech>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
</resources>

ในไฟล์ AndroidManifest.xml ให้ระบุไฟล์ทรัพยากรที่คุณเพิ่งสร้าง ในองค์ประกอบ <meta-data> ภายในองค์ประกอบ <activity> เช่นเดียวกับในตัวอย่างต่อไปนี้

<activity>
...
<intent-filter>
    <action android:name="android.nfc.action.TECH_DISCOVERED"/>
</intent-filter>

<meta-data android:name="android.nfc.action.TECH_DISCOVERED"
    android:resource="@xml/nfc_tech_filter" />
...
</activity>

ดูข้อมูลเพิ่มเติมเกี่ยวกับการทำงานกับเทคโนโลยีแท็กและACTION_TECH_DISCOVEREDเจตนาได้ที่การทำงานกับเทคโนโลยีแท็กที่รองรับในเอกสาร NFC ขั้นสูง

ACTION_TAG_DISCOVERED

หากต้องการกรองสำหรับ ACTION_TAG_DISCOVERED ให้ใช้ตัวกรอง Intent ต่อไปนี้

<intent-filter>
    <action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>

ACTION_VIEW

ตั้งแต่ Android 16 เป็นต้นไป การสแกนแท็ก NFC ที่จัดเก็บลิงก์ URL จะทริกเกอร์ Intent ACTION_VIEW หากต้องการกรอง ACTION_VIEW โปรดดูthis ใช้ Android app links เพื่อเปิดแอปสำหรับ URL

รับข้อมูลจาก Intent

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

  • EXTRA_TAG (ต้องระบุ): ออบเจ็กต์ Tag ที่แสดงแท็กที่สแกน
  • EXTRA_NDEF_MESSAGES (ไม่บังคับ): อาร์เรย์ของข้อความ NDEF ที่แยกวิเคราะห์จากแท็ก ต้องระบุข้อมูลเพิ่มเติมนี้ใน เจตนา ACTION_NDEF_DISCOVERED
  • EXTRA_ID (ไม่บังคับ): รหัสระดับต่ำของแท็ก

หากต้องการรับข้อมูลเพิ่มเติมเหล่านี้ ให้ตรวจสอบว่ากิจกรรมของคุณเปิดตัวด้วยเจตนา NFC อย่างใดอย่างหนึ่งเพื่อให้แน่ใจว่ามีการสแกนแท็ก จากนั้นรับข้อมูลเพิ่มเติมจากเจตนา ตัวอย่างต่อไปนี้จะตรวจสอบ ACTION_NDEF_DISCOVERED Intent และรับข้อความ NDEF จาก Intent Extra

Kotlin

override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    ...
    if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
        intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMessages ->
            val messages: List<NdefMessage> = rawMessages.map { it as NdefMessage }
            // Process the messages array.
            ...
        }
    }
}

Java

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    ...
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
        Parcelable[] rawMessages =
            intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        if (rawMessages != null) {
            NdefMessage[] messages = new NdefMessage[rawMessages.length];
            for (int i = 0; i < rawMessages.length; i++) {
                messages[i] = (NdefMessage) rawMessages[i];
            }
            // Process the messages array.
            ...
        }
    }
}

หรือคุณจะรับออบเจ็กต์ Tag จาก Intent ก็ได้ ซึ่งจะมีเพย์โหลดและช่วยให้คุณแจงนับเทคโนโลยีของแท็กได้

Kotlin

val tag: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)

Java

Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

สร้างระเบียน NDEF ประเภททั่วไป

ส่วนนี้จะอธิบายวิธีสร้างระเบียน NDEF ประเภทที่พบบ่อยเพื่อช่วยคุณเมื่อเขียนไปยัง แท็ก NFC ตั้งแต่ Android 4.0 (API ระดับ 14) เป็นต้นไป คุณจะใช้เมธอด createUri() เพื่อช่วยสร้างระเบียน URI โดยอัตโนมัติได้ ตั้งแต่ Android 4.1 (API ระดับ 16) เป็นต้นไป createExternal() และ createMime() จะพร้อมใช้งานเพื่อช่วยคุณสร้าง ระเบียน NDEF ของ MIME และประเภทภายนอก ใช้วิธีการช่วยเหล่านี้ทุกครั้งที่เป็นไปได้เพื่อหลีกเลี่ยงข้อผิดพลาด เมื่อสร้างระเบียน NDEF ด้วยตนเอง

ส่วนนี้ยังอธิบายวิธีสร้าง ตัวกรอง Intent ที่เกี่ยวข้องสำหรับระเบียนด้วย ตัวอย่างระเบียน NDEF ทั้งหมดนี้ควรอยู่ในระเบียน NDEF แรกของข้อความ NDEF ที่คุณเขียนลงในแท็ก

TNF_ABSOLUTE_URI

หมายเหตุ: เราขอแนะนำให้คุณใช้ประเภท RTD_URI แทน TNF_ABSOLUTE_URI เนื่องจากมีประสิทธิภาพมากกว่า

คุณสร้างระเบียน TNF_ABSOLUTE_URI NDEF ได้ด้วยวิธีต่อไปนี้

Kotlin

val uriRecord = ByteArray(0).let { emptyByteArray ->
    NdefRecord(
            TNF_ABSOLUTE_URI,
            "https://developer.android.com/index.html".toByteArray(Charset.forName("US-ASCII")),
            emptyByteArray,
            emptyByteArray
    )
}

Java

NdefRecord uriRecord = new NdefRecord(
    NdefRecord.TNF_ABSOLUTE_URI ,
    "https://developer.android.com/index.html".getBytes(Charset.forName("US-ASCII")),
    new byte[0], new byte[0]);

ตัวกรอง Intent สำหรับระเบียน NDEF ก่อนหน้าจะมีลักษณะดังนี้

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="https"
        android:host="developer.android.com"
        android:pathPrefix="/index.html" />
</intent-filter>

TNF_MIME_MEDIA

คุณสร้างระเบียน TNF_MIME_MEDIA NDEF ได้ด้วยวิธีต่อไปนี้

การใช้วิธี createMime()

Kotlin

val mimeRecord = NdefRecord.createMime(
        "application/vnd.com.example.android.beam",
        "Beam me up, Android".toByteArray(Charset.forName("US-ASCII"))
)

Java

NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam",
    "Beam me up, Android".getBytes(Charset.forName("US-ASCII")));

การสร้าง NdefRecord ด้วยตนเอง

Kotlin

val mimeRecord = Charset.forName("US-ASCII").let { usAscii ->
    NdefRecord(
            NdefRecord.TNF_MIME_MEDIA,
            "application/vnd.com.example.android.beam".toByteArray(usAscii),
            ByteArray(0),
            "Beam me up, Android!".toByteArray(usAscii)
    )
}

Java

NdefRecord mimeRecord = new NdefRecord(
    NdefRecord.TNF_MIME_MEDIA ,
    "application/vnd.com.example.android.beam".getBytes(Charset.forName("US-ASCII")),
    new byte[0], "Beam me up, Android!".getBytes(Charset.forName("US-ASCII")));

ตัวกรอง Intent สำหรับระเบียน NDEF ก่อนหน้าจะมีลักษณะดังนี้

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="application/vnd.com.example.android.beam" />
</intent-filter>

TNF_WELL_KNOWN ที่มี RTD_TEXT

คุณสร้างระเบียน TNF_WELL_KNOWN NDEF ได้โดยทำดังนี้

Kotlin

fun createTextRecord(payload: String, locale: Locale, encodeInUtf8: Boolean): NdefRecord {
    val langBytes = locale.language.toByteArray(Charset.forName("US-ASCII"))
    val utfEncoding = if (encodeInUtf8) Charset.forName("UTF-8") else Charset.forName("UTF-16")
    val textBytes = payload.toByteArray(utfEncoding)
    val utfBit: Int = if (encodeInUtf8) 0 else 1 shl 7
    val status = (utfBit + langBytes.size).toChar()
    val data = ByteArray(1 + langBytes.size + textBytes.size)
    data[0] = status.toByte()
    System.arraycopy(langBytes, 0, data, 1, langBytes.size)
    System.arraycopy(textBytes, 0, data, 1 + langBytes.size, textBytes.size)
    return NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, ByteArray(0), data)
}

Java

public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
    byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
    Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
    byte[] textBytes = payload.getBytes(utfEncoding);
    int utfBit = encodeInUtf8 ? 0 : (1 << 7);
    char status = (char) (utfBit + langBytes.length);
    byte[] data = new byte[1 + langBytes.length + textBytes.length];
    data[0] = (byte) status;
    System.arraycopy(langBytes, 0, data, 1, langBytes.length);
    System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
    NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
    NdefRecord.RTD_TEXT, new byte[0], data);
    return record;
}

ตัวกรอง Intent สำหรับระเบียน NDEF ก่อนหน้าจะมีลักษณะดังนี้

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="text/plain" />
</intent-filter>

TNF_WELL_KNOWN ที่มี RTD_URI

คุณสร้างระเบียน TNF_WELL_KNOWN NDEF ได้ด้วยวิธีต่อไปนี้

การใช้วิธี createUri(String)

Kotlin

val rtdUriRecord1 = NdefRecord.createUri("https://example.com")

Java

NdefRecord rtdUriRecord1 = NdefRecord.createUri("https://example.com");

การใช้วิธี createUri(Uri)

Kotlin

val rtdUriRecord2 = Uri.parse("https://example.com").let { uri ->
    NdefRecord.createUri(uri)
}

Java

Uri uri = Uri.parse("https://example.com");
NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);

การสร้าง NdefRecord ด้วยตนเอง

Kotlin

val uriField = "example.com".toByteArray(Charset.forName("US-ASCII"))
val payload = ByteArray(uriField.size + 1)                   //add 1 for the URI Prefix
payload [0] = 0x01                                           //prefixes https://www. to the URI
System.arraycopy(uriField, 0, payload, 1, uriField.size)     //appends URI to payload
val rtdUriRecord = NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, ByteArray(0), payload)

Java

byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII"));
byte[] payload = new byte[uriField.length + 1];              //add 1 for the URI Prefix
payload[0] = 0x01;                                           //prefixes https://www. to the URI
System.arraycopy(uriField, 0, payload, 1, uriField.length);  //appends URI to payload
NdefRecord rtdUriRecord = new NdefRecord(
    NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);

ตัวกรอง Intent สำหรับระเบียน NDEF ก่อนหน้าจะมีลักษณะดังนี้

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="https"
        android:host="example.com"
        android:pathPrefix="" />
</intent-filter>

TNF_EXTERNAL_TYPE

คุณสร้างระเบียน NDEF TNF_EXTERNAL_TYPE ได้ด้วยวิธีต่อไปนี้

การใช้วิธี createExternal()

Kotlin

var payload: ByteArray //assign to your data
val domain = "com.example" //usually your app's package name
val type = "externalType"
val extRecord = NdefRecord.createExternal(domain, type, payload)

Java

byte[] payload; //assign to your data
String domain = "com.example"; //usually your app's package name
String type = "externalType";
NdefRecord extRecord = NdefRecord.createExternal(domain, type, payload);

การสร้าง NdefRecord ด้วยตนเอง

Kotlin

var payload: ByteArray
...
val extRecord = NdefRecord(
        NdefRecord.TNF_EXTERNAL_TYPE,
        "com.example:externalType".toByteArray(Charset.forName("US-ASCII")),
        ByteArray(0),
        payload
)

Java

byte[] payload;
...
NdefRecord extRecord = new NdefRecord(
    NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType".getBytes(Charset.forName("US-ASCII")),
    new byte[0], payload);

ตัวกรอง Intent สำหรับระเบียน NDEF ก่อนหน้าจะมีลักษณะดังนี้

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="vnd.android.nfc"
        android:host="ext"
        android:pathPrefix="/com.example:externalType"/>
</intent-filter>

ใช้ TNF_EXTERNAL_TYPE สำหรับการติดตั้งใช้งานแท็ก NFC ทั่วไปมากขึ้นเพื่อรองรับทั้งอุปกรณ์ที่ใช้และไม่ได้ใช้ระบบปฏิบัติการ Android ได้ดียิ่งขึ้น

หมายเหตุ: URN สำหรับ TNF_EXTERNAL_TYPE มีรูปแบบ Canonical ดังนี้ urn:nfc:ext:example.com:externalType อย่างไรก็ตาม ข้อกำหนด RTD ของ NFC Forum ระบุว่าต้องละเว้นส่วน urn:nfc:ext: ของ URN จาก ระเบียน NDEF ดังนั้นสิ่งที่คุณต้องระบุคือโดเมน (example.com ในตัวอย่าง) และประเภท (externalType ในตัวอย่าง) โดยคั่นด้วยเครื่องหมายโคลอน เมื่อส่ง TNF_EXTERNAL_TYPE Android จะแปลง URN ของ urn:nfc:ext:example.com:externalType เป็น URI ของ vnd.android.nfc://ext/example.com:externalType ซึ่งเป็นสิ่งที่ ตัวกรอง Intent ในตัวอย่างประกาศ

บันทึกแอปพลิเคชัน Android

Android Application Record (AAR) ซึ่งเปิดตัวใน Android 4.0 (API ระดับ 14) ช่วยให้มั่นใจได้มากขึ้น ว่าแอปพลิเคชันจะเริ่มทำงานเมื่อมีการสแกนแท็ก NFC AAR มีชื่อแพ็กเกจ ของแอปพลิเคชันที่ฝังอยู่ภายในระเบียน NDEF คุณสามารถเพิ่ม AAR ลงในระเบียน NDEF ของข้อความ NDEF ได้ เนื่องจาก Android จะค้นหา AAR ในข้อความ NDEF ทั้งหมด หากพบ AAR ระบบจะเริ่ม แอปพลิเคชันตามชื่อแพ็กเกจภายใน AAR หากไม่มีแอปพลิเคชันในอุปกรณ์ ระบบจะเปิด Google Play เพื่อดาวน์โหลดแอปพลิเคชัน

AAR มีประโยชน์หากคุณต้องการป้องกันไม่ให้แอปพลิเคชันอื่นๆ กรองตามความตั้งใจเดียวกัน และ อาจจัดการแท็กที่เฉพาะเจาะจงซึ่งคุณได้ติดตั้งใช้งาน AAR รองรับเฉพาะที่ระดับแอปพลิเคชันเนื่องจากข้อจํากัดของชื่อแพ็กเกจ และไม่รองรับที่ระดับกิจกรรมเหมือนกับการกรอง Intent หากต้องการจัดการ Intent ที่ระดับกิจกรรม ให้ใช้ตัวกรอง Intent

หากแท็กมี AAR ระบบการเรียกใช้แท็กจะเรียกใช้ในลักษณะต่อไปนี้

  1. ลองเริ่มกิจกรรมโดยใช้ตัวกรอง Intent ตามปกติ หากกิจกรรมที่ตรงกับ ความตั้งใจตรงกับ AAR ด้วย ให้เริ่มกิจกรรม
  2. หากกิจกรรมที่กรอง Intent ไม่ตรงกับ AAR หากมีกิจกรรมหลายรายการที่จัดการ Intent ได้ หรือหากไม่มีกิจกรรมใดจัดการ Intent ให้เริ่มแอปพลิเคชันที่ระบุโดย AAR
  3. หากไม่มีแอปพลิเคชันใดที่สามารถเริ่มต้นด้วย AAR ให้ไปที่ Google Play เพื่อดาวน์โหลด แอปพลิเคชันตาม AAR

หมายเหตุ: คุณสามารถลบล้าง AAR และระบบการส่งเจตนาด้วยระบบการส่งในเบื้องหน้า ซึ่งจะช่วยให้กิจกรรมในเบื้องหน้ามีลำดับความสำคัญเมื่อตรวจพบแท็ก NFC วิธีนี้กำหนดให้กิจกรรมต้องอยู่ในเบื้องหน้าเพื่อลบล้าง AAR และระบบการส่งต่อ Intent

หากยังต้องการกรองแท็กที่สแกนซึ่งไม่มี AAR คุณสามารถประกาศ ตัวกรอง Intent ได้ตามปกติ ซึ่งจะมีประโยชน์หากแอปพลิเคชันของคุณสนใจแท็กอื่นๆ ที่ไม่มี AAR เช่น คุณอาจต้องการรับประกันว่าแอปพลิเคชันจะจัดการแท็กที่เป็นกรรมสิทธิ์ที่คุณติดตั้งใช้งาน รวมถึงแท็กทั่วไปที่บุคคลที่สามติดตั้งใช้งาน โปรดทราบว่า AAR ใช้ได้กับอุปกรณ์ Android 4.0 ขึ้นไป ดังนั้นเมื่อติดตั้งใช้งานแท็ก คุณอาจต้องใช้ AAR ร่วมกับประเภท MIME/URI เพื่อรองรับอุปกรณ์ที่หลากหลายที่สุด นอกจากนี้ เมื่อติดตั้งใช้งานแท็ก NFC ให้พิจารณาว่าคุณต้องการเขียนแท็ก NFC อย่างไรเพื่อเปิดใช้ การรองรับอุปกรณ์ส่วนใหญ่ (อุปกรณ์ที่ใช้ Android และอุปกรณ์อื่นๆ) คุณทำได้โดย กำหนดประเภท MIME หรือ URI ที่ค่อนข้างไม่ซ้ำกันเพื่อให้แอปพลิเคชันแยกความแตกต่างได้ง่ายขึ้น

Android มี API ที่ใช้งานง่ายสำหรับสร้าง AAR createApplicationRecord() สิ่งที่คุณต้องทำคือฝัง AAR ไว้ที่ใดก็ได้ใน NdefMessage คุณไม่ต้องการ ใช้ระเบียนแรกของ NdefMessage เว้นแต่ AAR จะเป็นระเบียนเดียวใน NdefMessage เนื่องจากระบบ Android จะตรวจสอบระเบียนแรกของ NdefMessage เพื่อกำหนดประเภท MIME หรือ URI ของแท็ก ซึ่งใช้เพื่อสร้าง Intent ให้แอปพลิเคชันกรอง โค้ดต่อไปนี้ แสดงวิธีสร้าง AAR

Kotlin

val msg = NdefMessage(
        arrayOf(
                ...,
                NdefRecord.createApplicationRecord("com.example.android.beam")
        )
)

Java

NdefMessage msg = new NdefMessage(
        new NdefRecord[] {
            ...,
            NdefRecord.createApplicationRecord("com.example.android.beam")}
        );
)

รายการที่อนุญาตของแอปสำหรับการสแกนแท็ก NFC

ตั้งแต่ Android 16 เป็นต้นไป ผู้ใช้จะได้รับการแจ้งเตือนเมื่อแอปได้รับ Intent NFC แรกเพื่อสแกนแท็ก NFC ผู้ใช้จะมีตัวเลือกในการไม่อนุญาตให้แอปสแกนหาแท็ก NFC อีกต่อไปในการแจ้งเตือน

  • แอปจะตรวจสอบได้ว่าผู้ใช้ได้อนุญาตให้แอปสแกนแท็ก NFC หรือไม่โดยใช้ NfcAdapter.isTagIntentAllowed()
  • แอปสามารถแจ้งให้ผู้ใช้อนุญาตการสแกนแท็ก NFC อีกครั้งได้โดยการส่ง Intent ACTION_CHANGE_TAG_INTENT_PREFERENCE

หมายเหตุ: คุณเข้าถึงรายการที่อนุญาตของแอปสแกนแท็ก NFC ได้ในส่วนSettings > Apps > Special app access > Launch via NFC

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