В этом документе описаны основные задачи NFC, которые вы выполняете в Android. В нем объясняется, как отправлять и получать данные NFC в виде сообщений NDEF, и описываются API-интерфейсы платформы Android, поддерживающие эти функции. Дополнительную информацию, в том числе о работе с данными, не относящимися к NDEF, можно найти в статье Расширенные возможности NFC.
Чтение данных NDEF из NFC-метки обрабатывается системой диспетчеризации меток, которая анализирует обнаруженные NFC-метки, соответствующим образом классифицирует данные и запускает приложение, заинтересованное в классифицированных данных. Приложение, которое хочет обработать отсканированную NFC-метку, может объявить фильтр интентов и запросить обработку данных.
Система отправки тегов
Устройства Android обычно ищут NFC-метки, когда экран разблокирован, если только NFC не отключен в меню настроек устройства. Когда устройство Android обнаруживает NFC-метку, наиболее подходящее действие должно обработать интент, не спрашивая пользователя, какое приложение использовать. Поскольку устройства сканируют NFC-теги на очень коротком расстоянии, необходимость вручную выбирать действие может заставить пользователей отодвинуть устройство от тега и прервать соединение. Настройте обработку только тех NFC-меток, которые нужны для работы вашего Activity, чтобы избежать появления окна выбора действий.
Чтобы помочь вам в этом, 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.
Примечание. Чтобы скачать полные спецификации NDEF, перейдите на сайт NFC Forum Specifications & Application Documents. Примеры создания записей NDEF можно найти в статье Создание распространенных типов записей NDEF.
Теперь, когда у вас есть некоторые знания о NFC-метках, в следующих разделах более подробно описывается, как Android обрабатывает NFC-метки в формате NDEF. Когда устройство Android сканирует NFC-метку, содержащую данные в формате NDEF, оно анализирует сообщение и пытается определить MIME-тип данных или идентифицирующий URI. Для этого система считывает первый элемент NdefRecord внутри NdefMessage, чтобы определить, как интерпретировать все сообщение NDEF (сообщение NDEF может содержать несколько записей NDEF). В правильно сформированном сообщении NDEF первая запись NdefRecord содержит следующие поля:
- 3-битный TNF (Type Name Format)
- Указывает, как интерпретировать поле типа переменной длины. Допустимые значения перечислены в таблице 1.
- Тип переменной длины
- Описывает тип записи. Если вы используете
TNF_WELL_KNOWN, укажите в этом поле определение типа записи (RTD). Допустимые значения RTD описаны в таблице 2. - Идентификатор переменной длины
- Уникальный идентификатор записи. Это поле используется редко, но если вам нужно уникально идентифицировать тег, вы можете создать для него идентификатор.
- Полезная нагрузка переменной длины
- Фактические данные, которые вы хотите прочитать или записать. Сообщение NDEF может содержать несколько записей NDEF, поэтому не думайте, что вся полезная нагрузка находится в первой записи NDEF сообщения NDEF.
Система диспетчеризации тегов использует поля TNF и типа, чтобы сопоставить MIME-тип или URI с сообщением NDEF. Если все в порядке, то эта информация вместе с полезной нагрузкой инкапсулируется в намерение ACTION_NDEF_DISCOVERED. Однако в некоторых случаях система диспетчеризации тегов не может определить тип данных на основе первой записи NDEF. Это происходит, когда данные NDEF не могут быть сопоставлены с MIME-типом или URI или когда NFC-метка не содержит данных NDEF. В таких случаях объект Tag, содержащий информацию о технологиях тега и полезной нагрузке, инкапсулируется в намерение ACTION_TECH_DISCOVERED.
В таблице 1 показано, как система диспетчеризации тегов сопоставляет поля TNF и типа с 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 на основе поля type. |
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), которое вы задаете в поле type. Дополнительную информацию о доступных 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-метку и ее идентифицирующую информацию, она отправляет интент заинтересованному приложению, которое фильтрует интент. Если интент может обработать несколько приложений, пользователю предлагается выбрать Activity. Система диспетчеризации тегов определяет три намерения, которые перечислены в порядке от наивысшего приоритета к наименьшему:
-
ACTION_NDEF_DISCOVERED– используется для запуска Activity, когда сканируется тег, содержащий полезную нагрузку NDEF и относящийся к распознанному типу. Это намерение с наивысшим приоритетом, и система отправки тегов пытается запустить Activity с этим интентом перед любым другим интентом, когда это возможно.Примечание. Начиная с Android 16, при сканировании NFC-меток, в которых хранятся веб-ссылки (то есть схема URI – http:// или https://), активируется намерение
ACTION_VIEW, а неACTION_NDEF_DISCOVERED. Начиная с Android 17, при сканировании такого тега появляется уведомление "Открыть ссылку", требующее явного взаимодействия с пользователем для запуска намеренияACTION_VIEW. 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). - Если ни одно действие не отфильтровано для этого интента, попробуйте запустить Activity с интентом следующего самого низкого приоритета (
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-интент, приложение, предназначенное для SDK >
Build.VERSION_CODES.BAKLAVA, должно быть защищено разрешениемandroid.permission.DISPATCH_NFC_MESSAGE. Это гарантирует, что только системный сервис NFC может отправлять намерения в ваше действие. Кроме того, система не будет отправлять намерения 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 во время выполнения, проверяя, является лиgetDefaultAdapter()null.
Фильтр для намерений 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
Чтобы отфильтровать интенты ACTION_NDEF_DISCOVERED, объявите фильтр интентов вместе с типом данных, которые вы хотите отфильтровать. В следующем примере показано, как отфильтровать намерения ACTION_NDEF_DISCOVERED с MIME-типом 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
Если ваше действие фильтрует intent 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 можно найти в разделе Работа с поддерживаемыми технологиями тегов документа Advanced NFC.
ACTION_TAG_DISCOVERED
Примечание. ACTION_TAG_DISCOVERED не поддерживается начиная с Android 17 (уровень API 37). Используйте ACTION_NDEF_DISCOVERED или ACTION_TECH_DISCOVERED.
Чтобы отфильтровать ACTION_TAG_DISCOVERED, используйте следующий фильтр intent:
<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>
ACTION_VIEW
Начиная с Android 16 сканирование NFC-меток, в которых хранятся веб-ссылки (то есть схема URI – http:// или https://), запускает намерение ACTION_VIEW вместо ACTION_NDEF_DISCOVERED. Начиная с Android 17, при сканировании такого тега появляется уведомление "Открыть ссылку", и для запуска намерения 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 из дополнительных данных намерения.
Kotlin
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 из намерения, который будет содержать полезную нагрузку и позволит вам перечислить технологии тега:
Kotlin
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 и внешними типами. По возможности используйте эти вспомогательные методы, чтобы избежать ошибок при создании записей NDEF вручную.
В этом разделе также описывается, как создать соответствующий фильтр намерений для записи. Все эти примеры записей NDEF должны находиться в первой записи NDEF сообщения NDEF, которое вы записываете в тег.
TNF_ABSOLUTE_URI
Примечание. Рекомендуем использовать тип RTD_URI вместо TNF_ABSOLUTE_URI, поскольку он более эффективен.
Создать запись NDEF TNF_ABSOLUTE_URI можно следующим образом:
Kotlin
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
Создать запись NDEF TNF_MIME_MEDIA можно следующими способами:
При использовании метода createMime():
Kotlin
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 вручную:
Kotlin
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
Создать запись NDEF TNF_WELL_KNOWN можно следующим образом:
Kotlin
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
Создать запись NDEF TNF_WELL_KNOWN можно следующими способами:
При использовании метода createUri(String):
Kotlin
val rtdUriRecord1 = NdefRecord.createUri("https://example.com")
Java
NdefRecord rtdUriRecord1 = NdefRecord.createUri("https://example.com");
При использовании метода createUri(Uri):
Kotlin
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 вручную:
Kotlin
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
Создать запись NDEF TNF_EXTERNAL_TYPE можно следующими способами:
При использовании метода createExternal():
Kotlin
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 вручную:
Kotlin
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, так и на других платформах.
Примечание. 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 urn:nfc:ext:example.com:externalType
в URI vnd.android.nfc://ext/example.com:externalType, который объявляется фильтром интентов в примере.
Записи приложений для Android
Запись Android Application Record (AAR), появившаяся в Android 4.0 (уровень API 14), повышает вероятность того, что приложение для Android запустится при сканировании NFC-метки. В AAR содержится название пакета приложения, встроенное в запись NDEF. Вы можете добавить запись AAR к любой записи NDEF в сообщении NDEF, поскольку Android ищет записи AAR по всему сообщению NDEF. Если запись AAR найдена, запускается приложение, название пакета которого указано в этой записи. Если приложение не установлено на устройстве, откроется Google Play, где его можно будет скачать.
Это полезно, если вы хотите, чтобы другие приложения не могли фильтровать по тому же намерению и обрабатывать определенные теги, которые вы развернули. Из-за ограничений, связанных с названием пакета, AAR поддерживаются только на уровне приложения, а не на уровне Activity, как в случае с фильтрацией интентов. Если вы хотите обрабатывать интент на уровне Activity, используйте фильтры интентов.
Если тег содержит AAR, система отправки тегов работает следующим образом:
- Попробуйте запустить Activity, используя фильтр интентов, как обычно. Если Activity, соответствующее намерению, также соответствует AAR, запустите Activity.
- Если объект Activity, который фильтрует intent, не соответствует AAR, если несколько объектов Activity могут обработать intent или если ни один объект Activity не обрабатывает intent, запустите приложение, указанное в AAR.
- Если ни одно приложение не может запуститься с помощью AAR, перейдите в Google Play и скачайте приложение, основанное на AAR.
Примечание. Вы можете переопределить записи AAR и систему диспетчеризации намерений с помощью системы диспетчеризации переднего плана, которая позволяет действию переднего плана иметь приоритет при обнаружении NFC-метки. При этом приложение должно быть активным, чтобы переопределить AAR и систему диспетчеризации намерений.
Если вы по-прежнему хотите отфильтровать отсканированные теги, которые не содержат AAR, вы можете объявить фильтры интентов как обычно. Это полезно, если ваше приложение работает с другими тегами, которые не содержат AAR. Например, вы можете гарантировать, что ваше приложение обрабатывает как собственные теги, которые вы развертываете, так и общие теги, развернутые третьими лицами. Помните, что записи AAR поддерживаются только на устройствах с Android 4.0 и более поздними версиями. Поэтому при развертывании тегов лучше использовать комбинацию записей AAR и MIME-типов/URI, чтобы обеспечить поддержку как можно большего количества устройств. Кроме того, при развертывании NFC-меток подумайте, как вы хотите их записать, чтобы обеспечить поддержку большинства устройств (на базе Android и других). Для этого задайте относительно уникальный MIME-тип или URI, чтобы приложениям было проще различать их.
В Android есть простой API для создания AAR:
createApplicationRecord(). Вам нужно лишь встроить AAR в любое место в NdefMessage. Не используйте первую запись NdefMessage, если только автоматическое применение рекомендаций не является единственной записью в NdefMessage. Это связано с тем, что система Android проверяет первую запись NdefMessage, чтобы определить MIME-тип или URI тега, который используется для создания намерения, фильтруемого приложениями. В следующем коде показано, как создать AAR:
Kotlin
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-метки, с помощью
NfcAdapter.isTagIntentAllowed(). - Приложения могут предлагать пользователю разрешить сканирование NFC-меток, отправляя намерение
ACTION_CHANGE_TAG_INTENT_PREFERENCE.
Примечание. Белый список приложений для сканирования NFC-меток доступен в разделе Settings > Apps > Special app access > Launch via NFC.