- Введение
- Mapping string to ndef
- Ndef compatible tag types
- Parsing content
- Parsing records from bytes
- Parsing ndef records
- Parsing records from bytes
- Smart poster record
- The makereadonly() method
- The nfc standard
- Ndef compatible tag types
- The write() method
- Использование готовых меток для управления устройством
- Чтение и запись меток
Введение
На первый взгляд может показаться, что многочисленные беспроводные интерфейсы сегодня уже покрывают все возможные популярные задачи и сценарии, так что еще один вариант просто не нужен. Однако если посмотреть на развитие современных технологий, то можно заметить, что все больше внимания уделяется вопросам энергопотребления, особенно если речь идет о мобильных устройствах.
В частности версия 4.0 известного семейства протоколов Bluetooth как раз ориентирована на снижение затрат заряда батареи. Второй момент, который стоит упомянуть, состоит в том, что не для каждой задачи требуется большая дальность работы. Бывает даже наоборот — хочется явно ограничить расстояние между взаимодействующими устройствами.
Кроме очевидного снижения потребления, это также влияет и на безопасность. Да и про объемы передаваемых данных тоже можно сделать аналогичное замечание. Так что идея небыстрого беспроводного интерфейса, работающего на небольших расстояниях и отличающегося низким энергопотреблением вполне имеет право на существование.
За начальную точку отсчета в истории развития NFC можно принять 2004 год, когда Nokia, Philips и Sony объявили о создании форума NFC с целью разработки и стандартизации интерфейса взаимодействия различных устройств, основанного на касании.
Впрочем, первые версии спецификаций были созданы немного ранее. Пожалуй, по современным меркам технологию можно считать очень молодой (если не учитывать историю RFID), однако она уже достаточно часто встречается в реальных продуктах и сервисах. В частности, на прошедшем в конце февраля Mobile World Congress 2021 этой теме были посвящены многие стенды и демонстрации.
Такой знак можно встретить на устройствах с технологией NFC
Формальные характеристики интерфейса следующие: работа на расстоянии нескольких сантиметров, максимальная скорость обмена информацией около 400 Кбит/с, поддерживается полнодуплексный обмен данными, рабочая частота 13,56 МГц, время установления соединения не превышает 0,1 с, режим работы — точка–точка. Видно, что эти параметры кардинально отличают NFC от других популярных беспроводных интерфейсов.
Если говорить про устройства, то кроме активных контроллеров в NFC существуют и пассивные варианты (они обычно называются метками), которые получают питание беспроводным способом от активного контроллера. Одним из примеров являются современные карты для проезда на городском транспорте.
Один из простейших вариантов пассивной NFC-метки
Компактный размер контроллера и его низкое потребление позволяет реализовать NFC даже в таких небольших конструкциях, как SIM-карты или карты памяти microSD. Однако для полноценной работы необходимо использование специальной антенны. В телефонах она обычно находится на обратной стороне крышки батарейного отсека или же встроена в заднюю панель, если аппарат не предполагает съемной батареи.
Антенну NFC часто размещают на задней крышке смартфона
Небольшой радиус действия может негативно сказаться при использовании планшетов — найти нужное место для «прикладывания» может быть не так просто, как хотелось бы. Для решения этой проблемы некоторые производители помечают местонахождение антенны специальным знаком.
С точки зрения безопасности, разработчики не стали реализовывать элементы защиты от перехвата и атаки ретрансляции. Это конечно затрудняет реализацию безопасных решений, поскольку требует от самих приложений защиты на более высоком уровне. Отметим, что на самом деле аналогично ведет себя и такой известный протокол, как TCP/IP.
Пожалуй, самое главное, что нужно сегодня знать о NFC, это то, что сам по себе интерфейс не дает никаких реальных практических сценариев использования или решений. В отличие, например, от Bluetooth, профили которого четко описывают, как передать файл, как подключить гарнитуру или обеспечить сетевой доступ, NFC является только базой, а непосредственные сценарии работы обеспечиваются дополнительным программным обеспечением, которое работает через него.
Интересно, что любые установленные на смартфон или планшет программы могут зарегистрироваться в операционной системе как обработчики событий, связанных с NFC, и тогда при внешнем «вызове» вы увидите стандартное меню «чем вы хотите осуществить это действие?».
Форум NFC старается помочь с этой неопределенностью, предлагая стандартизировать протоколы для определенных сценариев (в частности NDEF для хранения коротких сообщений на метках и SNEP (Simple NDEF Exchange Protocol) для обмена информацией между устройствами), однако практическое определение совместимости конкретных устройств обычно затруднено отсутствием детальной информации от производителя и средств диагностики.
Mapping string to ndef
To
map text to NDEF
given |record:NDEFRecordInit| and |ndef|,
run these steps:
This is useful when clients specifically want to write text in a
[=well-known type record=].
Other options would be to use the value «`mime`»
with an explicit MIME type text type, which allows for
better differentiation, e.g. when using «`text/xml`», or
«`text/vcard`».
- If |record|’s mediaType is not `undefined`,
[= exception/throw =] a {{TypeError}} and abort these steps. - If the type of |record|’s data is not {{DOMString}} or
{{BufferSource}}, [= exception/throw =] a {{TypeError}} and abort
these steps. - Let |documentLanguage:string| be the [=document element=]’s
lang attribute. - If |documentLanguage| is the empty string, set it to «`en`».
- Let |language:string| be |record|’s lang if it [= map/exists =],
or else to |documentLanguage|. - Switch on the type of |record|’s data:
- {{DOMString}}
- If |record|’s encoding is neither `undefined` nor
«`utf-8`», [= exception/throw =] a {{TypeError}} and abort
these steps. - Let |encoding label:string| be «`utf-8`».
- {{BufferSource}}
- Let |encoding label:string| be |record|’s encoding if
it [= map/exists =], or else «`utf-8`». - If |encoding label| is not equal to «`utf-8`», «`utf-16`»,
«`utf-16le`» or «`utf-16be`» [= exception/throw =] a
{{TypeError}} and abort these steps.
- Let |encoding name| be the [=encoding/name|name=]
obtained
from |encoding label|. - Let |header:byte| be a byte constructed the following way:
- If |encoding name| is equal to UTF-8, set bit `7` to the value
`0`, or else set the value to `1`. - Set bit `6` to the value `0` (reserved).
- Let |languageLength:octet| be the length of the
|language| string. - If |languageLength| cannot be stored in 6 bit
(|languageLength| > 63), [= exception/throw =] a {{SyntaxError}}. - Set bit `5` to bit `0` to |languageLength|.
- If |encoding name| is equal to UTF-8, set bit `7` to the value
- Let |data:byte sequence| be an empty [= byte sequence =].
- Set the first byte (position 0) of |data| to |header|.
- Set position 1 (second byte) to position |languageLength|
of |data| to |language|. - Switch on the type of |record|’s data:
- {{DOMString}}
- Let |stream:byte stream| be the resulting
byte stream of
running UTF-8 encode on |record|’s data. - Read bytes
from |stream| into |data| (from position |languageLength| 1)
until read
returns end-of-stream. - {{BufferSource}}
- Set bytes from |record|’s data into |data|
(from position |languageLength| 1) .
- Set |length:unsigned long| to the [=byte sequence/length=]
of |data|. - Set the |ndef|’s TNF field to `1` (
[=well-known type record=]). - Set the |ndef|’s TYPE field to «`T`» (`0x54`).
- Set the |ndef|’s PAYLOAD LENGTH field to |length|.
- If |length| > `0`, set the |ndef|’s PAYLOAD field
to |data|.
- Set the |ndef|’s TNF field to `1` (
- Return |ndef|.
Ndef compatible tag types
The NFC Forum has mandated the support of five different tag types to be
operable with NFC devices. The same is required on operating systems, such
as Android.
In addition to that, the MIFARE Standard specifies a way
for NDEF to work on top of the older MIFARE Standard, which may
be optionally supported by implementers.
A note about the NDEF mapping can be found here:
MIFARE Classic as NFC Type MIFARE Classic Tag.
- NFC Forum Type 1: This tag is based on the ISO/IEC 14443-3A
(NFC-A). The tags are rewritable and can be
configured to become read-only. Memory size can be between `96` bytes and
`2` Kbytes. Communication speed is `106` kbit/s. In contrast to all other
types, these tags have no anti-collision protection for dealing with multiple
tags within the NFC field. - NFC Forum Type 2: This tag is based on the
ISO/IEC 14443-3A (NFC-A). The tags are rewritable and can be configured
to become read-only. Memory size can be between `48` bytes and `2` Kbytes.
Communication speed is `106` kbit/s. - NFC Forum Type 3: This tag is based on the Japanese Industrial
Standard (JIS) X 6319-4 (ISO/IEC 18092), commonly known as FeliCa. The tags are
preconfigured to be either rewritable or read-only. Memory is `2` kbytes.
Communication speed is `212` kbit/s or `424` kbit/s. - NFC Forum Type 4: This tag is based on the ISO/IEC 14443-4 A/B
(NFC A, NFC B) and thus supports either NFC-A or NFC-B
for communication. On top of that the tag may optionally support ISO-DEP
(Data Exchange Protocol defined in ISO/IEC 14443 (ISO/IEC 14443-4:2008
Part 4: Transmission protocol). The tags are preconfigured
to be either rewritable or read-only. Variable memory, up to `32` kbytes.
Supports three different communication speeds `106` or `212` or
`424` kbit/s. - NFC Forum Type 5: This tag is based on ISO/IEC 15693 (NFC-V) and
allows reading and writing an NDEF message on an ISO/IEC 15693 RF tag
that is accessible by long range RFID readers as well. The NFC communication
is limited to short distance and may use the Active Communication Mode of
ISO/IEC 18092 where the sending peer generates the field which balances
power consumption and improves link stability. Variable memory, up to `64` kbytes.
Communication speed is `26.48` kbit/s. - MIFARE Standard: This tag, often sold under the brand names MIFARE
Classic or MIFARE Mini, is based on the ISO/IEC 14443-3A (also known as NFC-A,
as defined in ISO/IEC 14443-3:2021, Part 3: Initialization and anticollision).
The tags are rewritable and can be configured to become read-only. Memory size
can be between `320` and `4` kbytes. Communication speed is `106` kbit/s.MIFARE Standard is not an NFC Forum type and can only be read by devices
using NXP hardware. Support for reading and writing to tags based on the
MIFARE Standard is thus non-nominative, but the type is included
due to the popularity and use in legacy systems.
In addition to data types standardized for NDEF records by the NFC
Forum, many commercial products such as bus cards, door openers may be based
on the MIFARE Standard which requires specific NFC chips (same vendor of
card and reader) in order to function.
Parsing content
Parsing records from bytes
To parse records from bytes given |bytes:byte sequence| and
|context: string|, run these steps:
- If the length of |bytes| is `0`, return `null` and abort these steps.
- Let |records| be the empty list.
- As long as there are unread bytes of |bytes|, run the following
sub-steps:- If the remaining length of |bytes| is less than `3`, return `null`
and abort these sub-steps. - If any of the following steps requires reading bytes beyond the
remaining length of |bytes|, return `null` and abort these
sub-steps. - Let |ndef| be the notation for the current NDEF record.
- Let |header:byte| be the next byte of |bytes|.
- Let |messageBegin:boolean| (MB field) be the left most
bit (bit 7) of |header|. - If this is the first iteration of these sub-steps and
|messageBegin| is `false`, return `null` and abort these
sub-steps. - Let |messageEnd:boolean| (ME field) be bit 6 of |header|.
- Let |shortRecord:boolean| (SR field) be bit 4 of |header|.
- Let |hasIdLength:boolean| (IL field) be bit 3 of |header|.
- Let |ndef|’s |typeNameField:number| (TNF field) be the
integer value of bit 2-0 of |header|.
As chunked records are not allowed as sub records, ignore bit 5
(CF field) is ignored. - Let |messageBegin:boolean| (MB field) be the left most
- Let |typeLength:number| be the integer value of next byte
(TYPE LENGTH field) of |bytes|. - If |shortRecord| is `true`, let |payloadLength:number|
be the integer value of next byte (PAYLOAD LENGTH field) of
|bytes|. - Otherwise, let |payloadLength| be the integer value of the next 4
bytes of |bytes|. - If |hasIdLength| is `true`, let |idLength:number| be
the integer value of next byte (ID LENGTH field) of |bytes|,
otherwise let it be `0`. - If |typeLength| > 0, let |ndef|’s |type:string| be result of
running UTF-8 decode on the next |typeLength|
(TYPE field) bytes, or else let |type| be the empty string. - If |idLength| > 0, let |ndef|’s |id:string| be result of
running UTF-8 decode on the next |idLength| (ID field)
bytes, or else let |ndef|’s |id| be the empty string. - Let |ndef|’s |payload| be the byte sequence of the last
|payloadLength| (PAYLOAD field) bytes, which may be `0` bytes. - Let |record:NDEFRecord| be the result of parse an NDEF record
given |ndef| and |context|. - If |record| is not `null`, append |record| to |records|.
- If |messageEnd| is `true`,
- If check parsed records given |records| and |context|
throws an |error|, reject |promise| with |error| and abort these
steps. - Otherwise abort these sub-steps (terminate the loop).
- If check parsed records given |records| and |context|
- If the remaining length of |bytes| is less than `3`, return `null`
- Return |records|.
Parsing ndef records
To
parse an NDEF record
given |ndef| and |context:string| into a
|record:NDEFRecord|, run these steps:
- Set |record|’s id to |ndef|’s |id:string|.
- Set |record|’s lang to `null`.
- Set |record|’s encoding to `null`.
- If |ndef|’s |typeNameField:number| (TNF field) is `0`
(empty record):- Set |record|’s id to `null`.
- Set |record|’s recordType to «`empty`».
- Set |record|’s mediaType to `null`.
- Set |record|’s data to `null`.
- If |ndef|’s |typeNameField| is `1` ([=well-known type record=]), then
- If |ndef|’s |type:string| is «`T`» (`0x54`),
set |record| to the result of running
parse an NDEF text record on |ndef|. - If |ndef|’s |type:string| is «`U`» (`0x55`),
set |record| to the result of running
parse an NDEF URL record on |ndef|. - If |ndef|’s |type:string| is «`Sp`» (`0x53` `0x70`),
set |record| to the result of running
parse an NDEF smart-poster record on |ndef|. - If |ndef|’s |type:string| is «`s`» (`0x73`)
and if |context| is equal to `»smart-poster»`,
set |record| to the result of running
parse a smart-poster size record on |ndef|. - If |ndef|’s |type:string| is «`t`» (`0x74`)
and if |context| is equal to `»smart-poster»`,
set |record| to the result of running
parse a smart-poster type record on |ndef|. - If |ndef|’s |type:string| is «`act`» (`0x61` `0x63` `0x74`)
and if |context| is equal to `»smart-poster»`,
set |record| to the result of running
parse a smart-poster action record on |ndef|. - If running the validate local type steps on
|ndef|’s |type:string| returns `true`,- If |context| is not `»external»` or `»smart-poster»`,
[= exception/throw =] a {{TypeError}} and abort these steps. - Set |record| to the result of running
parse a local type record on |ndef|.
- If |context| is not `»external»` or `»smart-poster»`,
- Otherwise [= exception/throw =] a {{TypeError}} and abort these
steps.
- If |ndef|’s |type:string| is «`T`» (`0x54`),
- If |ndef|’s |typeNameField| is `2` (MIME type record), then
set |record| to the result of running
parse an NDEF MIME type record on |ndef|, or make sure that
the underlying platform provides equivalent values to the |record|
object’s properties. - If |ndef|’s |typeNameField| is `3` (absolute-URL record),
then set |record| to the result of running
parse an NDEF absolute-URL record on |ndef|. - If |ndef|’s |typeNameField| is `4` (external type record),
then set |record| to the result of running
parse an NDEF external type record on |ndef|, or make sure that
the underlying platform provides equivalent values to the |record|
object’s properties. - If |ndef|’s |typeNameField| is `5` (unknown record)
then set |record| to the result of running
parse an NDEF unknown record on |ndef|, or make sure that the
underlying platform provides equivalent values to the |record| object’s
properties. - Otherwise [= exception/throw =] a {{TypeError}} and abort these steps.
Parsing records from bytes
parse records from bytes
given |bytes:byte sequence| and
|context: string|, run these steps:
- If the length of |bytes| is `0`, return `null` and abort these steps.
- Let |records| be the empty list.
- As long as there are unread bytes of |bytes|, run the following
sub-steps:- If the remaining length of |bytes| is less than `3`, return `null`
and abort these sub-steps. - If any of the following steps requires reading bytes beyond the
remaining length of |bytes|, return `null` and abort these
sub-steps. - Let |ndef| be the notation for the current NDEF record.
- Let |header:byte| be the next byte of |bytes|.
- Let |messageBegin:boolean| (MB field) be the left most
bit (bit 7) of |header|. - If this is the first iteration of these sub-steps and
|messageBegin| is `false`, return `null` and abort these
sub-steps. - Let |messageEnd:boolean| (ME field) be bit 6 of |header|.
- Let |shortRecord:boolean| (SR field) be bit 4 of |header|.
- Let |hasIdLength:boolean| (IL field) be bit 3 of |header|.
- Let |ndef|’s |typeNameField:number| (TNF field) be the
integer value of bit 2-0 of |header|.
As chunked records are not allowed as sub records, ignore bit 5
(CF field) is ignored. - Let |messageBegin:boolean| (MB field) be the left most
- Let |typeLength:number| be the integer value of next byte
(TYPE LENGTH field) of |bytes|. - If |shortRecord| is `true`, let |payloadLength:number|
be the integer value of next byte (PAYLOAD LENGTH field) of
|bytes|. - Otherwise, let |payloadLength| be the integer value of the next 4
bytes of |bytes|. - If |hasIdLength| is `true`, let |idLength:number| be
the integer value of next byte (ID LENGTH field) of |bytes|,
otherwise let it be `0`. - If |typeLength| > 0, let |ndef|’s |type:string| be result of
running UTF-8 decode on the next |typeLength|
(TYPE field) bytes, or else let |type| be the empty string. - If |idLength| > 0, let |ndef|’s |id:string| be result of
running UTF-8 decode on the next |idLength| (ID field)
bytes, or else let |ndef|’s |id| be the empty string. - Let |ndef|’s |payload| be the byte sequence of the last
|payloadLength| (PAYLOAD field) bytes, which may be `0` bytes. - Let |record:NDEFRecord| be the result of parse an NDEF record
given |ndef| and |context|. - If |record| is not `null`, append |record| to |records|.
- If |messageEnd| is `true`,
- If check parsed records given |records| and |context|
throws an |error|, reject |promise| with |error| and abort these
steps. - Otherwise abort these sub-steps (terminate the loop).
- If check parsed records given |records| and |context|
- If the remaining length of |bytes| is less than `3`, return `null`
- Return |records|.
Smart poster record
is defined in [[NDEF-SMARTPOSTER]] to describe a
given web content as an NDEF record that contains an
NDEF message
as payload, including the following records:
- A single mandatory URI record that refers to the
smart poster content.The [[NDEF-SMARTPOSTER]] states that applications SHALL use only the
smart poster record if it is present in an NDEF message
that also contains other URI records. - Zero or more Text records that act as a title record
related to the content. When there are more than one title record
present, they MUST be with different language tags.
Applications SHOULD select one title record for presentation
to the end user. - Zero or more MIME type records that act as icon record
related to the content. The MIME type is usually «`image/jpg`»,
«`image/png`», «`image/gif`», or even «`video/mpeg`».
Applications SHOULD select one icon record for presentation
to the end user. - One optional type record that has a [=local type name=]
«`t`» specific to smart poster and the PAYLOAD field
contains a UTF-8 encoded MIME type for the content referred to by the
URI record. - One optional size record that has [=local type name=] «`s`»
specific to smart poster and the PAYLOAD field contains
a 4-byte 32 bit unsigned integer that denotes the size of the object
referred to by the URL in the URI record of the
smart poster. - One optional action record that has a [=local type name=]
«`act`» specific to smart poster and the PAYLOAD field
contains a single byte, whose value has the following meaning:Value Description 0 Do the action 1 Save for later 2 Open for editing 3..0xFF Reserved for future use There is no default action on the smart poster content if the
action record is missing.At the time of NDEF standardization the value `0` («do the action») was
intended for use cases like send an SMS, make a call or launch browser.
Similarly, the value `1`, («save the content for later processing») was
intended for use cases like store the SMS in inbox, save the URL in
bookmarks, or save the phone number to contacts. Also, the value `2`
(«open for editing») was meant to open the smart poster content with a
default application for editing.Implementations don’t need to implement any standardized behavior for the
actions defined here. In this API it’s up to the applications what actions
they define (that may include the use cases above). However, Web NFC
just provides the values. - A smart poster MAY also contain other records, which can be
handled in an application specific manner.
The example below shows a smart poster record that embeds a text and a
URL record.
The makereadonly() method
The
NDEFReader.makeReadOnly
method, when invoked, MUST run the
make an NFC tag permanently read-only
algorithm:
- Let |p:Promise| be a new {{Promise}} object.
- If not currently executing in the currently active top-level
browsing context, then reject |p| with and
{{«InvalidStateError»}} {{DOMException}} and return |p|. - Let |options:NDEFMakeReadOnlyOptions| be the second argument.
- Let |signal:AbortSignal| be the |options|’ dictionary member
of the same name if present, or `null` otherwise. - If |signal| is [= AbortSignal/aborted =], then reject |p|
with |signal|’s [=AbortSignal/abort reason=] and return |p|. - If |signal| is not `null`, then
add the following abort steps to |signal|:- Run the abort a pending make read-only operation on the
environment settings object.
- Run the abort a pending make read-only operation on the
- [=promise/React=] to |p|:
- If |p| was settled (fulfilled or rejected), then clear the
pending write tuple if it exists.
- If |p| was settled (fulfilled or rejected), then clear the
- Return |p| and run the following steps in parallel:
- If the obtain permission steps return `false`, then
reject |p| with a {{«NotAllowedError»}} {{DOMException}} and
abort these steps. - If there is no underlying NFC Adapter, or if a connection
cannot be established, then reject |p| with a
{{«NotSupportedError»}} {{DOMException}}
and abort these steps. - If the UA is not allowed to access the underlying NFC Adapter
(e.g. a user preference), then reject |p| with a
{{«NotReadableError»}} {{DOMException}}
and abort these steps. - An implementation MAY reject |p| with
a {{«NotSupportedError»}} {{DOMException}}
and abort these steps.The UA might abort at this point. The reasons for termination
are implementation details. For example, the implementation
might be unable to support the requested operation. - Attempt to abort a pending make read-only operation.
A make read-only operation replaces all previously configured
make read-only operations. - Set pending makeReadOnly tuple to (`this`, |p|).
- Run the start the NFC make read-only steps whenever an
NFC tag |device| comes within communication range.If NFC is suspended, continue waiting until promise is
aborted by the user or an NFC tag comes within
communication range.
- If the obtain permission steps return `false`, then
The nfc standard
NFC is standardized in the NFC Forum and described in [[NFC-STANDARDS]].
Ndef compatible tag types
The NFC Forum has mandated the support of five different tag types to be
operable with NFC devices. The same is required on operating systems, such
as Android.
In addition to that, the MIFARE Standard specifies a way
for NDEF to work on top of the older MIFARE Standard, which may
be optionally supported by implementers.
A note about the NDEF mapping can be found here:
MIFARE Classic as NFC Type MIFARE Classic Tag.
- NFC Forum Type 1: This tag is based on the ISO/IEC 14443-3A
(NFC-A). The tags are rewritable and can be
configured to become read-only. Memory size can be between `96` bytes and
`2` Kbytes. Communication speed is `106` kbit/s. In contrast to all other
types, these tags have no anti-collision protection for dealing with multiple
tags within the NFC field. - NFC Forum Type 2: This tag is based on the
ISO/IEC 14443-3A (NFC-A). The tags are rewritable and can be configured
to become read-only. Memory size can be between `48` bytes and `2` Kbytes.
Communication speed is `106` kbit/s. - NFC Forum Type 3: This tag is based on the Japanese Industrial
Standard (JIS) X 6319-4 (ISO/IEC 18092), commonly known as FeliCa. The tags are
preconfigured to be either rewritable or read-only. Memory is `2` kbytes.
Communication speed is `212` kbit/s or `424` kbit/s. - NFC Forum Type 4: This tag is based on the ISO/IEC 14443-4 A/B
(NFC A, NFC B) and thus supports either NFC-A or NFC-B
for communication. On top of that the tag may optionally support ISO-DEP
(Data Exchange Protocol defined in ISO/IEC 14443 (ISO/IEC 14443-4:2008
Part 4: Transmission protocol). The tags are preconfigured
to be either rewritable or read-only. Variable memory, up to `32` kbytes.
Supports three different communication speeds `106` or `212` or
`424` kbit/s. - NFC Forum Type 5: This tag is based on ISO/IEC 15693 (NFC-V) and
allows reading and writing an NDEF message on an ISO/IEC 15693 RF tag
that is accessible by long range RFID readers as well. The NFC communication
is limited to short distance and may use the Active Communication Mode of
ISO/IEC 18092 where the sending peer generates the field which balances
power consumption and improves link stability. Variable memory, up to `64` kbytes.
Communication speed is `26.48` kbit/s. - MIFARE Standard: This tag, often sold under the brand names MIFARE
Classic or MIFARE Mini, is based on the ISO/IEC 14443-3A (also known as NFC-A,
as defined in ISO/IEC 14443-3:2021, Part 3: Initialization and anticollision).
The tags are rewritable and can be configured to become read-only. Memory size
can be between `320` and `4` kbytes. Communication speed is `106` kbit/s.MIFARE Standard is not an NFC Forum type and can only be read by devices
using NXP hardware. Support for reading and writing to tags based on the
MIFARE Standard is thus non-nominative, but the type is included
due to the popularity and use in legacy systems.
In addition to data types standardized for NDEF records by the NFC
Forum, many commercial products such as bus cards, door openers may be based
on the MIFARE Standard which requires specific NFC chips (same vendor of
card and reader) in order to function.
The write() method
The
NDEFReader.write
method, when invoked, MUST run the
write a message
algorithm:
- Let |p:Promise| be a new {{Promise}} object.
- If not currently executing in the currently active top-level
browsing context, then reject |p| with and
{{«InvalidStateError»}} {{DOMException}} and return |p|. - Let |message:NDEFMessageSource| be the first argument.
- Let |options:NDEFWriteOptions| be the second argument.
- Let |signal:AbortSignal| be the |options|’ dictionary member
of the same name if present, or `null` otherwise. - If |signal| is [= AbortSignal/aborted =], then reject |p|
with |signal|’s [=AbortSignal/abort reason=] and return |p|. - If |signal| is not `null`, then
add the following abort steps to |signal|:- Run the abort a pending write operation on the
environment settings object.
- Run the abort a pending write operation on the
- [=promise/React=] to |p|:
- If |p| was settled (fulfilled or rejected), then clear the
pending write tuple if it exists.
- If |p| was settled (fulfilled or rejected), then clear the
- Return |p| and run the following steps in parallel:
- If the obtain permission steps return `false`, then
reject |p| with a {{«NotAllowedError»}} {{DOMException}} and
abort these steps. - If there is no underlying NFC Adapter, or if a connection
cannot be established, then reject |p| with a
{{«NotSupportedError»}} {{DOMException}}
and abort these steps. - If the UA is not allowed to access the underlying NFC Adapter
(e.g. a user preference), then reject |p| with a
{{«NotReadableError»}} {{DOMException}}
and abort these steps. - If pushing data is not supported by the underlying
NFC Adapter, then reject |p| with a {{«NotSupportedError»}}
{{DOMException}} and abort these steps. - An implementation MAY reject |p| with
a {{«NotSupportedError»}} {{DOMException}}
and abort these steps.The UA might abort message write at this point. The reasons
for termination are implementation details. For example, the
implementation might be unable to support the requested
operation. - Let |output| be the notation for the NDEF message
to be created by UA, as the result of invoking
create NDEF message with |message|, `»»`, and `0`.
If this throws an exception, reject |p| with that
exception and abort these steps. - Attempt to abort a pending write operation.
A write replaces all previously configured write operations.
- Set `this`.[[WriteOptions]] to |options|.
- Set `this`.[[WriteMessage]] to |output|.
- Set pending write tuple to (`this`, |p|).
- Run the start the NFC write steps whenever an
NFC tag |device| comes within communication range.If NFC is suspended, continue waiting until promise is
aborted by the user or an NFC tag comes within
communication range.
- If the obtain permission steps return `false`, then
To
start the NFC write
, run these steps:
- Let |p:Promise| be the pending write tuple‘s promise.
- Let |writer| be the pending write tuple‘s writer.
- Let |options:NDEFWriteOptions| be |writer|.[[WriteOptions]].
- If the NFC tag in proximity range does not expose
NDEF technology for formatting or writing, then
reject |p| with a {{«NotSupportedError»}} {{DOMException}} and
return |p|. - Verify that NFC is not suspended.
- In case of success, run the following steps:
- If |device| is an NFC tag and if |options|’s overwrite is
`false`, read the tag to check whether there are NDEF
records on the tag. If yes, then reject |p| with a
{{«NotAllowedError»}} {{DOMException}} and return |p|. - Let |output:NDEFMessage| be |writer|.[[WriteMessage]].
- Initiate data transfer to |device| using
|output| as buffer, using the NFC adapter
in communication range with |device|.If the NFC tag in proximity range is unformatted and
NDEF-formatable, format it and write |output| as
buffer.Multiple adapters should be used sequentially by users.
There is very little likelihood that a simultaneous tap
will happen on two or multiple different and connected
NFC adapters.
If it happens, the user will likely need to repeat the
taps until success, preferably one device at a time.
The error here gives an indication that the operation
needs to be repeated. Otherwise the user may think the
operation succeeded on all connected NFC adapters. - If the transfer fails, reject |p| with
{{«NetworkError»}} {{DOMException}}
and abort these steps. - When the transfer has completed, resolve |p|.
- If |device| is an NFC tag and if |options|’s overwrite is
Использование готовых меток для управления устройством
Одним из активных участников процесса внедрения NFC является компания Sony. В ее аппаратах предустановленна программа Smart Connect, поддерживающая работу с оригинальными метками Sony. При желании с использованием утилиты SmartTag Maker вы можете создать их самостоятельно из чистых заготовок.
Для работы системы используется формат NDEF URI с кодированием номера/цвета метки в текстовой ссылке. Всего система предусматривает до восьми меток, которые обозначены как «дом», «офис», «машина», «спальня», «слушать», «играть», «активности», «смотреть».
Вариант оригинальных меток Sony SmartTags
Сама программа Smart Connect работает не только с NFC-метками, но и с другими подключаемыми к телефону устройствами, включая гарнитуры, блок питания, устройства Bluetooth. Достаточно удобно, что штатные настройки уже неплохо соответствуют указанным выше сценариям. При этом пользователь может перепрограммировать все схемы; в каждой из них указывается набор из условия и действий.
Настройка работы с метками в Sony Smart Connect
В качестве условия можно использовать опознание метки или подключение устройства, дополнительно можно ограничить время работы схемы. Набор действий достаточно широкий, в него входят запуск приложения, открытие ссылки в браузере, запуск музыки, регулировка громкости и режима, подключение аудиоустройства Bluetooth, отправка SMS, звонок, управление беспроводными интерфейсами, регулировка яркости и другие действия.
Но на самом деле не обязательно использовать фирменные метки Sony — можно найти применение и готовым меткам, не допускающим перезаписи информации. Например, это могут быть использованные транспортные карты. Дело в том, что каждая из них имеет собственный уникальный идентификатор, который можно привязать к определенным действиям специальными программами.
В магазине Play Store есть несколько утилит для этого сценария, упомянем пару из них:
Напомним, что не стоит устанавливать сразу несколько подобных программ. Удобства от такого режима не добавится, поскольку при обнаружении метки на экране телефона будет возникать диалоговое окно с выбором программы для ее обработки.
Во время поиска программ для работы с метками мы также встретились с еще одним классом утилит, которые могут быть интересны в случае наличия записываемых меток. Эти программы используют собственный оригинальный формат записей, работать с которым могут только они сами. При этом набор возможных действий почти не отличается от описанных выше:
- NFC Actions: возможность работы с облачным сервисом для хранения действий меток, запуск приложений, все традиционные для NDEF действия и несколько дополнительных (включение Wi-Fi, фонарика и т. п.);
- NFC Profile: изменение некоторых параметров конфигурации устройства, включая состояние беспроводных интерфейсов, будильник, а также запуск программ;
- NFC Smart Q: опции по настройке режимов телефона, запуску приложений, можно использовать несколько записей на одной метке, дополнительно создается короткая web-ссылка стандартного формата NDEF, которая позволяет на новом устройстве загрузить данную программу и использовать некоторые из опций;
- NFC Task Launcher: кроме меток NFC может активировать настройки по подключению к Bluetooth или Wi-Fi, среди действий есть переключение режимов, интерфейсов, громкости и настроек экрана, публикации в социальных сетях, отправка e-mail и SMS, запуск приложений, открытие страниц в браузере, управление медиаплеером, настройка будильника, телефонный звонок.
Напомним, что в настоящий момент чтение метки осуществляется только при разблокированном аппарате. Так что сценарий «пришел домой, положил телефон на тумбочку — автоматически переключил профиль, отключил звонок и Bluetooth, настроил будильник» потребует от пользователя некоторых действий. Такое поведение все-таки немного ограничивает возможности программ.
Чтение и запись меток
Описанный Android Beam использует возможность передачи и обработки коротких информационных сообщений. Однако в реальности их можно не только передавать с телефона, но и считывать с пассивных меток. В некотором смысле эта технология аналогична известным QR-кодам, которые считываются фотокамерой телефона.
При этом полезная информация (например, ссылка на страницу сайта) занимает буквально несколько десятков байт. Метки могут использоваться компаниями, например, для продвижения своих товаров или услуг. Учитывая компактный размер пассивной метки (точнее, сравнимую с листом бумаги толщину — из-за антенны площадь будет все-таки значительной, не менее пятирублевой монеты), она может быть размещена практически в любом месте: на коробке с товаром, в журнале, на информационной стойке и других местах.
Пассивные метки NFC могут быть изготовлены в виде брелков
Если же говорить про собственноручное изготовление меток, то и это вполне осуществимый сценарий. Для этого нужно приобрести чистые заготовки и с использованием специальной программы для телефона записать на них требуемую информацию. Для примера мы купили несколько разных вариантов: наклейку минимальной толщины, защищенный кружочек из пластика и брелки.
Все они имели совсем небольшой объем памяти — всего 144 байта (на рынке присутствуют варианты и на 4 КБ). Число циклов перезаписи указано не было, но для большинства сценариев применения этот параметр не критичен. Для работы с метками можно рекомендовать программы NXP Semiconductors — TagInfo и TagWriter.
Чтение меток в NXP Semiconductors TagInfo
Первая позволит вам считать данные с метки и расшифровать информацию по стандарту NDEF, а вторая поможет создать собственные метки. При этом поддерживаются несколько подвариантов NDEF: контакт, ссылка, текст, SMS, почтовое сообщение, телефонный номер, соединение по Bluetooth, географическое расположение, ссылка на локальный файл, запуск приложения, URI.
Обратите внимание, что при создании записи нужно учитывать объем хранимых данных. Например, фотография контакта может занимать несколько килобайт, сообщения или текст также легко могут выйти за 144 байта. Кстати, программа NFC TagInfo компании NFC Research Lab со специальным плагином может прочитать и показать вам цветную фотографию из биометрического паспорта.
Запись меток в NXP Semiconductors TagWriter
Отметим, что автоматическая обработка считанных меток зависит от контента. В частности, иногда требуются дополнительные подтверждение для осуществления самого действия. Например, в случае SMS открывается заполненная форма сообщения, но собственно отправку должен подтвердить пользователь.
А вот записанная web-ссылка может сразу открываться в браузере. Любая автоматизация связана с потерей контроля, так что и описанные возможности стоит применять осторожно, поскольку простой заменой или перепрограммированием меток злоумышленники могут перенаправить вас на подставной сайт вместо оригинального. Штатных настроек ОС для ограничения подобного автозапуска мы не обнаружили (если только не отключить сам NFC).
Еще один важный момент при использовании меток в публичных местах — защита от перезаписи. При записи метки вы можете поставить флаг защиты, который будет блокировать все попытки изменения информации, но снять его будет уже невозможно. Так что метка будет в дальнейшем использоваться в режиме «только для чтения». Для домашнего применения это в большинстве случаев не очень критично.
Упомянем еще несколько программ для записи меток: