העקרונות הבסיסיים של NFC

במסמך הזה מתוארות הפעולות הבסיסיות של NFC שאפשר לבצע ב-Android. במאמר מוסבר איך לשלוח ולקבל נתוני NFC בצורת הודעות NDEF, ומתוארים ממשקי ה-API של Android framework שתומכים בתכונות האלה. לנושאים מתקדמים יותר, כולל דיון על עבודה עם נתונים שאינם NDEF, תוכלו לעיין במאמר NFC מתקדם.

הקריאה של נתוני NDEF מתג NFC מתבצעת באמצעות מערכת שליחת התגים, שמנתחת את תגי ה-NFC שזוהו, מסווגת את הנתונים בצורה מתאימה ומפעילה אפליקציה שמתעניינת בנתונים המסווגים. אפליקציה שרוצה לטפל בתג ה-NFC שנסרק יכולה להצהיר על מסנן Intent ולבקש לטפל בנתונים.

מערכת השליחה של התגים

מכשירי Android מחפשים בדרך כלל תגי NFC כשהמסך לא נעול, אלא אם ה-NFC מושבת בתפריט ההגדרות של המכשיר. כשמכשיר מבוסס Android מזהה תג NFC, ההתנהגות הרצויה היא שהפעילות המתאימה ביותר תטפל בכוונה, בלי לבקש מהמשתמש באיזו אפליקציה להשתמש. מכיוון שהמכשירים סורקים תגי NFC לטווח קצר מאוד, סביר להניח שכשמשתמשים יצטרכו לבחור פעילות באופן ידני, הם ייאלצו להרחיק את המכשיר מהתג ולנתק את החיבור. עליך לפתח את הפעילות כך שתטפל רק בתגי ה-NFC שחשובים לפעילות שלך, כדי למנוע את ההופעה של 'בורר הפעילויות'.

כדי לעזור לכם במשימה הזו, מערכת Android מספקת מערכת מיוחדת לשליחת תגים, שמנתחת תגי NFC סרוקים, מנתחת אותם ומנסה לאתר אפליקציות שמתעניינות בנתונים הסרוקים. כדי לעשות זאת, הוא:

  1. ניתוח של תג ה-NFC וזיהוי סוג ה-MIME או ה-URI שמזהה את המטען הייעודי (payload) של הנתונים בתג.
  2. אנקפסולציה של סוג ה-MIME או ה-URI ושל עומס העבודה (payload) בתוך כוונה (intent). שני השלבים הראשונים מתוארים בקטע איך תגי NFC ממופה לסוגי MIME ולמזהי URI.
  3. הפעלת פעילות על סמך הכוונה. המידע הזה מפורט בקטע איך תגי NFC מועברים לאפליקציות.

איך תגי NFC ממפים לסוגי MIME ול-URI

לפני שמתחילים לכתוב אפליקציות NFC, חשוב להבין את הסוגים השונים של תגי NFC, את האופן שבו מערכת שליחת התגים מנתחת תגי NFC ואת הפעולה המיוחדת שמערכת שליחת התגים מבצעת כשהיא מזהה הודעת NDEF. תגי NFC מגיעים במגוון רחב של טכנולוגיות, ואפשר גם לכתוב עליהם נתונים בדרכים רבות ושונות. מערכת Android מספקת הכי הרבה תמיכה בתקן NDEF, שמוגדר בפורום NFC.

נתוני NDEF נארזים בתוך הודעה (NdefMessage) שמכילה רשומה אחת או יותר (NdefRecord). כל רשומת NDEF חייבת להיות בפורמט תקין בהתאם למפרט של סוג הרשומה שרוצים ליצור. Android תומך גם בסוגים אחרים של תגים שלא מכילים נתוני NDEF. אפשר לעבוד עם התגים האלה באמצעות הכיתות בחבילה android.nfc.tech. למידע נוסף על הטכנולוגיות האלה, ראו את הנושא NFC מתקדם. כדי לעבוד עם סוגי התגים האחרים האלה, צריך לכתוב מחסנית פרוטוקול משלכם כדי לתקשר עם התגים. לכן מומלץ להשתמש ב-NDEF כשאפשר, כדי להקל על הפיתוח ולקבל תמיכה מרבית במכשירים מבוססי Android.

הערה: כדי להוריד את המפרטים המלאים של NDEF, אפשר להיכנס לאתר NFC Forum Specifications & Application Documents ולעיין במאמר יצירת סוגים נפוצים של רשומות NDEF כדי לקבל דוגמאות ליצירת רשומות NDEF.

עכשיו, אחרי שקיבלתם רקע על תגי NFC, בקטעים הבאים נסביר בפירוט איך Android מטפלת בתגים בפורמט NDEF. כשמכשיר עם Android סורק תג NFC שמכיל נתונים בפורמט NDEF, הוא מנתח את ההודעה ומנסה לזהות את סוג ה-MIME או את מזהה ה-URI של הנתונים. כדי לעשות זאת, המערכת קוראת את ה-NdefRecord הראשון בתוך ה-NdefMessage כדי לקבוע איך לפרש את הודעת ה-NDEF כולה (הודעת NDEF יכולה לכלול כמה רשומות NDEF). בהודעת NDEF תקינה, השדה NdefRecord הראשון מכיל את השדות הבאים:

TNF (פורמט שם טיפוס) של 3 ביט
מציין איך לפרש את שדה סוג האורך של המשתנה. הערכים החוקיים מתוארים בטבלה 1.
סוג אורך משתנה
תיאור הסוג של הרשומה. אם משתמשים ב-TNF_WELL_KNOWN, צריך להשתמש בשדה הזה כדי לציין את הערך Record Type Definition (RTD). ערכי RTD חוקיים מתוארים בטבלה 2.
מזהה אורך משתנה
מזהה ייחודי של הרשומה. לא נעשה שימוש בשדה הזה לעיתים קרובות, אבל אם אתם צריכים לזהות תג באופן ייחודי, תוכלו ליצור לו מזהה.
מטען נתונים באורך משתנה
מטען הייעודי (payload) בפועל של הנתונים שרוצים לקרוא או לכתוב. הודעת NDEF יכולה להכיל כמה רשומות NDEF, לכן אל תניחו שהמטען המועיל המלא נמצא ברשומת NDEF הראשונה של הודעת ה-NDEF.

מערכת שליחת התגים משתמשת בשדות TNF ו-type כדי לנסות למפות סוג MIME או URI להודעת NDEF. אם הפעולה מצליחה, היא עוטפת את המידע הזה בתוך כוונה (intent) מסוג ACTION_NDEF_DISCOVERED יחד עם עומס העבודה בפועל. אבל יש מקרים שבהם מערכת שליחת התגים לא יכולה לקבוע את סוג הנתונים על סמך רשומת ה-NDEF הראשונה. זה קורה כשלא ניתן למפות את נתוני NDEF לסוג MIME או URI, או כאשר התג NFC לא מכיל נתוני NDEF מלכתחילה. במקרים כאלה, אובייקט Tag שמכיל מידע על הטכנולוגיות של התג ועל המטען הייעודי (Payload) נכלל ב-Intent מסוג ACTION_TECH_DISCOVERED.

טבלה 1 מתארת איך מערכת שליחת התגים ממפה שדות TNF וסוגי שדות לסוגי MIME או למזהי URI. בנוסף, מוסבר אילו TNF לא ניתן למפות לסוג MIME או ל-URI. במקרים כאלה, מערכת השליחה של התגים חוזרת ל-ACTION_TECH_DISCOVERED.

לדוגמה, אם מערכת שליחת התגים נתקלת ברשומה מסוג TNF_ABSOLUTE_URI, היא ממפה את שדה סוג האורך המשתנה של הרשומה הזו ל-URI. מערכת השליחה של התגים עוטפת את ה-URI הזה בשדה הנתונים של כוונה ACTION_NDEF_DISCOVERED, יחד עם מידע נוסף על התג, כמו עומס העבודה. לעומת זאת, אם המערכת נתקלת ברשומה מסוג TNF_UNKNOWN, היא יוצרת כוונה שמכילה את הטכנולוגיות של התג במקום זאת.

טבלה 1. TNF נתמכים והמיפויים שלהם

Type Name Format (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) בשדה type. מידע נוסף על מדדי 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 מבוסס על מטען ייעודי (payload).

איך תגי NFC מועברים לאפליקציות

כשמערכת שליחת התגים מסיימת ליצור כוונה שמכילה את תג ה-NFC ואת פרטי הזיהוי שלו, היא שולחת את הכוונה לאפליקציה שמתעניינת בכך ומסננת את הכוונה. אם יש יותר מאפליקציה אחת שיכולה לטפל ב-Intent, מוצג בורר הפעילויות כדי שהמשתמש יוכל לבחור את הפעילות. מערכת השליחה של התגים מגדירה שלושה כוונות, שמפורטות לפי סדר העדיפות הגבוה ביותר לנמוך ביותר:

  1. ACTION_NDEF_DISCOVERED: ה-intent הזה משמש להפעלת פעילות כשנסרק תג שמכיל עומס נתונים של NDEF והוא מסוג מוכר. זאת ה-Intent בעדיפות הגבוהה ביותר, ומערכת שליחת התגים תנסה להתחיל פעילות עם כוונת הרכישה הזו לפני כל כוונה אחרת, כשהדבר יתאפשר.
  2. ACTION_TECH_DISCOVERED: אם לא נרשמו פעילויות לטיפול בכוונה ACTION_NDEF_DISCOVERED, מערכת שליחת התגים תנסה להפעיל אפליקציה עם הכוונה הזו. הכוונה הזו מופעלת ישירות גם (בלי להפעיל קודם את ACTION_NDEF_DISCOVERED) אם התג שנסרק מכיל נתוני NDEF שאי אפשר למפות לסוג MIME או ל-URI, או אם התג לא מכיל נתוני NDEF אבל הוא מתבסס על טכנולוגיית תגים ידועה.
  3. ACTION_TAG_DISCOVERED: ה-Intent הזה מתחיל אם אין פעילויות שמטפלות באובייקטים מסוג ACTION_NDEF_DISCOVERED או ACTION_TECH_DISCOVERED.

כך פועלת המערכת הבסיסית לשליחת תגים:

  1. כדאי לנסות להתחיל פעילות עם הכוונה שנוצרה על ידי מערכת שליחת התגים בזמן ניתוח תג ה-NFC (ACTION_NDEF_DISCOVERED או ACTION_TECH_DISCOVERED).
  2. אם אין פעילות שמסננת את הכוונה הזו, מנסים להפעיל פעילות עם הכוונה הבאה ברמת העדיפות הנמוכה ביותר (ACTION_TECH_DISCOVERED או ACTION_TAG_DISCOVERED) עד שאפליקציה מסננת את הכוונה הזו או עד שמערכת שליחת התגים מנסה את כל הכוונות האפשריות.
  3. אם אף אפליקציה לא מסננת אף אחד מהכוונות, לא עושים כלום.
איור 1. מערכת שליחת תגים

כשאפשר, כדאי לעבוד עם הודעות NDEF ועם Intent מסוג ACTION_NDEF_DISCOVERED, כי זו ההודעה הספציפית ביותר מבין השלושה. הכוונה הזו מאפשרת לכם להפעיל את האפליקציה בזמן מתאים יותר משני הכוונות האחרות, וכך לספק למשתמש חוויה טובה יותר.

בקשת גישה ל-NFC במניפסט של Android

כדי לגשת לחומרת ה-NFC של המכשיר ולטפל כראוי בכוונות NFC, צריך להצהיר על הפריטים הבאים בקובץ AndroidManifest.xml:

  • הרכיב <uses-permission> של NFC כדי לגשת לחומרה של NFC:
    <uses-permission android:name="android.permission.NFC" />
    
  • גרסת ה-SDK המינימלית שהאפליקציה יכולה לתמוך בה. רמת API 9 תומכת רק בשליחת תגים מוגבלת דרך ACTION_TAG_DISCOVERED, ומספקת גישה להודעות NDEF רק דרך התוסף EXTRA_NDEF_MESSAGES. אי אפשר לגשת לתכונות אחרות של התג או לפעולות קלט/פלט. רמת 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 שאתם רוצים לטפל בו, האפליקציה יכולה לסנן את אחד, שניים או את כל שלושת הכוונות של NFC במניפסט של Android. עם זאת, בדרך כלל כדאי לסנן לפי הכוונה ACTION_NDEF_DISCOVERED כדי לשלוט בצורה הטובה ביותר במועד שבו האפליקציה תתחיל לפעול. ה-Intent ACTION_TECH_DISCOVERED הוא חלופה ל-ACTION_NDEF_DISCOVERED כשאין אפליקציות שמסננים בשביל ACTION_NDEF_DISCOVERED או כשהמטען הייעודי (payload) אינו NDEF. הסינון לפי ACTION_TAG_DISCOVERED בדרך כלל כללי מדי מקטגוריה ואי אפשר לסנן לפיה. הרבה אפליקציות יסוננו לפי ACTION_NDEF_DISCOVERED או ACTION_TECH_DISCOVERED לפני ACTION_TAG_DISCOVERED, כך שיש סבירות נמוכה שהאפליקציה תתחיל לפעול. ACTION_TAG_DISCOVERED זמין רק כחלופה אחרונה לאפליקציות לסינון, במקרים שבהם לא מותקנות אפליקציות אחרות לטיפול בכוונה ACTION_NDEF_DISCOVERED או ACTION_TECH_DISCOVERED.

פריסות של תגי NFC משתנות, ולרוב הן לא בשליטתכם, ולכן לא תמיד תוכלו לעשות זאת. לכן, במקרה הצורך, תוכלו להשתמש בשני הכוונות האחרות. אם יש לכם שליטה על סוגי התגים והנתונים שנכתבים, מומלץ להשתמש ב-NDEF כדי לעצב את התגים. בקטעים הבאים מוסבר איך לסנן לפי כל סוג של כוונת רכישה.

ACTION_NDEF_DISCOVERED

כדי לסנן לפי כוונות ACTION_NDEF_DISCOVERED, מגדירים את מסנן הכוונה יחד עם סוג הנתונים שרוצים לסנן. הדוגמה הבאה מסננת ACTION_NDEF_DISCOVERED כוונות עם סוג 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 חייבת לציין את כל השלוש, שתי הטכנולוגיות או אחת מהטכנולוגיות (ולא שום דבר נוסף) כדי שתהיה התאמה לפעילות שלך.

בדוגמה הבאה מפורטות כל הטכנולוגיות. צריך להסיר את התגים שלא נתמכים בתג ה-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 ראו עבודה עם טכנולוגיות תגים נתמכות במסמך Advanced NFC.

ACTION_TAG_DISCOVERED

כדי לסנן לפי ACTION_TAG_DISCOVERED, משתמשים בפילטר הכוונה הבא:

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

אחזור מידע מכוונות

אם פעילות מתחילה בגלל כוונה ל-NFC, אפשר לקבל מידע על תג ה-NFC שנסרק מהכוונה. כוונות יכולות להכיל את האפשרויות הנוספות הבאות, בהתאם לתג שנסרק:

  • EXTRA_TAG (חובה): אובייקט Tag שמייצג את התג שנסרק.
  • EXTRA_NDEF_MESSAGES (אופציונלי): מערך הודעות NDEF שנותחו מהתג. התוסף הזה הוא חובה ב-intents של ACTION_NDEF_DISCOVERED.
  • EXTRA_ID (אופציונלי): המזהה ברמה הנמוכה של התג.

כדי לקבל את הנתונים הנוספים האלה, צריך לבדוק אם הפעילות הופעלה באמצעות אחד מהכוונות של NFC כדי לוודא שסורקתם תג, ואז לקבל את הנתונים הנוספים מהכוונה. בדוגמה הבאה בודקים את הכוונה ACTION_NDEF_DISCOVERED ומקבלים את הודעות ה-NDEF מפריט נוסף של הכוונה.

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 שיכיל את עומס העבודה ויאפשר לכם למנות את הטכנולוגיות של התג:

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), ה-method createUri() זמינה כדי לעזור לכם ליצור רשומות URI באופן אוטומטי. החל מ-Android 4.1 (רמת API 16), createExternal() ו-createMime() זמינים כדי לעזור ליצור רשומות MIME ורשומות NDEF חיצוניות. כדאי להשתמש ב-methods העוזרות האלה ככל האפשר, כדי למנוע טעויות ביצירה ידנית של רשומות 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

אפשר ליצור רשומת 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 ובמכשירים ללא Android.

הערה: ל-URNs של 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, שהוא הערך שמוצהר על ידי מסנן הכוונה בדוגמה.

רשומות של אפליקציות ל-Android

רשומת אפליקציה ל-Android‏ (AAR) הוצגה ב-Android 4.0 (רמת API‏ 14) ומספקת ודאות גבוהה יותר שהאפליקציה תופעל כשתסרקו תג NFC. ל-AAR יש את שם החבילה של אפליקציה שמוטמעת ברשומת NDEF. אפשר להוסיף AAR לכל רשומת NDEF של הודעת ה-NDEF, כי Android מחפשת AARs בכל הודעת ה-NDEF. אם הוא מוצא קובץ AAR, הוא מפעיל את האפליקציה על סמך שם החבילה בתוך קובץ ה-AAR. אם האפליקציה לא נמצאת במכשיר, Google Play מופעל כדי להוריד את האפליקציה.

AARs שימושיים אם אתם רוצים למנוע מאפליקציות אחרות לסנן לפי אותה כוונת שימוש, וגם לטפל בתגים ספציפיים שפרסמתם. אפשר להשתמש ב-AARs רק ברמת האפליקציה, בגלל האילוץ על שם החבילה, ולא ברמת הפעילות כמו בסינון לפי כוונה. אם רוצים לטפל ב-Intent ברמת הפעילות, צריך להשתמש במסנני Intent.

אם תג מכיל AAR, מערכת שליחת התגים נשלחת באופן הבא:

  1. כדאי לנסות להתחיל פעילות באמצעות מסנן Intent כרגיל. אם הפעילות שתואמת לכוונה תואמת גם ל-AAR, מתחילים את הפעילות.
  2. אם הפעילות שמסננת את Intent לא תואמת ל-AAR, אם יש כמה פעילויות שיכולות לטפל ב-Intent, או אם אין פעילות שמטפלת ב-Intent, צריך להפעיל את האפליקציה שצוינה ב-AAR.
  3. אם אף אפליקציה לא יכולה להתחיל באמצעות ה-AAR, עוברים אל Google Play כדי להוריד את האפליקציה על סמך ה-AAR.

הערה: אפשר לשנות את ההגדרות של AAR ושל מערכת שליחת הכוונות באמצעות מערכת שליחת הכוונות בחזית, שמאפשרת לפעילות בחזית לקבל עדיפות כשמתגלה תג NFC. בשיטה הזו, הפעילות חייבת להיות בחזית כדי לבטל את ה-AAR ואת המערכת של שליחת Intent.

אם אתם עדיין רוצים לסנן לפי תגים סרוקים שלא מכילים AAR, תוכלו להצהיר על מסנני כוונה כרגיל. האפשרות הזו שימושית אם האפליקציה שלכם מתעניינת בתגים אחרים שלא מכילים 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")}
        );
)