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

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

François Beaufort
François Beaufort

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

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

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

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

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

تقتصر تقنية NFC على الويب على NDEF لأنّ خصائص الأمان لقراءة بيانات NDEF ونقلها يمكن قياسها بسهولة أكبر. لا تتوفّر عمليات الإدخال/الإخراج من المستوى المنخفض (مثل ISO-DEP وNFC-A/B وNFC-F) ووضع الاتصال من جهاز إلى جهاز ومحاكاة البطاقة المستندة إلى المضيف (HCE).

تشمل أمثلة المواقع الإلكترونية التي قد تستخدم تقنية 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 في Chrome 100 أو الإصدارات الأحدث، تأكّد مما إذا كانت هذه الميزة متوافقة مع ما يلي:

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 وعنصر "صورة" لفك ترميز بيانات الصور.

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 في المكوّنات. يعمل الخطأ بشكلٍ رائع لمشاركة عمليات إعادة الإنتاج السريعة والسهلة.

إظهار الدعم

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

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

روابط مفيدة

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

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