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

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

François Beaufort
François Beaufort

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

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

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

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

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

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

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

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

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

שימוש ב-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 Forum.

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

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

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

סריקת תגי NFC

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

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

אחרי שההבטחה מתקבלת, אפשר להירשם לאירועים מסוג reading דרך מאזין אירועים כדי לקבל הודעות NDEF נכנסות. כדאי גם להירשם לאירועי 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, מעבירים מילון שמייצג הודעת NDEF אל write(). בדוגמה הבאה, הודעת ה-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 באפשרויות המועברות לשיטה 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 תכנן והטמיע את טכנולוגיית ה-Web NFC בהתאם לעקרונות הליבה שהוגדרו במאמר Controlling Access to Powerful Web Platform, כולל בקרת משתמשים, שקיפות וארגונומיה.

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

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

Web 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 והעברת תוכן 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 דרך האפשרויות של השיטות scan(), ‏ makeReadOnly() ו-write() של NDEFReader, ולבטל את שתי פעולות ה-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 ל-method 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 מוחלטת

אפשר לפענח את רשומת ה-absolute-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 לשיטה write() של NDEFReader. הרשומה absolute-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 לשיטה 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 כמטען שימושי שאפשר לגשת אליו באמצעות 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 לשיטה 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] });

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

רשומה ריקה לא מכילה מטען ייעודי.

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

const emptyRecord = {
  recordType: "empty"
};

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

תמיכה בדפדפנים

התכונה 'Web NFC' זמינה ב-Android בגרסה 89 של Chrome.

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

הנה רשימה של דברים שרציתי לדעת כשהתחלתי לשחק עם Web 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] });

הדגמות

כדאי לנסות את הדוגמה הרשמית ולראות כמה הדגמות מגניבות של Web NFC:

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

משוב

קבוצת הקהילה של Web NFC וצוות Chrome ישמחו לשמוע את דעתכם על Web NFC ואת החוויות שלכם איתו.

תיאור של עיצוב ה-API

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

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

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

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

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

הצגת תמיכה

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

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

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

אישורים

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