В этом документе описываются основные задачи NFC, выполняемые в Android. В нем объясняется, как отправлять и получать данные NFC в виде сообщений NDEF, а также описываются API-интерфейсы платформы Android, поддерживающие эти функции. Более подробные сведения, включая обсуждение работы с данными, не являющимися NDEF, см. в разделе «Расширенные возможности NFC» .
Reading NDEF data from an NFC tag is handled with the tag dispatch system , which analyzes discovered NFC tags, appropriately categorizes the data, and starts an application that is interested in the categorized data. An application that wants to handle the scanned NFC tag can declare an intent filter and request to handle the data.
Система отправки меток
Устройства на базе Android обычно ищут NFC-метки, когда экран разблокирован, если только NFC не отключен в меню настроек устройства. Когда устройство на базе Android обнаруживает NFC-метку, желаемое поведение заключается в том, чтобы наиболее подходящее действие обрабатывало намерение без запроса у пользователя, какое приложение использовать. Поскольку устройства сканируют NFC-метки на очень небольшом расстоянии, вероятно, что требование от пользователей вручную выбирать действие заставит их отодвинуть устройство от метки и разорвать связь. Вам следует разработать действие таким образом, чтобы оно обрабатывало только те NFC-метки, которые его интересуют, чтобы предотвратить появление окна выбора действия.
Для достижения этой цели Android предоставляет специальную систему обработки меток, которая анализирует отсканированные NFC-метки, обрабатывает их и пытается найти приложения, заинтересованные в отсканированных данных. Это достигается следующим образом:
- Анализ NFC-метки и определение MIME-типа или URI, идентифицирующего полезную нагрузку данных в метке.
- Инкапсуляция MIME-типа или URI и полезной нагрузки в намерение. Эти первые два шага описаны в разделе «Как NFC-метки сопоставляются с MIME-типами и URI» .
- Запускает действие в зависимости от намерения. Это описано в разделе «Как NFC-метки отправляются в приложения» .
Как NFC-метки сопоставляются с MIME-типами и URI.
Прежде чем начать разработку NFC-приложений, важно понимать различные типы NFC-меток, как система обработки меток анализирует NFC-метки и какие специальные действия выполняет система обработки меток при обнаружении сообщения NDEF. NFC-метки выпускаются с использованием самых разных технологий, и данные на них могут записываться различными способами. Android лучше всего поддерживает стандарт NDEF, разработанный NFC Forum .
Данные NDEF инкапсулируются в сообщение ( NdefMessage ), содержащее одну или несколько записей ( NdefRecord ). Каждая запись NDEF должна быть корректно сформирована в соответствии со спецификацией типа записи, которую вы хотите создать. Android также поддерживает другие типы меток, не содержащие данных NDEF, с которыми вы можете работать, используя классы из пакета android.nfc.tech . Чтобы узнать больше об этих технологиях, см. раздел «Расширенные возможности NFC» . Работа с этими другими типами меток предполагает написание собственного стека протоколов для связи с метками, поэтому мы рекомендуем использовать NDEF, когда это возможно, для упрощения разработки и максимальной поддержки устройств на базе Android.
Note: To download complete NDEF specifications, go to the NFC Forum Specifications & Application Documents site and see Creating common types of NDEF records for examples of how to construct NDEF records.
Now that you have some background in NFC tags, the following sections describe in more detail how Android handles NDEF formatted tags. When an Android-powered device scans an NFC tag containing NDEF formatted data, it parses the message and tries to figure out the data's MIME type or identifying URI. To do this, the system reads the first NdefRecord inside the NdefMessage to determine how to interpret the entire NDEF message (an NDEF message can have multiple NDEF records). In a well-formed NDEF message, the first NdefRecord contains the following fields:
- 3-битный TNF (формат имени типа)
- Указывает, как интерпретировать поле типа переменной длины. Допустимые значения описаны в таблице 1 .
- Тип переменной длины
- Описывает тип записи. Если используется
TNF_WELL_KNOWN, используйте это поле для указания определения типа записи (RTD). Допустимые значения RTD описаны в таблице 2 . - Идентификатор переменной длины
- Уникальный идентификатор записи. Это поле используется нечасто, но если вам необходимо однозначно идентифицировать тег, вы можете создать для него идентификатор.
- Полезная нагрузка переменной длины
- Фактический объем данных, которые вы хотите прочитать или записать. Сообщение NDEF может содержать несколько записей NDEF, поэтому не следует предполагать, что весь объем данных находится в первой записи NDEF сообщения NDEF.
Система отправки меток использует поля TNF и type для попытки сопоставления MIME-типа или URI с сообщением NDEF. В случае успеха, она инкапсулирует эту информацию в интенте ACTION_NDEF_DISCOVERED вместе с фактической полезной нагрузкой. Однако бывают случаи, когда система отправки меток не может определить тип данных на основе первой записи NDEF. Это происходит, когда данные NDEF не могут быть сопоставлены с MIME-типом или URI, или когда NFC-метка изначально не содержит данных NDEF. В таких случаях объект Tag , содержащий информацию о технологиях метки и полезной нагрузке, инкапсулируется в интенте ACTION_TECH_DISCOVERED .
В таблице 1 описано, как система диспетчеризации тегов сопоставляет поля TNF и type с типами MIME или URI. Также описано, какие поля TNF не могут быть сопоставлены с типом MIME или URI. В этих случаях система диспетчеризации тегов возвращается к значению ACTION_TECH_DISCOVERED .
Например, если система обработки тегов встречает запись типа TNF_ABSOLUTE_URI , она сопоставляет поле типа переменной длины этой записи с URI. Система обработки тегов инкапсулирует этот URI в поле данных интента ACTION_NDEF_DISCOVERED вместе с другой информацией о теге, такой как полезная нагрузка. С другой стороны, если она встречает запись типа TNF_UNKNOWN , она создает интент, который инкапсулирует технологии тега.
Таблица 1. Поддерживаемые TNF и их сопоставления.
| Формат имени типа (TNF) | Картографирование |
|---|---|
TNF_ABSOLUTE_URI | URI, основанный на поле типа. |
TNF_EMPTY | В случае отказа используется значение ACTION_TECH_DISCOVERED . |
TNF_EXTERNAL_TYPE | URI основан на URN в поле типа. URN кодируется в поле типа NDEF в сокращенном виде: <domain_name>:<service_name> . Android сопоставляет это с URI в формате: vnd.android.nfc://ext/ <domain_name>:<service_name> . |
TNF_MIME_MEDIA | MIME-тип определяется на основе поля type. |
TNF_UNCHANGED | В первой записи значение недопустимо, поэтому используется значение ACTION_TECH_DISCOVERED . |
TNF_UNKNOWN | В случае отказа используется значение ACTION_TECH_DISCOVERED . |
TNF_WELL_KNOWN | Тип MIME или URI зависит от определения типа записи (RTD), которое вы задаете в поле типа. Дополнительную информацию о доступных RTD и их сопоставлениях см. в таблице 2. |
Таблица 2. Поддерживаемые RTD для TNF_WELL_KNOWN и их сопоставления.
| Определение типа записи (RTD) | Картографирование |
|---|---|
RTD_ALTERNATIVE_CARRIER | В случае отказа используется значение ACTION_TECH_DISCOVERED . |
RTD_HANDOVER_CARRIER | В случае отказа используется значение ACTION_TECH_DISCOVERED . |
RTD_HANDOVER_REQUEST | В случае отказа используется значение ACTION_TECH_DISCOVERED . |
RTD_HANDOVER_SELECT | В случае отказа используется значение ACTION_TECH_DISCOVERED . |
RTD_SMART_POSTER | URI, основанный на анализе полезной нагрузки. |
RTD_TEXT | MIME-тип text/plain . |
RTD_URI | URI, основанный на полезной нагрузке. |
Как NFC-метки передаются в приложения
Когда система отправки меток завершает создание намерения, которое инкапсулирует NFC-метку и ее идентификационную информацию, она отправляет это намерение заинтересованному приложению, которое выполняет фильтрацию по данному намерению. Если несколько приложений могут обрабатывать данное намерение, отображается окно выбора действия, чтобы пользователь мог выбрать нужное действие. Система отправки меток определяет три намерения, которые перечислены в порядке от наивысшего к наинизшему приоритету:
-
ACTION_NDEF_DISCOVERED: Этот интент используется для запуска действия при сканировании тега, содержащего полезную нагрузку NDEF и имеющего распознанный тип. Это интент с наивысшим приоритетом, и система диспетчеризации тегов пытается запустить действие с этим интентом раньше любого другого, когда это возможно.Примечание: Начиная с Android 16, сканирование NFC-меток, хранящих URL-ссылки (т.е. схема URI "htttps://" или "http://"), будет запускать интент
ACTION_VIEWвместо интентаACTION_NDEF_DISCOVERED. -
ACTION_TECH_DISCOVERED: Если ни одно действие не зарегистрировалось для обработки намеренияACTION_NDEF_DISCOVERED, система диспетчеризации тегов пытается запустить приложение с этим намерением. Это намерение также запускается напрямую (без предварительного запускаACTION_NDEF_DISCOVERED), если сканируемый тег содержит данные NDEF, которые не могут быть сопоставлены с типом MIME или URI, или если тег не содержит данных NDEF, но относится к известной технологии тегов. -
ACTION_TAG_DISCOVERED: Этот интент запускается, если ни одно действие не обрабатывает интентыACTION_NDEF_DISCOVEREDилиACTION_TECH_DISCOVERED.
Основной принцип работы системы отправки тегов следующий:
- Попробуйте запустить Activity с намерением, созданным системой отправки меток при анализе NFC-метки (либо
ACTION_NDEF_DISCOVERED, либоACTION_TECH_DISCOVERED). - Если ни одно из действий не отфильтровывает данные для этого намерения, попытайтесь запустить действие со следующим намерением с самым низким приоритетом (либо
ACTION_TECH_DISCOVERED, либоACTION_TAG_DISCOVERED), пока приложение не отфильтрует данные для этого намерения или пока система диспетчеризации тегов не попробует все возможные намерения. - Если ни одно приложение не использует фильтры по каким-либо из указанных намерений, ничего не делайте.

По возможности используйте сообщения NDEF и интент ACTION_NDEF_DISCOVERED , поскольку он является наиболее специфичным из трех. Этот интент позволяет запускать приложение в более подходящее время, чем два других, обеспечивая пользователю лучший опыт.
Запросить доступ по NFC в манифесте Android
Прежде чем получить доступ к аппаратному обеспечению NFC устройства и корректно обрабатывать NFC-интенты, укажите следующие элементы в файле AndroidManifest.xml :
- Элемент NFC
<uses-permission>используется для доступа к NFC-оборудованию:<uses-permission android:name="android.permission.NFC" />
- Начиная с Android 17 (уровень API 37), для отправки NFC-интента в Activity, если приложение ориентировано на SDK >
Build.VERSION_CODES.BAKLAVA, оно должно быть защищено разрешениемandroid.permission.DISPATCH_NFC_MESSAGE. Это гарантирует, что только системная служба NFC может отправлять интенты в вашу Activity. Кроме того, система не будет отправлять NFC-интенты приложениям, находящимся в остановленном состоянии (например, если приложение никогда не запускалось пользователем или было принудительно остановлено).<activity android:name=".MyActivity" android:exported="true" android:permission="android.permission.DISPATCH_NFC_MESSAGE"> ... </activity>
- Минимальная версия SDK, которую может поддерживать ваше приложение. API уровня 9 поддерживает только ограниченную отправку тегов через
ACTION_TAG_DISCOVEREDи предоставляет доступ к сообщениям NDEF только через дополнительный параметрEXTRA_NDEF_MESSAGES. Никакие другие свойства тегов или операции ввода-вывода недоступны. API уровня 10 включает в себя всестороннюю поддержку чтения/записи, а также отправку NDEF-сообщений в фоновом режиме, а API уровня 14 предоставляет дополнительные удобные методы для создания записей NDEF.<uses-sdk android:minSdkVersion="10"/> - Элемент
uses-featureпозволяет вашему приложению отображаться в Google Play только для устройств, оснащенных NFC-модулем:<uses-feature android:name="android.hardware.nfc" android:required="true" />
Если ваше приложение использует функциональность NFC, но эта функциональность не является критически важной для вашего приложения, вы можете опустить элемент
uses-featureи проверять доступность NFC во время выполнения, проверяя, равен лиnullgetDefaultAdapter().
Фильтр по NFC-интентам
Чтобы запустить ваше приложение при сканировании NFC-метки, которую вы хотите обработать, ваше приложение может отфильтровать данные по одному, двум или всем трем NFC-интентам в манифесте Android. Однако обычно рекомендуется фильтровать данные по интенту ACTION_NDEF_DISCOVERED для максимального контроля над моментом запуска приложения. Интент ACTION_TECH_DISCOVERED является резервным вариантом для ACTION_NDEF_DISCOVERED , если ни одно приложение не фильтрует данные по ACTION_NDEF_DISCOVERED или если полезная нагрузка не является NDEF. Фильтрация по ACTION_TAG_DISCOVERED обычно слишком общая категория. Многие приложения будут фильтровать данные по ACTION_NDEF_DISCOVERED или ACTION_TECH_DISCOVERED перед ACTION_TAG_DISCOVERED , поэтому вероятность запуска вашего приложения низка. Параметр ACTION_TAG_DISCOVERED доступен только в крайнем случае, когда приложения не установлены для обработки намерений ACTION_NDEF_DISCOVERED или ACTION_TECH_DISCOVERED .
Поскольку способы установки NFC-меток различаются и зачастую не зависят от вас, это не всегда возможно, поэтому при необходимости можно использовать два других варианта. Если вы контролируете типы меток и записываемые данные, рекомендуется использовать NDEF для форматирования меток. В следующих разделах описано, как фильтровать данные по каждому типу.
ACTION_NDEF_DISCOVERED
To filter for ACTION_NDEF_DISCOVERED intents, declare the intent filter along with the type of data that you want to filter for. The following example filters for ACTION_NDEF_DISCOVERED intents with a MIME type of text/plain :
<activity android:name=".MyActivity" android:exported="true" android:permission="android.permission.DISPATCH_NFC_MESSAGE"> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain" /> </intent-filter> </activity>
В следующем примере фильтрация выполняется по URI в формате https://developer.android.com/index.html .
<activity android:name=".MyActivity" android:exported="true" android:permission="android.permission.DISPATCH_NFC_MESSAGE"> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="https" android:host="developer.android.com" android:pathPrefix="/index.html" /> </intent-filter> </activity>
ТЕХНОЛОГИИ ИЗОБРАЖЕНЫ
Если ваша активность фильтруется по намерению ACTION_TECH_DISCOVERED , необходимо создать XML-файл ресурсов, в котором указываются технологии, поддерживаемые вашей активностью, в рамках набора tech-list . Ваша активность считается соответствующей, если набор tech-list является подмножеством технологий, поддерживаемых тегом, который можно получить, вызвав getTechList() .
Например, если сканируемый тег поддерживает MifareClassic, NdefFormatable и NfcA, то для сопоставления вашей активности ваш набор tech-list должен указывать все три, два или одну из этих технологий (и ничего больше).
В приведенном ниже примере описаны все технологии. Необходимо удалить те, которые не поддерживаются вашей NFC-меткой. Сохраните этот файл (вы можете назвать его как угодно) в папке <project-root>/res/xml .
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <tech-list> <tech>android.nfc.tech.IsoDep</tech> <tech>android.nfc.tech.NfcA</tech> <tech>android.nfc.tech.NfcB</tech> <tech>android.nfc.tech.NfcF</tech> <tech>android.nfc.tech.NfcV</tech> <tech>android.nfc.tech.Ndef</tech> <tech>android.nfc.tech.NdefFormatable</tech> <tech>android.nfc.tech.MifareClassic</tech> <tech>android.nfc.tech.MifareUltralight</tech> </tech-list> </resources>
Вы также можете указать несколько наборов tech-list . Каждый из наборов tech-list рассматривается независимо, и ваша активность считается соответствующей, если хотя бы один набор tech-list является подмножеством технологий, возвращаемых функцией getTechList() . Это обеспечивает семантику AND и OR для сопоставления технологий. Следующий пример соответствует тегам, которые могут поддерживать технологии NfcA и Ndef или технологии NfcB и Ndef:
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <tech-list> <tech>android.nfc.tech.NfcA</tech> <tech>android.nfc.tech.Ndef</tech> </tech-list> <tech-list> <tech>android.nfc.tech.NfcB</tech> <tech>android.nfc.tech.Ndef</tech> </tech-list> </resources>
В файле AndroidManifest.xml укажите созданный вами файл ресурсов в элементе <meta-data> внутри элемента <activity> , как показано в следующем примере:
<activity android:name=".MyActivity" android:exported="true" android:permission="android.permission.DISPATCH_NFC_MESSAGE"> <intent-filter> <action android:name="android.nfc.action.TECH_DISCOVERED"/> </intent-filter> <meta-data android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filter" /> </activity>
Для получения дополнительной информации о работе с технологиями меток и намерением ACTION_TECH_DISCOVERED см. раздел «Работа с поддерживаемыми технологиями меток» в документе «Расширенные возможности NFC».
ACTION_TAG_DISCOVERED
Note: ACTION_TAG_DISCOVERED is deprecated starting Android 17 (API level 37). Use ACTION_NDEF_DISCOVERED or ACTION_TECH_DISCOVERED instead.
Для фильтрации по ACTION_TAG_DISCOVERED используйте следующий фильтр намерений:
<activity android:name=".MyActivity" android:exported="true" android:permission="android.permission.DISPATCH_NFC_MESSAGE"> <intent-filter> <action android:name="android.nfc.action.TAG_DISCOVERED"/> </intent-filter> </activity>
ДЕЙСТВИЕ_ПРОСМОТР
Начиная с Android 16, сканирование NFC-меток, хранящих URL-ссылки, будет запускать интент ACTION_VIEW . Чтобы отфильтровать результаты по ACTION_VIEW , см. this . Используйте Android app links , чтобы открыть ваше приложение по указанному URL-адресу.
Получение информации из намерений
Если действие запускается в результате NFC-интента, вы можете получить информацию о отсканированной NFC-метке из этого интента. Интенты могут содержать следующие дополнительные данные в зависимости от отсканированной метки:
-
EXTRA_TAG(обязательно): ОбъектTag, представляющий отсканированный тег. -
EXTRA_NDEF_MESSAGES(необязательно): Массив сообщений NDEF, полученных из тега. Этот дополнительный параметр является обязательным для интентовACTION_NDEF_DISCOVERED. -
EXTRA_ID(необязательно): Низкоуровневый идентификатор тега.
Чтобы получить эти дополнительные данные, проверьте, было ли ваше действие запущено с одним из NFC-интентов, чтобы убедиться, что метка была отсканирована, а затем получите дополнительные данные из интента. В следующем примере проверяется интент ACTION_NDEF_DISCOVERED и сообщения NDEF из дополнительных данных интента.
Котлин
override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) ... if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) { intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMessages -> val messages: List<NdefMessage> = rawMessages.map { it as NdefMessage } // Process the messages array. ... } } }
Java
@Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); ... if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); if (rawMessages != null) { NdefMessage[] messages = new NdefMessage[rawMessages.length]; for (int i = 0; i < rawMessages.length; i++) { messages[i] = (NdefMessage) rawMessages[i]; } // Process the messages array. ... } } }
В качестве альтернативы, вы можете получить объект Tag из интента, который будет содержать полезную нагрузку и позволит вам перечислить технологии, используемые в теге:
Котлин
val tag: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
Java
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Создание распространенных типов записей NDEF
В этом разделе описывается, как создавать распространенные типы записей NDEF, которые помогут вам при записи на NFC-метки. Начиная с Android 4.0 (уровень API 14), доступен метод createUri() , который позволяет автоматически создавать записи URI. Начиная с Android 4.1 (уровень API 16), доступны методы createExternal() и createMime() , которые помогут вам создавать записи NDEF MIME и external. Используйте эти вспомогательные методы, когда это возможно, чтобы избежать ошибок при ручном создании записей NDEF.
В этом разделе также описывается, как создать соответствующий фильтр намерений для записи. Все эти примеры записей NDEF должны находиться в первой записи NDEF сообщения NDEF, которое вы записываете в тег.
TNF_ABSOLUTE_URI
Примечание: Мы рекомендуем использовать тип RTD_URI вместо TNF_ABSOLUTE_URI , поскольку он более эффективен.
Создать запись TNF_ABSOLUTE_URI NDEF можно следующим образом:
Котлин
val uriRecord = ByteArray(0).let { emptyByteArray -> NdefRecord( TNF_ABSOLUTE_URI, "https://developer.android.com/index.html".toByteArray(Charset.forName("US-ASCII")), emptyByteArray, emptyByteArray ) }
Java
NdefRecord uriRecord = new NdefRecord( NdefRecord.TNF_ABSOLUTE_URI , "https://developer.android.com/index.html".getBytes(Charset.forName("US-ASCII")), new byte[0], new byte[0]);
Фильтр намерений для предыдущей записи NDEF будет выглядеть следующим образом:
<activity android:name=".MyActivity" android:exported="true" android:permission="android.permission.DISPATCH_NFC_MESSAGE"> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="https" android:host="developer.android.com" android:pathPrefix="/index.html" /> </intent-filter> </activity>
TNF_MIME_MEDIA
Создать запись TNF_MIME_MEDIA NDEF можно следующими способами:
Использование метода createMime() :
Котлин
val mimeRecord = NdefRecord.createMime( "application/vnd.com.example.android.beam", "Beam me up, Android".toByteArray(Charset.forName("US-ASCII")) )
Java
NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam", "Beam me up, Android".getBytes(Charset.forName("US-ASCII")));
Создание NdefRecord вручную:
Котлин
val mimeRecord = Charset.forName("US-ASCII").let { usAscii -> NdefRecord( NdefRecord.TNF_MIME_MEDIA, "application/vnd.com.example.android.beam".toByteArray(usAscii), ByteArray(0), "Beam me up, Android!".toByteArray(usAscii) ) }
Java
NdefRecord mimeRecord = new NdefRecord( NdefRecord.TNF_MIME_MEDIA , "application/vnd.com.example.android.beam".getBytes(Charset.forName("US-ASCII")), new byte[0], "Beam me up, Android!".getBytes(Charset.forName("US-ASCII")));
Фильтр намерений для предыдущей записи NDEF будет выглядеть следующим образом:
<activity android:name=".MyActivity" android:exported="true" android:permission="android.permission.DISPATCH_NFC_MESSAGE"> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="application/vnd.com.example.android.beam" /> </intent-filter> </activity>
TNF_WELL_KNOWN с RTD_TEXT
Создать запись TNF_WELL_KNOWN NDEF можно следующим образом:
Котлин
fun createTextRecord(payload: String, locale: Locale, encodeInUtf8: Boolean): NdefRecord { val langBytes = locale.language.toByteArray(Charset.forName("US-ASCII")) val utfEncoding = if (encodeInUtf8) Charset.forName("UTF-8") else Charset.forName("UTF-16") val textBytes = payload.toByteArray(utfEncoding) val utfBit: Int = if (encodeInUtf8) 0 else 1 shl 7 val status = (utfBit + langBytes.size).toChar() val data = ByteArray(1 + langBytes.size + textBytes.size) data[0] = status.toByte() System.arraycopy(langBytes, 0, data, 1, langBytes.size) System.arraycopy(textBytes, 0, data, 1 + langBytes.size, textBytes.size) return NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, ByteArray(0), data) }
Java
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) { byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII")); Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16"); byte[] textBytes = payload.getBytes(utfEncoding); int utfBit = encodeInUtf8 ? 0 : (1 << 7); char status = (char) (utfBit + langBytes.length); byte[] data = new byte[1 + langBytes.length + textBytes.length]; data[0] = (byte) status; System.arraycopy(langBytes, 0, data, 1, langBytes.length); System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length); NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data); return record; }
Фильтр намерений для предыдущей записи NDEF будет выглядеть следующим образом:
<activity android:name=".MyActivity" android:exported="true" android:permission="android.permission.DISPATCH_NFC_MESSAGE"> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> </activity>
TNF_WELL_KNOWN с RTD_URI
Создать запись TNF_WELL_KNOWN NDEF можно следующими способами:
Использование метода createUri(String) :
Котлин
val rtdUriRecord1 = NdefRecord.createUri("https://example.com")
Java
NdefRecord rtdUriRecord1 = NdefRecord.createUri("https://example.com");
Использование метода createUri(Uri) :
Котлин
val rtdUriRecord2 = Uri.parse("https://example.com").let { uri -> NdefRecord.createUri(uri) }
Java
Uri uri = Uri.parse("https://example.com"); NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);
Создание NdefRecord вручную:
Котлин
val uriField = "example.com".toByteArray(Charset.forName("US-ASCII")) val payload = ByteArray(uriField.size + 1) //add 1 for the URI Prefix payload [0] = 0x01 //prefixes https://www. to the URI System.arraycopy(uriField, 0, payload, 1, uriField.size) //appends URI to payload val rtdUriRecord = NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, ByteArray(0), payload)
Java
byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII")); byte[] payload = new byte[uriField.length + 1]; //add 1 for the URI Prefix payload[0] = 0x01; //prefixes https://www. to the URI System.arraycopy(uriField, 0, payload, 1, uriField.length); //appends URI to payload NdefRecord rtdUriRecord = new NdefRecord( NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);
Фильтр намерений для предыдущей записи NDEF будет выглядеть следующим образом:
<activity android:name=".MyActivity" android:exported="true" android:permission="android.permission.DISPATCH_NFC_MESSAGE"> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="https" android:host="example.com" android:pathPrefix="" /> </intent-filter> </activity>
TNF_EXTERNAL_TYPE
Создать запись TNF_EXTERNAL_TYPE NDEF можно следующими способами:
Использование метода createExternal() :
Котлин
var payload: ByteArray //assign to your data val domain = "com.example" //usually your app's package name val type = "externalType" val extRecord = NdefRecord.createExternal(domain, type, payload)
Java
byte[] payload; //assign to your data String domain = "com.example"; //usually your app's package name String type = "externalType"; NdefRecord extRecord = NdefRecord.createExternal(domain, type, payload);
Создание NdefRecord вручную:
Котлин
var payload: ByteArray ... val extRecord = NdefRecord( NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType".toByteArray(Charset.forName("US-ASCII")), ByteArray(0), payload )
Java
byte[] payload; ... NdefRecord extRecord = new NdefRecord( NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType".getBytes(Charset.forName("US-ASCII")), new byte[0], payload);
Фильтр намерений для предыдущей записи NDEF будет выглядеть следующим образом:
<activity android:name=".MyActivity" android:exported="true" android:permission="android.permission.DISPATCH_NFC_MESSAGE"> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="vnd.android.nfc" android:host="ext" android:pathPrefix="/com.example:externalType"/> </intent-filter> </activity>
Используйте TNF_EXTERNAL_TYPE для более универсального развертывания NFC-меток, чтобы лучше поддерживать как устройства на базе Android, так и устройства, не работающие под управлением Android.
Примечание : URN для TNF_EXTERNAL_TYPE имеют канонический формат: urn:nfc:ext:example.com:externalType , однако спецификация NFC Forum RTD указывает, что часть urn:nfc:ext: URN должна быть опущена в записи NDEF. Таким образом, вам нужно указать только домен ( example.com в примере) и тип ( externalType в примере), разделенные двоеточием. При отправке TNF_EXTERNAL_TYPE Android преобразует urn:nfc:ext:example.com:externalType в URI vnd.android.nfc://ext/example.com:externalType , что и указано в фильтре намерений в примере.
записи приложений Android
Введенная в Android 4.0 (уровень API 14) запись приложения Android (AAR) обеспечивает более высокую уверенность в том, что ваше приложение запускается при сканировании NFC-метки. AAR содержит имя пакета приложения, встроенное в запись NDEF. Вы можете добавить AAR к любой записи NDEF вашего сообщения NDEF, поскольку Android ищет AAR по всему сообщению NDEF. Если он находит AAR, он запускает приложение на основе имени пакета внутри AAR. Если приложение отсутствует на устройстве, запускается Google Play для его загрузки.
AAR-файлы полезны, если вы хотите предотвратить фильтрацию другими приложениями по тому же намерению и, возможно, обработку определенных тегов, которые вы развернули. AAR-файлы поддерживаются только на уровне приложения из-за ограничения по имени пакета, а не на уровне активности, как в случае фильтрации намерений. Если вы хотите обрабатывать намерение на уровне активности, используйте фильтры намерений .
Если метка содержит AAR, система отправки меток осуществляет отправку следующим образом:
- Попробуйте запустить Activity, используя фильтр намерений, как обычно. Если Activity, соответствующая намерению, также соответствует AAR, запустите Activity.
- Если Activity, выполняющая фильтрацию по намерению, не соответствует AAR, если несколько Activity могут обрабатывать намерение, или если ни одно Activity не обрабатывает намерение, запустите приложение, указанное в AAR.
- Если приложение, созданное на основе AAR, не запускается, перейдите в Google Play и загрузите приложение, созданное на основе AAR.
Примечание: Вы можете переопределить AAR и систему диспетчеризации намерений с помощью системы диспетчеризации на переднем плане , которая позволяет активности на переднем плане иметь приоритет при обнаружении NFC-метки. При этом методе активность должна находиться на переднем плане, чтобы переопределить AAR и систему диспетчеризации намерений.
Если вы все же хотите фильтровать отсканированные метки, не содержащие AAR, вы можете объявить фильтры намерений как обычно. Это полезно, если ваше приложение заинтересовано в других метках, не содержащих AAR. Например, вы можете захотеть гарантировать, что ваше приложение будет обрабатывать как собственные метки, которые вы развертываете, так и общие метки, развернутые сторонними разработчиками. Имейте в виду, что AAR специфичны для устройств Android 4.0 и более поздних версий, поэтому при развертывании меток, скорее всего, вам потребуется использовать комбинацию AAR и MIME-типов/URI для поддержки максимально широкого спектра устройств. Кроме того, при развертывании NFC-меток подумайте о том, как вы хотите записывать свои NFC-метки, чтобы обеспечить поддержку наибольшего количества устройств (на базе Android и других). Вы можете сделать это, определив относительно уникальный MIME-тип или URI, чтобы приложениям было проще их различать.
Android предоставляет простой API для создания AAR-файла — ` createApplicationRecord() . Всё, что вам нужно сделать, это встроить AAR-файл в любое место вашего NdefMessage . Не следует использовать первую запись вашего NdefMessage , если только AAR не является единственной записью в NdefMessage . Это связано с тем, что система Android проверяет первую запись ` NdefMessage , чтобы определить MIME-тип или URI тега, который используется для создания интента, который приложения могут фильтровать. Следующий код показывает, как создать AAR-файл:
Котлин
val msg = NdefMessage( arrayOf( ..., NdefRecord.createApplicationRecord("com.example.android.beam") ) )
Java
NdefMessage msg = new NdefMessage( new NdefRecord[] { ..., NdefRecord.createApplicationRecord("com.example.android.beam")} ); )
Список разрешенных приложений для сканирования NFC-меток
Начиная с Android 16, пользователи получают уведомление, когда приложение получает первое NFC-запрос на сканирование NFC-меток. В уведомлении пользователю предоставляется возможность запретить приложению дальнейшее сканирование NFC-меток.
- Приложения могут проверить, разрешил ли пользователь приложению сканирование NFC-меток, используя
NfcAdapter.isTagIntentAllowed(). - Приложения могут запросить у пользователя разрешение на повторное сканирование NFC-меток, отправив намерение
ACTION_CHANGE_TAG_INTENT_PREFERENCE.
Примечание: Список разрешенных приложений для сканирования NFC-меток доступен в разделе Settings > Apps > Special app access > Launch via NFC .