במסמך הזה מתוארים נושאים מתקדמים על NFC, כמו עבודה עם טכנולוגיות תגים שונות, כתיבה לתגי NFC ושליחה בחזית, שמאפשרים לאפליקציה בחזית להתמודד עם כוונות גם כשאפליקציות אחרות מסוננות לפי אותן כוונות.
עבודה עם טכנולוגיות תגים נתמכות
כשעובדים עם תגי NFC ועם מכשירים מבוססי Android, הפורמט העיקרי שבו משתמשים כדי לקרוא
וכתיבת נתונים בתגים היא NDEF. כשמכשיר סורק תג עם נתוני NDEF, Android מספק תמיכה
בניתוח ההודעה ובמסירה שלה בNdefMessage
ככל האפשר. עם זאת, במקרים מסוימים כאשר סורקים תג שלא מכיל
נתוני NDEF או כאשר לא ניתן למפות את נתוני NDEF לסוג MIME או URI.
במקרים כאלה, צריך לפתוח תקשורת ישירות עם התג ולקרוא בו ולכתוב בו
בפרוטוקול משלכם (בבייטים גולמיים). מערכת Android מספקת תמיכה כללית לתרחישים לדוגמה האלה באמצעות
חבילת android.nfc.tech
, המתוארת בטבלה 1. אפשר
להשתמש בשיטה getTechList()
כדי לזהות את הטכנולוגיות
שנתמכות על ידי התג, ויוצרים את הערך המתאים של TagTechnology
אובייקט עם אחת המחלקות שסופקה על ידי android.nfc.tech
דרגה | תיאור |
---|---|
TagTechnology |
הממשק שכל הסוגים של טכנולוגיות התגים חייבים להטמיע. |
NfcA |
מספקת גישה לנכסי NFC-A (ISO 14443-3A) ולפעולות קלט/פלט (I/O). |
NfcB |
מספקת גישה לתכונות NFC-B (ISO 14443-3B) ולפעולות קלט/פלט (I/O). |
NfcF |
מספקת גישה לנכסי NFC-F (JIS 6319-4) ולפעולות קלט/פלט (I/O). |
NfcV |
מספקת גישה לתכונות NFC-V (ISO 15693) ולפעולות קלט/פלט (I/O). |
IsoDep |
מספקת גישה לתכונות ISO-DEP (ISO 14443-4) ולפעולות קלט/פלט (I/O). |
Ndef |
גישה לנתונים ולפעולות של NDEF בתגי NFC בפורמט NDEF. |
NdefFormatable |
כוללת פעולות פורמט לתגים שעשויים להיות בפורמט NDEF. |
טכנולוגיות התגים הבאות לא נתמכות במכשירים מבוססי Android.
דרגה | תיאור |
---|---|
MifareClassic |
גישה לנכסים של MIFARE Classic ולפעולות קלט/פלט (I/O), אם מכשיר Android הזה שתומך ב-MIFARE. |
MifareUltralight |
מספקת גישה למאפייני MIFARE Ultralight ופעולות קלט/פלט (I/O), אם מערכת ההפעלה Android שהמכשיר תומך ב-MIFARE. |
עבודה עם טכנולוגיות תגים ו-Intent ACTION_TECH_DISCOVERED
כשמכשיר סורק תג שיש בו נתוני NDEF אבל לא ניתן למפות אותו ל-MIME או URI,
מערכת שליחת התגים מנסה להתחיל פעילות עם ACTION_TECH_DISCOVERED
בכוונה טובה. השדה ACTION_TECH_DISCOVERED
משמש גם לתג
עם נתונים שאינם של NDEF. החלופה הזו מאפשרת לעבוד עם הנתונים בתג
ישירות אם מערכת שליחת התגים לא הצליחה לנתח אותו בשבילכם. השלבים הבסיסיים בעבודה עם
אלו הן טכנולוגיות התגים:
- סינון לפי Intent של
ACTION_TECH_DISCOVERED
שמציין את שבהן רוצים לטפל. למידע נוסף על סינון לפי NFC Intents לקבלת מידע נוסף. באופן כללי, מערכת שליחת התגים מנסה להפעיל Intent מסוגACTION_TECH_DISCOVERED
כשהודעת NDEF לא ניתן למפות לסוג MIME או ל-URI, או אם התג שנסרק לא הכיל נתוני NDEF. עבור מידע נוסף על האופן שבו נקבע המאפיין הזה זמין במאמר מערכת שליחת התגים. - כשהאפליקציה מקבלת את ה-Intent, צריך לקבל את האובייקט
Tag
מ- הכוונה:Kotlin
var tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
Java
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
- כדי לקבל מופע של
TagTechnology
, מפעילים את אחת מהאפשרויותget
שיטות המקוריות של המחלקות בחבילהandroid.nfc.tech
. אפשר לספור את הטכנולוגיות הנתמכות של התג באמצעות קריאה ל-getTechList()
לפני קריאה ל-method של היצרןget
. לדוגמה, כדי לקבל מכונה שלMifareUltralight
מ-Tag
, צריך לבצע את הפעולות הבאות:Kotlin
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))
Java
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
קריאה וכתיבה בתגים
קריאה וכתיבה בתג NFC כרוכות בהשגת התג מה-Intent לפתוח תקשורת עם התג. עליך להגדיר מקבץ פרוטוקול משלך כדי לקרוא ולכתוב נתונים לתג. עם זאת, חשוב לזכור שעדיין אפשר לקרוא ולכתוב נתוני NDEF כשעובדים ישירות באמצעות תג. אתם קובעים איך תרצו לבנות את הדברים. הדוגמה הבאה מראה איך לעבוד עם תג MIFARE Ultralight.
Kotlin
package com.example.android.nfc import android.nfc.Tag import android.nfc.tech.MifareUltralight import java.io.IOException import java.nio.charset.Charset class MifareUltralightTagTester { fun writeTag(tag: Tag, tagText: String) { MifareUltralight.get(tag)?.use { ultralight -> ultralight.connect() Charset.forName("US-ASCII").also { usAscii -> ultralight.writePage(4, "abcd".toByteArray(usAscii)) ultralight.writePage(5, "efgh".toByteArray(usAscii)) ultralight.writePage(6, "ijkl".toByteArray(usAscii)) ultralight.writePage(7, "mnop".toByteArray(usAscii)) } } } fun readTag(tag: Tag): String? { return MifareUltralight.get(tag)?.use { mifare -> mifare.connect() val payload = mifare.readPages(4) String(payload, Charset.forName("US-ASCII")) } } }
Java
package com.example.android.nfc; import android.nfc.Tag; import android.nfc.tech.MifareUltralight; import android.util.Log; import java.io.IOException; import java.nio.charset.Charset; public class MifareUltralightTagTester { private static final String TAG = MifareUltralightTagTester.class.getSimpleName(); public void writeTag(Tag tag, String tagText) { MifareUltralight ultralight = MifareUltralight.get(tag); try { ultralight.connect(); ultralight.writePage(4, "abcd".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(5, "efgh".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(6, "ijkl".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(7, "mnop".getBytes(Charset.forName("US-ASCII"))); } catch (IOException e) { Log.e(TAG, "IOException while writing MifareUltralight...", e); } finally { try { ultralight.close(); } catch (IOException e) { Log.e(TAG, "IOException while closing MifareUltralight...", e); } } } public String readTag(Tag tag) { MifareUltralight mifare = MifareUltralight.get(tag); try { mifare.connect(); byte[] payload = mifare.readPages(4); return new String(payload, Charset.forName("US-ASCII")); } catch (IOException e) { Log.e(TAG, "IOException while reading MifareUltralight message...", e); } finally { if (mifare != null) { try { mifare.close(); } catch (IOException e) { Log.e(TAG, "Error closing tag...", e); } } } return null; } }
שימוש במערכת השליחה בחזית
מערכת השליחה בחזית מאפשרת לפעילות לקלוט כוונה וטענה עדיפות על פני פעילויות אחרות שמטפלות באותה כוונה. השימוש במערכת הזו כרוך לבנות כמה מבני נתונים כדי שמערכת Android תוכל לשלוח את את הכוונות שלכם. כדי להפעיל את מערכת השליחה בחזית:
- מוסיפים את הקוד הבא ל-method
onCreate()
של הפעילות:- יצירת אובייקט
PendingIntent
שניתן לשנות כדי שמערכת Android תוכל לאכלס אותו בפרטי התג בזמן הסריקה.Kotlin
val intent = Intent(this, javaClass).apply { addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) } var pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE)
Java
PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE);
- צריך להצהיר על מסנני Intent כדי לטפל באובייקטים של Intent שרוצים ליירט. החזית
המערכת בודקת את מסנני ה-Intent שצוינו באמצעות הכוונה שמתקבלת
שהמכשיר סורק תג. אם הוא תואם, האפליקציה תטפל ב-Intent. אם כן
לא תואם, מערכת שליחת המידע בחזית תוחזר למערכת הפצת ה-Intent.
ציון מערך
null
של מסנני Intent ומסנני טכנולוגיה, מציין שרוצים לסנן כדי להציג את כל התגים שמבוססים עלTAG_DISCOVERED
בכוונה טובה. קטע הקוד שבהמשך מטפל בכל סוגי MIME עבורNDEF_DISCOVERED
. שלך צריך לטפל רק באלה שדרושות לך.Kotlin
val ndef = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED).apply { try { addDataType("*/*") /* Handles all MIME based dispatches. You should specify only the ones that you need. */ } catch (e: IntentFilter.MalformedMimeTypeException) { throw RuntimeException("fail", e) } } intentFiltersArray = arrayOf(ndef)
Java
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); try { ndef.addDataType("*/*"); /* Handles all MIME based dispatches. You should specify only the ones that you need. */ } catch (MalformedMimeTypeException e) { throw new RuntimeException("fail", e); } intentFiltersArray = new IntentFilter[] {ndef, };
- מגדירים מערך של טכנולוגיות תגים שהאפליקציה שלכם רוצה לטפל בהן. קוראים לפונקציה
השיטה
Object.class.getName()
כדי לקבל את הסיווג של הטכנולוגיה שרוצים לתמוך.Kotlin
techListsArray = arrayOf(arrayOf<String>(NfcF::class.java.name))
Java
techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
- יצירת אובייקט
- ביטול הקריאות החוזרות הבאות במחזור החיים של הפעילות והוספת לוגיקה להפעלה ולהשבתה של
שליחה בחזית כשהפעילות מאבדת (
onPause()
) ומחזיר את המיקוד (onResume()
). הקריאה אלenableForegroundDispatch()
חייבת להיות מ: ה-thread הראשי, ורק כשהפעילות היא בחזית (קריאה ל-onResume()
מבטיחה זאת). כמו כן, צריך להטמיע את הקריאה החוזרת שלonNewIntent
כדי לעבד את הנתונים מסריקת ה-NFC הסרוקה התיוג.
Kotlin
public override fun onPause() { super.onPause() adapter.disableForegroundDispatch(this) } public override fun onResume() { super.onResume() adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray) } public override fun onNewIntent(intent: Intent) { val tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) // do something with tagFromIntent }
Java
public void onPause() { super.onPause(); adapter.disableForegroundDispatch(this); } public void onResume() { super.onResume(); adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray); } public void onNewIntent(Intent intent) { Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); // do something with tagFromIntent }