التفاعل مع أجهزة NFC على Chrome لنظام Android

أصبح بإمكانك الآن قراءة علامات NFC والكتابة فيها.

François Beaufort
François Beaufort

ما هي تقنية Web NFC؟

‫NFC هي اختصار لـ Near Field Communications، وهي تقنية لاسلكية قصيرة المدى تعمل على تردد 13.56 ميغاهرتز وتتيح الاتصال بين الأجهزة على مسافة تقل عن 10 سم بمعدّل نقل يصل إلى 424 كيلوبت في الثانية.

توفّر تقنية Web NFC للمواقع الإلكترونية إمكانية قراءة علامات NFC وكتابتها عندما تكون بجوار جهاز المستخدم (عادةً من 5 إلى 10 سم أو من 2 إلى 4 بوصات). يقتصر النطاق الحالي على تنسيق تبادل البيانات عبر تقنية NFC (NDEF)، وهو تنسيق رسائل ثنائي بسيط يعمل مع تنسيقات العلامات المختلفة.

هاتف يشغِّل علامة NFC لتبادل البيانات
مخطّط بياني لعملية NFC

حالات الاستخدام المقترَحة

تقتصر تقنية NFC على Web على NDEF لأنّ خصائص الأمان لقراءة بيانات NDEF ونقلها يمكن قياسها بسهولة أكبر. لا تتوفّر عمليات الإدخال/الإخراج من المستوى المنخفض (مثل ISO-DEP وNFC-A/B وNFC-F) ووضع الاتصال من جهاز إلى جهاز ومحاكاة البطاقة المستندة إلى المضيف (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، وهو تنسيق رسائل ثنائي خفيف تم توحيده من قِبل NFC Forum.

يُستخدَم العنصر NDEFReader لتنفيذ إجراءات بشأن رسائل NDEF الواردة من علامات NFC وكتابة رسائل NDEF في علامات NFC ضمن النطاق.

علامة NFC المتوافقة مع NDEF تشبه ملاحظة Post-it. يمكن لأي مستخدم قراءتها، وإذا لم تكن للقراءة فقط، يمكن لأي مستخدم الكتابة فيها. يحتوي على رسالة NDEF واحدة تضمّن سجلّ NDEF واحدًا أو أكثر. كل سجلّ NDEF هو بنية ثنائية تحتوي على حمولة بيانات ومعلومات النوع المرتبطة بها. تتيح تقنية 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، يمكنك تصفُّح 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 وتم ضبطها على وضع القراءة فقط بنجاح.
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 ونفّذها باستخدام المبادئ الأساسية المحدّدة في مقالة التحكّم في الوصول إلى ميزات منصة الويب الفعّالة، بما في ذلك التحكّم الذي يمارسه المستخدم والشفافية وسهولة الاستخدام.

بما أنّ تقنية NFC توسّع نطاق المعلومات التي يمكن أن تتوفّر للمواقع الإلكترونية الضارّة، يتم حظر توفّر تقنية NFC لزيادة وعي المستخدمين والتحكّم في استخدامها إلى أقصى حد.

لقطة شاشة لطلب Web 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 مستهدَفة يعكس نمط الاختيار الذي يمكن العثور عليه في واجهات برمجة التطبيقات الأخرى للوصول إلى الملفات والأجهزة.

لإجراء عملية مسح ضوئي أو كتابة، يجب أن تكون صفحة الويب مرئية عندما يلمس المستخدم علامة 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})`);
}

لكتابة سجلّ نصي بسيط، عليك تمرير سلسلة إلى طريقة NDEFReader write().

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 إلى طريقة NDEFReader write(). يتم تعريف سجلّ عنوان 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 لحمولة سجلّ NDEF حتى يمكن فك ترميز data بشكل صحيح. على سبيل المثال، استخدِم JSON.parse لفك ترميز نص JSON وعنصر Image لفك ترميز بيانات الصورة.

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 إلى write()method 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 كحمولته. اتصل بـ 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 كحمولة يمكن الوصول إليها باستخدام 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 إلى طريقة NDEFReader write(). يتم تعريف السجلّ الفارغ الوارد في رسالة 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.

أخبِرنا عن تصميم واجهة برمجة التطبيقات.

هل هناك مشكلة في واجهة برمجة التطبيقات لا تعمل على النحو المتوقّع؟ هل هناك methods أو properties مفقودة تحتاجها لتنفيذ فكرتك؟

يمكنك الإبلاغ عن مشكلة في المواصفات على مستودع Web NFC على GitHub أو إضافة ملاحظاتك إلى مشكلة حالية.

الإبلاغ عن مشكلة في التنفيذ

هل رصدت خطأ في عملية تنفيذ Chrome؟ أم هل التنفيذ مختلف عن المواصفات؟

يمكنك إرسال بلاغ عن الخطأ على الرابط https://new.crbug.com. احرص على تضمين أكبر عدد ممكن من التفاصيل، وتقديم تعليمات بسيطة لإعادة إنتاج الخطأ، وضبط قيمة Blink>NFC في المكوّنات. تُعدّ أداة Glitch رائعة لمشاركة عمليات إعادة الإنتاج السريعة والسهلة.

إظهار الدعم

هل تخطّط لاستخدام Web NFC؟ يساعد دعمك العلني فريق Chrome في تحديد الميزات التي يجب منح الأولوية لها، ويُظهر لموفّري المتصفّحات الآخرين مدى أهمية توفير هذه الميزات.

أرسِل تغريدة إلى ‎@ChromiumDev باستخدام الهاشتاغ #WebNFC وأطلِعنا على مكان استخدامك للميزة وطريقة استخدامك لها.

روابط مفيدة

الشكر والتقدير

نشكر فريق Intel على تنفيذ Web NFC. يعتمد Google Chrome على منتدى للمشاركين يعملون معًا لتطوير مشروع Chromium. ليس كلّ مُرسِل رمز في Chromium موظفًا في Google، وهؤلاء المساهمون يستحقون تقديرًا خاصًا.