ข้อมูลพื้นฐานเกี่ยวกับ 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. เริ่มกิจกรรมตาม Intent โปรดดูรายละเอียดในหัวข้อวิธีส่งแท็ก NFC ไปยังแอปพลิเคชัน

วิธีจับคู่แท็ก NFC กับประเภท MIME และ URI

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

ข้อมูล NDEF จะรวมอยู่ในข้อความ (NdefMessage) ที่มีระเบียน (NdefRecord) อย่างน้อย 1 รายการ ระเบียน 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 หากทําสําเร็จ ระบบจะรวมข้อมูลดังกล่าวไว้ใน Intent ACTION_NDEF_DISCOVERED พร้อมกับเพย์โหลดจริง อย่างไรก็ตาม อาจมีกรณีที่ระบบส่งแท็กไม่สามารถระบุประเภทข้อมูลตามระเบียน NDEF รายการแรก กรณีนี้จะเกิดขึ้นเมื่อระบบจับคู่ข้อมูล NDEF กับประเภท MIME หรือ URI ไม่ได้ หรือเมื่อแท็ก NFC ไม่มีข้อมูล NDEF มาตั้งแต่ต้น ในกรณีเช่นนี้ ออบเจ็กต์ Tag ที่มีข้อมูลเกี่ยวกับเทคโนโลยีของแท็กและเพย์โหลดจะรวมอยู่ใน Intent ACTION_TECH_DISCOVERED แทน

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

เช่น หากระบบส่งแท็กพบระเบียนประเภท TNF_ABSOLUTE_URI ระบบจะแมปช่องประเภทที่มีความยาวแปรผันของระเบียนนั้นเป็น URI ระบบการส่งแท็กจะรวม URI นั้นไว้ในช่องข้อมูลของ Intent ACTION_NDEF_DISCOVERED พร้อมกับข้อมูลอื่นๆ เกี่ยวกับแท็ก เช่น เพย์โหลด ในทางกลับกัน หากพบระเบียนประเภท 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 คือ "htttps://" หรือ "http://") จะทริกเกอร์ Intent ACTION_VIEW แทน Intent ACTION_NDEF_DISCOVERED

  2. ACTION_TECH_DISCOVERED: หากไม่มีกิจกรรมลงทะเบียนเพื่อจัดการกับ Intent ACTION_NDEF_DISCOVERED ระบบการส่งแท็กจะพยายามเริ่มแอปพลิเคชันด้วย 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 เนื่องจากมีความเฉพาะเจาะจงมากที่สุดในบรรดา 3 รายการ Intent นี้ช่วยให้คุณเริ่มแอปพลิเคชันในเวลาที่เหมาะสมกว่า Intent 2 รายการที่เหลือ ซึ่งจะช่วยให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ดีขึ้น

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

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

  • องค์ประกอบ 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 รายการใดรายการหนึ่ง 2 รายการ หรือทั้ง 3 รายการในไฟล์ Manifest ของ Android อย่างไรก็ตาม คุณมักจะต้องกรองหา Intent ACTION_NDEF_DISCOVERED เพื่อให้ควบคุมเวลาเริ่มต้นของแอปพลิเคชันได้มากที่สุด Intent 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 มีไว้เป็นทางเลือกสุดท้ายเท่านั้นสำหรับแอปพลิเคชันที่จะกรองหาในกรณีที่ไม่มีการติดตั้งแอปพลิเคชันอื่นเพื่อจัดการกับ Intent ACTION_NDEF_DISCOVERED หรือ ACTION_TECH_DISCOVERED

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

ACTION_NDEF_DISCOVERED

หากต้องการกรอง Intent ACTION_NDEF_DISCOVERED ให้ประกาศตัวกรอง Intent พร้อมกับประเภทข้อมูลที่ต้องการกรอง ตัวอย่างตัวกรองต่อไปนี้สําหรับ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

หากกิจกรรมกรอง Intent 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>

ดูข้อมูลเพิ่มเติมเกี่ยวกับการทำงานกับเทคโนโลยีแท็กและ Intent 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 Intents อาจมีข้อมูลเพิ่มเติมต่อไปนี้โดยขึ้นอยู่กับแท็กที่สแกน

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

หากต้องการรับข้อมูลเพิ่มเติมเหล่านี้ ให้ตรวจสอบว่ามีการเริ่มกิจกรรมด้วย Intent ของ NFC รายการใดรายการหนึ่งหรือไม่เพื่อให้แน่ใจว่ามีการสแกนแท็ก จากนั้นรับข้อมูลเพิ่มเติมจาก Intent ตัวอย่างต่อไปนี้จะตรวจสอบ Intent ACTION_NDEF_DISCOVERED และรับข้อความ 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() จะใช้เพื่อช่วยคุณสร้างระเบียน MIME และ NDEF ประเภทภายนอกได้ ใช้เมธอดตัวช่วยเหล่านี้ทุกครั้งที่เป็นไปได้เพื่อหลีกเลี่ยงข้อผิดพลาดเมื่อสร้างระเบียน 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

คุณสร้างระเบียน NDEF TNF_MIME_MEDIA ได้ดังนี้

การใช้เมธอด 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

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

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

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

การใช้เมธอด 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

คุณสร้างระเบียน TNF_EXTERNAL_TYPE NDEF ได้ดังนี้

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

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

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

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

หมายเหตุ: คุณสามารถลบล้าง AAR และระบบการจัดเตรียม Intent ด้วยระบบการจัดเตรียมที่ทำงานอยู่เบื้องหน้า ซึ่งจะช่วยให้กิจกรรมที่ทำงานอยู่เบื้องหน้ามีลำดับความสำคัญเมื่อตรวจพบแท็ก 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 (บัตรเครดิต โทรศัพท์/นาฬิกาเครื่องอื่น ฯลฯ)