אינטראקציה עם מכשירי 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), מצב תקשורת מקצה לקצה (Peer) וכרטיס מבוסס מארח אין תמיכה באמולציה (HCE).

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

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

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

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

שימוש ב-NFC באינטרנט

זיהוי תכונות

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

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

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

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

סריקת תגי NFC

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

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

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

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 ב-Chrome 100 ואילך, כדאי לבדוק אם התכונה הזו נתמכת בתכונות הבאות:

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

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

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

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

צילום מסך של הודעת Web 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 ב-AI. הדוגמה הבאה מראה איך להעביר את 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})`);
}

כדי לכתוב רשומת טקסט פשוטה, מעבירים את המחרוזת ל-method 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

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

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

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

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 אל NDEFReader. אמצעי תשלום אחד (write()). רשומת סוג 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 אל שיטת NDEFReader write(). רשומת כתובת ה-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 אל NDEFReader write() . רשומת הפוסטר החכמה שכלולה בהודעת ה-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 אל שיטת NDEFReader write(). רשומת הסוג החיצונית שכלולה ב-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 ל-NDEFReader אמצעי תשלום אחד (write()). הרשומה הריקה הכלולה בהודעת NDEF מוגדרת כך: אובייקט עם מפתח recordType שמוגדר ל-"empty".

const emptyRecord = {
  recordType: "empty"
};

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

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

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

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

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

  • מערכת Android מטפלת בתגי NFC ברמת מערכת ההפעלה לפני ש-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 לשנת 2019

משוב

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

מתארים את עיצוב ה-API

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

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

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

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

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

פנייה לתמיכה

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

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

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

אישורים

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