ข้อมูลพื้นฐานเกี่ยวกับ 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 แมปกับประเภทและ URI ของ MIME

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

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

หมายเหตุ: หากต้องการดาวน์โหลดข้อกำหนด NDEF ที่สมบูรณ์ ให้ไปที่เว็บไซต์ข้อกำหนดเฉพาะของฟอรัม NFC และเอกสารแอปพลิเคชัน และดูการสร้างระเบียน 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 กับประเภทหรือ URI ของ MIME หรือเมื่อแท็ก 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 อื่นๆ เมื่อเป็นไปได้
  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()

เช่น หากแท็กที่สแกนรองรับ MifareCLASS, 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>

รับข้อมูลจาก 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 ด้วยตนเอง

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

TNF_ABSOLUTE_URI

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

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

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 และอุปกรณ์ที่ไม่ใช่ 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

หากแท็กมี 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")}
        );
)