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

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

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

Что такое веб-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 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.

Снимок экрана с приглашением Web NFC на веб-сайте
Подсказка пользователя веб-NFC

Веб-NFC доступен только для кадров верхнего уровня и контекстов безопасного просмотра (только HTTPS). Origins должен сначала запросить разрешение "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 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.
  }
};

Поваренная книга

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

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

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})`);
}

Чтобы написать простую текстовую запись, передайте строку методу 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;
  }
}

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

const encoder = new TextEncoder();
const smartPosterRecord = {
  recordType: "smart-poster",
  data: {
    records: [
      {
        recordType: "url", // URL record for smart poster content
        data: "https://my.org/content/19911"
      },
      {
        recordType: "text", // title record for smart poster content
        data: "Funny dance"
      },
      {
        recordType: ":t", // type record, a local type to smart poster
        data: encoder.encode("image/gif") // MIME type of smart poster content
      },
      {
        recordType: ":s", // size record, a local type to smart poster
        data: new Uint32Array([4096]) // byte size of smart poster content
      },
      {
        recordType: ":act", // action record, a local type to smart poster
        // do the action, in this case open in the browser
        data: new Uint8Array([0])
      },
      {
        recordType: "mime", // icon record, a MIME type record
        mediaType: "image/png",
        data: await (await fetch("icon1.png")).arrayBuffer()
      },
      {
        recordType: "mime", // another icon record
        mediaType: "image/jpg",
        data: await (await fetch("icon2.jpg")).arrayBuffer()
      }
    ]
  }
};

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

Чтение и запись записи внешнего типа

Для создания записей, определяемых приложением, используйте записи внешнего типа. Они могут содержать сообщение NDEF в качестве полезной нагрузки, доступной с помощью toRecords() . Их имя содержит доменное имя организации-эмитента, двоеточие и имя типа длиной не менее одного символа, например "example.com:foo" .

function readExternalTypeRecord(externalTypeRecord) {
  for (const record of externalTypeRecord.toRecords()) {
    if (record.recordType == "text") {
      const decoder = new TextDecoder(record.encoding);
      console.log(`Text: ${textDecoder.decode(record.data)} (${record.lang})`);
    } else if (record.recordType == "url") {
      const decoder = new TextDecoder();
      console.log(`URL: ${decoder.decode(record.data)}`);
    } else {
      // TODO: Handle other type of records.
    }
  }
}

Чтобы записать запись внешнего типа, передайте словарь сообщений NDEF методу write() NDEFReader. Запись внешнего типа, содержащаяся в сообщении NDEF, определяется как объект с ключом recordType установленным для имени внешнего типа, и ключом data , установленным для объекта, который представляет сообщение NDEF, содержащееся в записи внешнего типа. Обратите внимание, что ключ data также может быть либо ArrayBuffer , либо предоставлять представление ArrayBuffer (например, Uint8Array , DataView ).

const externalTypeRecord = {
  recordType: "example.game:a",
  data: {
    records: [
      {
        recordType: "url",
        data: "https://example.game/42"
      },
      {
        recordType: "text",
        data: "Game context given here"
      },
      {
        recordType: "mime",
        mediaType: "image/png",
        data: await (await fetch("image.png")).arrayBuffer()
      }
    ]
  }
};

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

Чтение и запись пустой записи

Пустая запись не имеет полезной нагрузки.

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

const emptyRecord = {
  recordType: "empty"
};

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

Поддержка браузера

Веб-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 . Glitch отлично подходит для быстрого и простого обмена репродукциями.

Показать поддержку

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

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

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

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

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