אינטראקציה עם מכשירי NFC ב-Chrome ל-Android

עכשיו אפשר לקרוא ולכתוב בתגי NFC.

François Beaufort
François Beaufort

מה זה Web NFC?

NFC הוא קיצור של Near Field Communications (תקשורת מטווח קצר), טכנולוגיה אלחוטית ברזולוציית 13.56MHz שמאפשרת תקשורת בין מכשירים במרחק של פחות מ-10 ס"מ עם קצב שידור של עד 424 קילובייט לשנייה.

באמצעות NFC באינטרנט אפשר לקרוא ולכתוב תגי NFC כשהם קרובים למכשיר של המשתמש (בדרך כלל 5 עד 10 ס"מ או 2 עד 4 אינץ'). ההיקף הנוכחי מוגבל לפורמט NFC Data Exchange (NDEF), שהוא פורמט קליל של הודעות בינאריות שפועל בפורמטים שונים של תגים.

הטלפון מפעיל תג NFC כדי לשלוח ולקבל נתונים
תרשים של פעולת NFC

תרחישים לדוגמה

NFC באינטרנט מוגבל ל-NDEF כי קל יותר לכמת את מאפייני האבטחה של קריאה וכתיבה של נתוני NDEF. אין תמיכה בפעולות קלט/פלט ברמה נמוכה (כמו ISO-DEP, NFC-A/B, NFC-F), מצב תקשורת מקצה לקצה (P2P) ואמולציה של כרטיסים מבוססי מארח (HCE).

דוגמאות לאתרים שעשויים להשתמש ב-Web NFC:

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

הסטטוס הנוכחי

שלב סטטוס
1. יצירת הסבר הושלם
2. יצירת טיוטה ראשונית של מפרט הושלם
3. אוספים משוב וחוזרים על העיצוב הושלם
4. גרסת מקור לניסיון הושלם
5. הפעלה הושלם

שימוש ב-Web NFC

זיהוי תכונות

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

if ('NDEFReader' in window) { /* Scan and write NFC tags */ }

הסברים על המונחים

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

תמונה של תג NFC שקוף
תג NFC שקוף

האובייקט NDEFReader הוא נקודת הכניסה ב-Web NFC שחושפת פונקציונליות של הכנה של קריאה ו/או כתיבה שאפשר למלא כשמתקבל תג NDEF בקרבת מקום. NDEF ב-NDEFReader הם ראשי תיבות של NFC Data Exchange Format (פורמט NFC Data Exchange), פורמט בינארי קליל של הודעות, שמאושר על ידי פורום NFC.

האובייקט NDEFReader פועל בתגובה להודעות NDEF נכנסות מתגי NFC ולכתיבת הודעות NDEF לתגי NFC בטווח.

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

תרשים של הודעת NDEF
תרשים של הודעת NDEF

סריקת תגי NFC

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

  • היא הופעלה רק בתגובה לתנועה של משתמש כמו תנועת מגע או לחיצת עכבר.
  • המשתמש אפשר לאתר לקיים אינטראקציה עם מכשירי NFC.
  • הטלפון של המשתמש תומך בטכנולוגיית NFC.
  • המשתמש הפעיל את ה-NFC בטלפון שלו.

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

const ndef = new NDEFReader();
ndef.scan().then(() => {
  console.log("Scan started successfully.");
  ndef.onreadingerror = () => {
    console.log("Cannot read data from the NFC tag. Try another one?");
  };
  ndef.onreading = event => {
    console.log("NDEF message read.");
  };
}).catch(error => {
  console.log(`Error! Scan failed to start: ${error}.`);
});

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

  • serialNumber מייצג את המספר הסידורי של המכשיר (למשל, 00-11-22-33-44-55-66), או מחרוזת ריקה אם אין אף מחרוזת זמינה.
  • message מייצג את הודעת ה-NDEF ששמורה בתג ה-NFC.

כדי לקרוא את התוכן של הודעת ה-NDEF בלולאה, עוברים message.records בלולאה ומעבדים את data החברים שלהם באופן הולם בהתאם לrecordType שלהם. החבר data חשוף בתור DataView כי הוא מאפשר טיפול במקרים שבהם הנתונים מקודדים ב-UTF-16.

ndef.onreading = event => {
  const message = event.message;
  for (const record of message.records) {
    console.log("Record type:  " + record.recordType);
    console.log("MIME type:    " + record.mediaType);
    console.log("Record id:    " + record.id);
    switch (record.recordType) {
      case "text":
        // TODO: Read text record with record data, lang, and encoding.
        break;
      case "url":
        // TODO: Read URL record with record data.
        break;
      default:
        // TODO: Handle other records with record data.
    }
  }
};

כתיבת תגי NFC

כדי לכתוב תגי NFC, קודם צריך ליצור אובייקט NDEFReader חדש. התקשרות אל write() תחזיר את ההבטחה. אם לא ניתנה גישה בעבר, יכול להיות שהמשתמש יתבקש לבחור. בשלב הזה, הודעת NDEF במצב 'מוכן' וההתחייבות תיסגר אם כל התנאים הבאים יתקיימו:

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

כדי לכתוב טקסט לתג NFC, צריך להעביר מחרוזת לשיטה write().

const ndef = new NDEFReader();
ndef.write(
  "Hello World"
).then(() => {
  console.log("Message written.");
}).catch(error => {
  console.log(`Write failed :-( try again: ${error}.`);
});

כדי לכתוב רשומה של כתובת URL בתג NFC, צריך להעביר אל write() מילון שמייצג הודעת NDEF. בדוגמה הבאה, הודעת NDEF היא מילון עם מפתח records. הערך שלו הוא מערך של רשומות – במקרה הזה, רשומת כתובת URL שמוגדרת כאובייקט עם מפתח recordType שמוגדר ל-"url" ומפתח data מוגדר למחרוזת של כתובת ה-URL.

const ndef = new NDEFReader();
ndef.write({
  records: [{ recordType: "url", data: "https://w3c.github.io/web-nfc/" }]
}).then(() => {
  console.log("Message written.");
}).catch(error => {
  console.log(`Write failed :-( try again: ${error}.`);
});

יש גם אפשרות לכתוב כמה רשומות בתג NFC.

const ndef = new NDEFReader();
ndef.write({ records: [
    { recordType: "url", data: "https://w3c.github.io/web-nfc/" },
    { recordType: "url", data: "https://web.dev/nfc/" }
]}).then(() => {
  console.log("Message written.");
}).catch(error => {
  console.log(`Write failed :-( try again: ${error}.`);
});

אם תג ה-NFC מכיל הודעת NDEF שלא מיועדת להחלפה, מגדירים את המאפיין overwrite לערך false באפשרויות שמועברות ל-method write(). במקרה כזה, ההבטחה שמוחזרת תידחה אם הודעת NDEF כבר שמורה בתג ה-NFC.

const ndef = new NDEFReader();
ndef.write("Writing data on an empty NFC tag is fun!", { overwrite: false })
.then(() => {
  console.log("Message written.");
}).catch(error => {
  console.log(`Write failed :-( try again: ${error}.`);
});

הגדרת תגי NFC לקריאה בלבד

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

כדי להפוך תגי NFC לקריאה בלבד, קודם צריך ליצור אובייקט NDEFReader חדש. התקשרות אל makeReadOnly() תחזיר את ההבטחה. אם לא ניתנה גישה בעבר, יכול להיות שהמשתמש יתבקש לבחור. ההבטחה תיפתר אם כל התנאים הבאים יתקיימו:

  • היא הופעלה רק בתגובה לתנועה של משתמש כמו תנועת מגע או לחיצת עכבר.
  • המשתמש אפשר לאתר לקיים אינטראקציה עם מכשירי NFC.
  • הטלפון של המשתמש תומך בטכנולוגיית NFC.
  • המשתמש הפעיל את ה-NFC בטלפון שלו.
  • המשתמש הקיש על תג NFC ותג ה-NFC הוגדר בהצלחה לקריאה בלבד.
const ndef = new NDEFReader();
ndef.makeReadOnly()
.then(() => {
  console.log("NFC tag has been made permanently read-only.");
}).catch(error => {
  console.log(`Operation failed: ${error}`);
});

כך מגדירים תג NFC לקריאה בלבד אחרי שכותבים בו באופן קבוע.

const ndef = new NDEFReader();
try {
  await ndef.write("Hello world");
  console.log("Message written.");
  await ndef.makeReadOnly();
  console.log("NFC tag has been made permanently read-only after writing to it.");
} catch (error) {
  console.log(`Operation failed: ${error}`);
}

makeReadOnly() זמין ב-Android בגרסה 100 ואילך של Chrome, ולכן כדאי לבדוק אם התכונה הזו נתמכת בדרכים הבאות:

if ("NDEFReader" in window && "makeReadOnly" in NDEFReader.prototype) {
  // makeReadOnly() is supported.
}

אבטחה והרשאות

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

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

צילום מסך של בקשה ל-NFC באינטרנט באתר
הודעה למשתמש בנושא NFC באינטרנט

NFC באינטרנט זמין רק למסגרות ברמה העליונה ולהקשרי גלישה מאובטחת (HTTPS בלבד). המקורות צריכים לבקש תחילה את ההרשאה "nfc" בזמן טיפול בתנועת משתמש (למשל, לחיצה על לחצן). השיטות NDEFReader scan(), write() ו-makeReadOnly() מפעילות בקשה למשתמש, אם לא ניתנה גישה בעבר.

  document.querySelector("#scanButton").onclick = async () => {
    const ndef = new NDEFReader();
    // Prompt user to allow website to interact with NFC devices.
    await ndef.scan();
    ndef.onreading = event => {
      // TODO: Handle incoming NDEF messages.
    };
  };

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

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

הודות ל-Page Visibility API, אפשר לעקוב אחרי שינויים בחשיפה של המסמכים.

document.onvisibilitychange = event => {
  if (document.hidden) {
    // All NFC operations are automatically suspended when document is hidden.
  } else {
    // All NFC operations are resumed, if needed.
  }
};

ספר המתכונים

הנה כמה דוגמאות קוד שיעזרו לכם להתחיל.

בדיקת ההרשאה

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

const ndef = new NDEFReader();

async function startScanning() {
  await ndef.scan();
  ndef.onreading = event => {
    /* handle NDEF messages */
  };
}

const nfcPermissionStatus = await navigator.permissions.query({ name: "nfc" });
if (nfcPermissionStatus.state === "granted") {
  // NFC access was previously granted, so we can start NFC scanning now.
  startScanning();
} else {
  // Show a "scan" button.
  document.querySelector("#scanButton").style.display = "block";
  document.querySelector("#scanButton").onclick = event => {
    // Prompt user to allow UA to send and receive info when they tap NFC devices.
    startScanning();
  };
}

ביטול פעולות NFC

אם משתמשים בגרסה הראשונית של AbortController, קל לבטל פעולות NFC. הדוגמה הבאה ממחישה איך להעביר את ה-signal של AbortController דרך האפשרויות של NDEFReader scan(), makeReadOnly(), write() ולבטל את שתי פעולות ה-NFC בו-זמנית.

const abortController = new AbortController();
abortController.signal.onabort = event => {
  // All NFC operations have been aborted.
};

const ndef = new NDEFReader();
await ndef.scan({ signal: abortController.signal });

await ndef.write("Hello world", { signal: abortController.signal });
await ndef.makeReadOnly({ signal: abortController.signal });

document.querySelector("#abortButton").onclick = event => {
  abortController.abort();
};

קריאה אחרי כתיבה

אם משתמשים ב-write() ואז ב-scan() עם התג AbortController, אפשר לקרוא תג NFC אחרי שכותבים בו הודעה. הדוגמה הבאה מראה איך לכתוב הודעת טקסט בתג NFC ולקרוא את ההודעה החדשה בתג ה-NFC. הסריקה מפסיקה אחרי שלוש שניות.

// Waiting for user to tap NFC tag to write to it...
const ndef = new NDEFReader();
await ndef.write("Hello world");
// Success! Message has been written.

// Now scanning for 3 seconds...
const abortController = new AbortController();
await ndef.scan({ signal: abortController.signal });
const message = await new Promise((resolve) => {
  ndef.onreading = (event) => resolve(event.message);
});
// Success! Message has been read.

await new Promise((r) => setTimeout(r, 3000));
abortController.abort();
// Scanning is now stopped.

קריאה וכתיבה של רשומת טקסט

אפשר לפענח את רשומת הטקסט data באמצעות יצירת מופע TextDecoder באמצעות המאפיין של הרשומה encoding. שימו לב שהשפה של רשומת הטקסט זמינה באמצעות המאפיין lang שלה.

function readTextRecord(record) {
  console.assert(record.recordType === "text");
  const textDecoder = new TextDecoder(record.encoding);
  console.log(`Text: ${textDecoder.decode(record.data)} (${record.lang})`);
}

כדי לכתוב רשומת טקסט פשוטה, צריך להעביר מחרוזת לשיטה write() של NDEFReader.

const ndef = new NDEFReader();
await ndef.write("Hello World");

רשומות טקסט הן UTF-8 כברירת מחדל, ומתבססת על ההנחה ששפת המסמך הנוכחי, אבל אפשר לציין את שני המאפיינים (encoding ו-lang) באמצעות התחביר המלא ליצירת רשומת NDEF מותאמת אישית.

function a2utf16(string) {
  let result = new Uint16Array(string.length);
  for (let i = 0; i < string.length; i++) {
    result[i] = string.codePointAt(i);
  }
  return result;
}

const textRecord = {
  recordType: "text",
  lang: "fr",
  encoding: "utf-16",
  data: a2utf16("Bonjour, François !")
};

const ndef = new NDEFReader();
await ndef.write({ records: [textRecord] });

קריאה וכתיבה של רשומת כתובת URL

משתמשים ב-TextDecoder כדי לפענח את ה-data של הרשומה.

function readUrlRecord(record) {
  console.assert(record.recordType === "url");
  const textDecoder = new TextDecoder();
  console.log(`URL: ${textDecoder.decode(record.data)}`);
}

כדי לכתוב רשומה של כתובת URL, מעבירים מילון הודעות של NDEF ל-method write() של NDEFReader. רשומת ה-URL שכלולה בהודעת ה-NDEF מוגדרת כאובייקט, עם מפתח recordType שמוגדר ל-"url" ומפתח data שמוגדר למחרוזת ה-URL.

const urlRecord = {
  recordType: "url",
  data:"https://w3c.github.io/web-nfc/"
};

const ndef = new NDEFReader();
await ndef.write({ records: [urlRecord] });

קריאה וכתיבה של רשומה מסוג MIME

המאפיין mediaType ברשומה מסוג MIME מייצג את סוג ה-MIME של המטען הייעודי (payload) של רשומות NDEF, כדי שאפשר יהיה לפענח את data כראוי. לדוגמה, אפשר להשתמש ב-JSON.parse כדי לפענח טקסט JSON וברכיב תמונה כדי לפענח נתוני תמונה.

function readMimeRecord(record) {
  console.assert(record.recordType === "mime");
  if (record.mediaType === "application/json") {
    const textDecoder = new TextDecoder();
    console.log(`JSON: ${JSON.parse(decoder.decode(record.data))}`);
  }
  else if (record.mediaType.startsWith('image/')) {
    const blob = new Blob([record.data], { type: record.mediaType });
    const img = new Image();
    img.src = URL.createObjectURL(blob);
    document.body.appendChild(img);
  }
  else {
    // TODO: Handle other MIME types.
  }
}

כדי לכתוב רשומה מסוג MIME, יש להעביר מילון הודעות של NDEF לשיטה write() של NDEFReader. רשומת סוג MIME שכלולה בהודעת NDEF מוגדרת כאובייקט עם מפתח recordType שמוגדר ל-"mime", מפתח mediaType שמוגדר לסוג MIME בפועל של התוכן, ומפתח data שמוגדר לאובייקט שיכול להיות ArrayBuffer או מספק תצוגת ArrayBuffer (למשל Uint8Array, DataView).

const encoder = new TextEncoder();
const data = {
  firstname: "François",
  lastname: "Beaufort"
};
const jsonRecord = {
  recordType: "mime",
  mediaType: "application/json",
  data: encoder.encode(JSON.stringify(data))
};

const imageRecord = {
  recordType: "mime",
  mediaType: "image/png",
  data: await (await fetch("icon1.png")).arrayBuffer()
};

const ndef = new NDEFReader();
await ndef.write({ records: [jsonRecord, imageRecord] });

קריאה וכתיבה של רשומה של כתובת URL מוחלטת

אפשר לפענח את הרשומה של כתובת ה-URL המוחלטת data באמצעות TextDecoder פשוט.

function readAbsoluteUrlRecord(record) {
  console.assert(record.recordType === "absolute-url");
  const textDecoder = new TextDecoder();
  console.log(`Absolute URL: ${textDecoder.decode(record.data)}`);
}

כדי לכתוב רשומה של כתובת URL מוחלטת, צריך להעביר מילון הודעות NDEF ל-method write() של NDEFReader. הרשומה של כתובת ה-URL המוחלטת בהודעת NDEF מוגדרת כאובייקט עם מפתח recordType שמוגדר ל-"absolute-url" ומפתח data מוגדר למחרוזת של כתובת ה-URL.

const absoluteUrlRecord = {
  recordType: "absolute-url",
  data:"https://w3c.github.io/web-nfc/"
};

const ndef = new NDEFReader();
await ndef.write({ records: [absoluteUrlRecord] });

קריאה וכתיבה של רשומה של פוסטר חכם

רשומת פוסטר חכמה (שמשמשת בפרסומות של כתבי עת, עלונים, שלטי חוצות וכו') מתארת תוכן מסוים באינטרנט כרשומת NDEF שמכילה הודעת NDEF בתור המטען הייעודי (payload). קוראים לפונקציה record.toRecords() כדי להפוך את data לרשימת רשומות שכלולות ברשומת הפוסטר החכם. היא צריכה לכלול רשומה של כתובת URL, רשומת טקסט לכותרת, רשומה מסוג MIME לתמונה וכמה רשומות מותאמות אישית מסוג מקומי כמו ":t", ":act" ו-":s", בהתאמה לסוג, לפעולה ולגודל של רשומת הפוסטר החכם.

רשומות מסוג מקומי ייחודיות רק בהקשר המקומי של רשומת ה-NDEF שמכילה. כדאי להשתמש בהם כשהמשמעות של הסוגים לא חשובה מחוץ להקשר המקומי של הרשומה שמכילה, וכשהשימוש באחסון מהווה מגבלות מחמירות. שמות של רשומות מסוג מקומי תמיד מתחילים ב-: ב-Web NFC (למשל ":t", ":s", ":act"). ההבדל בין רשומת טקסט לבין רשומת טקסט מסוג מקומי הוא למשל.

function readSmartPosterRecord(smartPosterRecord) {
  console.assert(record.recordType === "smart-poster");
  let action, text, url;

  for (const record of smartPosterRecord.toRecords()) {
    if (record.recordType == "text") {
      const decoder = new TextDecoder(record.encoding);
      text = decoder.decode(record.data);
    } else if (record.recordType == "url") {
      const decoder = new TextDecoder();
      url = decoder.decode(record.data);
    } else if (record.recordType == ":act") {
      action = record.data.getUint8(0);
    } else {
      // TODO: Handle other type of records such as `:t`, `:s`.
    }
  }

  switch (action) {
    case 0:
      // Do the action
      break;
    case 1:
      // Save for later
      break;
    case 2:
      // Open for editing
      break;
  }
}

כדי לכתוב רשומה של פוסטר חכם, צריך להעביר הודעת NDEF ל-method write() של NDEFReader. רשומת הפוסטר החכם שכלולה בהודעת NDEF מוגדרת כאובייקט עם מפתח recordType שמוגדר ל-"smart-poster" ומפתח data שמוגדר לאובייקט שמייצג (פעם נוספת) הודעת NDEF שכלולה ברשומת הפוסטר החכם.

const encoder = new TextEncoder();
const smartPosterRecord = {
  recordType: "smart-poster",
  data: {
    records: [
      {
        recordType: "url", // URL record for smart poster content
        data: "https://my.org/content/19911"
      },
      {
        recordType: "text", // title record for smart poster content
        data: "Funny dance"
      },
      {
        recordType: ":t", // type record, a local type to smart poster
        data: encoder.encode("image/gif") // MIME type of smart poster content
      },
      {
        recordType: ":s", // size record, a local type to smart poster
        data: new Uint32Array([4096]) // byte size of smart poster content
      },
      {
        recordType: ":act", // action record, a local type to smart poster
        // do the action, in this case open in the browser
        data: new Uint8Array([0])
      },
      {
        recordType: "mime", // icon record, a MIME type record
        mediaType: "image/png",
        data: await (await fetch("icon1.png")).arrayBuffer()
      },
      {
        recordType: "mime", // another icon record
        mediaType: "image/jpg",
        data: await (await fetch("icon2.jpg")).arrayBuffer()
      }
    ]
  }
};

const ndef = new NDEFReader();
await ndef.write({ records: [smartPosterRecord] });

קריאה וכתיבה של רשומת סוג חיצונית

כדי ליצור רשומות שהוגדרו על ידי האפליקציה, צריך להשתמש ברשומות מסוג חיצוני. הקבצים האלה עשויים להכיל הודעת NDEF כמטען ייעודי (payload) שאפשר לגשת אליה באמצעות toRecords(). השם שלהם כולל את שם הדומיין של הארגון המנפיק, נקודתיים ושם סוג באורך של לפחות תו אחד, למשל "example.com:foo".

function readExternalTypeRecord(externalTypeRecord) {
  for (const record of externalTypeRecord.toRecords()) {
    if (record.recordType == "text") {
      const decoder = new TextDecoder(record.encoding);
      console.log(`Text: ${textDecoder.decode(record.data)} (${record.lang})`);
    } else if (record.recordType == "url") {
      const decoder = new TextDecoder();
      console.log(`URL: ${decoder.decode(record.data)}`);
    } else {
      // TODO: Handle other type of records.
    }
  }
}

כדי לכתוב רשומה מסוג חיצוני, מעבירים מילון הודעות של NDEF ל-method write() של NDEFReader. רשומת הסוג החיצוני שכלולה בהודעת NDEF מוגדרת כאובייקט עם מפתח recordType שמוגדר לשם הסוג החיצוני, ומפתח data שמוגדר לאובייקט שמייצג הודעת NDEF שכלולה ברשומת הסוג החיצוני. שימו לב שהמפתח data יכול להיות גם ArrayBuffer או מספק תצוגה של ArrayBuffer (למשל Uint8Array, DataView).

const externalTypeRecord = {
  recordType: "example.game:a",
  data: {
    records: [
      {
        recordType: "url",
        data: "https://example.game/42"
      },
      {
        recordType: "text",
        data: "Game context given here"
      },
      {
        recordType: "mime",
        mediaType: "image/png",
        data: await (await fetch("image.png")).arrayBuffer()
      }
    ]
  }
};

const ndef = new NDEFReader();
ndef.write({ records: [externalTypeRecord] });

קריאה וכתיבה של רשומה ריקה

לרשומה ריקה אין מטען ייעודי (payload).

כדי לכתוב רשומה ריקה, מעבירים מילון הודעות של NDEF ל-method write() של NDEFReader. הרשומה הריקה בהודעת NDEF מוגדרת כאובייקט עם מפתח recordType שמוגדר ל-"empty".

const emptyRecord = {
  recordType: "empty"
};

const ndef = new NDEFReader();
await ndef.write({ records: [emptyRecord] });

תמיכת דפדפן

NFC באינטרנט זמין ב-Android ב-Chrome 89.

טיפים למפתחים

הנה רשימה של הדברים שהייתי רוצה לדעת כשהתחלתי לשחק עם NFC באינטרנט:

  • מערכת Android מטפלת בתגי NFC ברמת מערכת ההפעלה לפני ש-Web NFC פועל.
  • תוכלו למצוא סמל NFC ב-material.io.
  • אפשר להשתמש ברשומת NDEF id כדי לזהות רשומה בקלות במקרה הצורך.
  • תג NFC לא מעוצב שתומך ב-NDEF מכיל רשומה יחידה מהסוג הריק.
  • קל לכתוב רשומה של אפליקציית Android, כפי שמתואר בהמשך.
const encoder = new TextEncoder();
const aarRecord = {
  recordType: "android.com:pkg",
  data: encoder.encode("com.example.myapp")
};

const ndef = new NDEFReader();
await ndef.write({ records: [aarRecord] });

הדגמות

כדאי לך לנסות את הדוגמה הרשמית ולצפות בהדגמות מגניבות של NFC באינטרנט:

הדגמה של כרטיסי ה-NFC באינטרנט ב-Chrome Dev Summit 2019

משוב

קבוצת קהילת ה-NFC באינטרנט והצוות של Chrome ישמחו לשמוע מה דעתכם על חוויית השימוש ב-NFC באינטרנט.

לספר לנו על עיצוב ה-API

האם יש משהו ב-API שלא פועל כצפוי? או האם יש שיטות או מאפיינים חסרים שאתם צריכים כדי ליישם את הרעיון?

שלחו בעיה במפרט במאגר GitHub באינטרנט או הוסיפו את דעתכם לבעיה קיימת.

דיווח על בעיה בהטמעה

האם מצאת באג בהטמעה של Chrome? או שההטמעה שונה מהמפרט?

אפשר לדווח על באג בכתובת https://new.crbug.com. חשוב לכלול כמה שיותר פרטים, לספק הוראות פשוטות לשחזור הבאג ולהגדיר את הרכיבים ל-Blink>NFC. גליץ' הוא כלי מעולה לשיתוף גיבויים מהירים וקלים.

הבעת תמיכה

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

שלח ציוץ אל @ChromiumDev באמצעות ה-hashtag #WebNFC וספר לנו איפה אתם משתמשים בו ואיך אתם משתמשים בו.

קישורים שימושיים

אישורים

תודה רבה לאנשים ב-Intel על ההטמעה של Web NFC. השימוש ב-Google Chrome תלוי בקהילה של צוותים שעובדים יחד כדי לקדם את פרויקט Chromium. לא כל המשתמשים ב-Chromium הם גוגלרים, ולתורמים האלה מגיע הכרה מיוחדת!