Взаимодействие с устройствами NFC в Chrome для Android

Теперь возможно чтение и запись на NFC-метки.

Франсуа Бофор
François Beaufort

Что такое Web NFC?

NFC означает Near Field Communications (коммуникации ближнего радиуса действия) — беспроводная технология ближнего радиуса действия, работающая на частоте 13,56 МГц и обеспечивающая связь между устройствами на расстоянии менее 10 см со скоростью передачи данных до 424 кбит/с.

Web NFC предоставляет сайтам возможность считывать и записывать данные с NFC-меток, когда они находятся в непосредственной близости от устройства пользователя (обычно на расстоянии 5–10 см, 2–4 дюйма). В настоящее время область применения ограничена форматом обмена данными NFC (NDEF) — облегчённым двоичным форматом сообщений, совместимым с различными форматами тегов.

Телефон активирует NFC-метку для обмена данными
Схема работы NFC

Предлагаемые варианты использования

Web 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 (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 на своем телефоне.

После выполнения обещания входящие сообщения 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-метку, передайте write() словарь, представляющий сообщение NDEF. В примере ниже сообщение NDEF представляет собой словарь с ключом records . Его значение — массив записей, в данном случае запись URL определена как объект с ключом recordType , равным "url" , и ключом data , равным строке URL.

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

Также возможно записать несколько записей в метку NFC.

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

Если NFC-метка содержит сообщение NDEF, которое не подлежит перезаписи, установите свойство overwrite в значение false в параметрах, передаваемых методу 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 разработала и реализовала Web NFC, используя основные принципы, определенные в документе «Управление доступом к мощным функциям веб-платформы» , включая пользовательский контроль, прозрачность и эргономичность.

Поскольку NFC расширяет область информации, потенциально доступной вредоносным веб-сайтам, доступность NFC ограничена, чтобы максимизировать осведомленность пользователей и контроль над использованием NFC.

Скриншот запроса NFC на веб-сайте
Веб-подсказка для пользователя NFC

Веб-NFC доступен только для фреймов верхнего уровня и безопасных контекстов просмотра (только HTTPS). Источники должны сначала запросить разрешение "nfc" при обработке жеста пользователя (например, нажатия кнопки). Методы NDEFReader scan() , write() и makeReadOnly() вызывают запрос пользователя, если доступ не был предоставлен ранее.

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

Сочетание запроса разрешения, инициированного пользователем, и реального физического движения при поднесении устройства к целевой метке NFC отражает шаблон выбора, который можно найти в других API-интерфейсах доступа к файлам и устройствам.

Для сканирования или записи веб-страница должна быть видна пользователю при касании NFC-метки устройством. Браузер использует тактильную обратную связь для индикации прикосновения. Доступ к NFC-модулю блокируется, если дисплей выключен или устройство заблокировано. Для невидимых веб-страниц получение и отправка NFC-контента приостанавливаются и возобновляются, когда веб-страница снова становится видимой.

Благодаря 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.
  }
};

Кулинарная книга

Вот несколько примеров кода, с которых можно начать.

Проверить наличие разрешения

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-метку и прочитать новое сообщение. Сканирование останавливается через три секунды.

// 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 методу 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 полезной нагрузки записи 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 методу 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-адреса

data записи абсолютного URL можно декодировать с помощью простого 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. Запись абсолютного 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;
  }
}

Чтобы создать запись Smart Poster, передайте сообщение NDEF методу write() объекта NDEFReader. Запись Smart Poster, содержащаяся в сообщении NDEF, определяется как объект с ключом recordType , установленным на "smart-poster" , и ключом data , установленным на объект, представляющий (опять же) сообщение NDEF, содержащееся в записи Smart Poster.

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 в Chrome 89.

Советы разработчикам

Вот список вещей, которые я хотел бы знать, когда начал работать с Web NFC:

  • Android обрабатывает метки NFC на уровне ОС еще до того, как начнет работать Web NFC.
  • Иконку NFC можно найти на material.io .
  • Используйте id записи NDEF для легкой идентификации записи при необходимости.
  • Неформатированная метка 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 . Опишите проблему как можно подробнее, предоставьте простые инструкции по воспроизведению ошибки и установите для компонентов значение Blink>NFC .

Выразить поддержку

Планируете ли вы использовать Web NFC? Ваша публичная поддержка помогает команде Chrome расставить приоритеты в отношении функций и показывает другим разработчикам браузеров, насколько важна их поддержка.

Отправьте твит @ChromiumDev , используя хэштег #WebNFC и расскажите, где и как вы его используете.

Полезные ссылки

Благодарности

Большое спасибо ребятам из Intel за реализацию Web NFC. Google Chrome опирается на сообщество разработчиков, работающих вместе над развитием проекта Chromium. Не каждый разработчик Chromium — сотрудник Google, и эти участники заслуживают особого признания!