Основы NFC

В этом документе описаны основные задачи NFC, которые вы выполняете в Android. В нем объясняется, как отправлять и получать данные NFC в форме сообщений NDEF, и описываются API-интерфейсы платформы Android, которые поддерживают эти функции. Более сложные темы, включая обсуждение работы с данными, не относящимися к NDEF, см. в разделе Advanced NFC .

Чтение данных NDEF из тега NFC обрабатывается системой диспетчеризации тегов , которая анализирует обнаруженные теги NFC, соответствующим образом классифицирует данные и запускает приложение, заинтересованное в классифицированных данных. Приложение, которое хочет обрабатывать отсканированную метку NFC, может объявить фильтр намерений и запросить обработку данных.

Система отправки тегов

Устройства на базе Android обычно ищут метки NFC, когда экран разблокирован, если только NFC не отключен в меню настроек устройства. Когда устройство под управлением Android обнаруживает метку NFC, желательно, чтобы наиболее подходящее действие обрабатывало намерение, не спрашивая пользователя, какое приложение использовать. Поскольку устройства сканируют метки NFC на очень небольшом расстоянии, вполне вероятно, что если пользователям придется выбирать действие вручную, им придется отодвинуть устройство от метки и разорвать соединение. Вам следует разработать свою деятельность так, чтобы она обрабатывала только те NFC-теги, которые важны для вашей деятельности, чтобы предотвратить появление средства выбора активности.

Чтобы помочь вам в достижении этой цели, Android предоставляет специальную систему отправки тегов, которая анализирует отсканированные теги NFC, анализирует их и пытается найти приложения, которым интересны отсканированные данные. Это делается путем:

  1. Анализ тега NFC и определение типа MIME или URI, который идентифицирует полезные данные в теге.
  2. Инкапсуляция типа MIME или URI и полезных данных в намерение. Эти первые два шага описаны в разделе «Как теги NFC сопоставляются с типами MIME и URI» .
  3. Запускает действие на основе намерения. Это описано в разделе «Как теги 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» и ознакомьтесь с примерами создания записей NDEF в разделе «Создание общих типов записей NDEF».

Теперь, когда вы имеете некоторый опыт работы с тегами NFC, в следующих разделах более подробно описывается, как Android обрабатывает теги в формате NDEF. Когда устройство под управлением Android сканирует тег NFC, содержащий данные в формате NDEF, оно анализирует сообщение и пытается определить тип MIME данных или идентифицирующий URI. Для этого система считывает первую NdefRecord внутри NdefMessage , чтобы определить, как интерпретировать все сообщение NDEF (сообщение NDEF может иметь несколько записей NDEF). В правильно сформированном сообщении NDEF первая NdefRecord содержит следующие поля:

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 и типа с типами 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 на основе поля типа.
TNF_UNCHANGED Недопустимо в первой записи, поэтому возвращается к ACTION_TECH_DISCOVERED .
TNF_UNKNOWN Возвращается к ACTION_TECH_DISCOVERED .
TNF_WELL_KNOWN Тип MIME или URI в зависимости от определения типа записи (RTD), которое вы установили в поле типа. См. Таблицу 2 для получения дополнительной информации о доступных RTD и их сопоставлениях.

Таблица 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 и его идентификационную информацию, она отправляет намерение заинтересованному приложению, которое фильтрует это намерение. Если с намерением могут справиться несколько приложений, отображается окно выбора действия, позволяющее пользователю выбрать действие. Система отправки тегов определяет три намерения, которые перечислены в порядке от высшего к низшему приоритету:

  1. ACTION_NDEF_DISCOVERED : это намерение используется для запуска действия, когда тег, содержащий полезную нагрузку NDEF, сканируется и имеет распознанный тип. Это намерение с наивысшим приоритетом, и система отправки тегов пытается запустить действие с этим намерением раньше, чем с любым другим намерением, когда это возможно.
  2. ACTION_TECH_DISCOVERED : если не зарегистрировано никаких действий для обработки намерения ACTION_NDEF_DISCOVERED , система диспетчеризации тегов пытается запустить приложение с этим намерением. Это намерение также запускается напрямую (без предварительного запуска ACTION_NDEF_DISCOVERED ), если сканируемый тег содержит данные NDEF, которые невозможно сопоставить с типом MIME или URI, или если тег не содержит данных NDEF, но относится к известной технологии тегов.
  3. ACTION_TAG_DISCOVERED : это намерение запускается, если никакие действия не обрабатывают намерения ACTION_NDEF_DISCOVERED или ACTION_TECH_DISCOVERED .

Основной принцип работы системы отправки тегов заключается в следующем:

  1. Попробуйте запустить Activity с намерением, которое было создано системой диспетчеризации тегов при разборе тега NFC (либо ACTION_NDEF_DISCOVERED , либо ACTION_TECH_DISCOVERED ).
  2. Если никакие действия не фильтруются для этого намерения, попробуйте запустить действие со следующим намерением с наименьшим приоритетом ( ACTION_TECH_DISCOVERED или ACTION_TAG_DISCOVERED ), пока приложение не отфильтрует намерение или пока система отправки тегов не перепробует все возможные намерения.
  3. Если ни одно из приложений не фильтрует ни одно из намерений, ничего не делайте.
Рисунок 1. Система отправки тегов

По возможности работайте с сообщениями NDEF и намерением ACTION_NDEF_DISCOVERED , поскольку оно является наиболее конкретным из трех. Это намерение позволяет вам запустить приложение в более подходящее время, чем два других намерения, предоставляя пользователю лучший опыт.

Запросить доступ NFC в манифесте Android

Прежде чем вы сможете получить доступ к оборудованию NFC устройства и правильно обработать намерения NFC, объявите эти элементы в файле AndroidManifest.xml :

  • Элемент NFC <uses-permission> для доступа к оборудованию NFC:
    <uses-permission android:name="android.permission.NFC" />
    
  • Минимальная версия 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 :

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="text/plain" />
</intent-filter>

В следующем примере фильтруется URI в форме https://developer.android.com/index.html .

<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>

ACTION_TECH_DISCOVERED

Если ваша деятельность фильтрует намерение 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>
...
<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 используйте следующий фильтр намерений:

<intent-filter>
    <action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>

Получить информацию из намерений

Если действие начинается из-за намерения 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.
            ...
        }
    }
}

Ява

@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)

Ява

Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

Создание общих типов записей NDEF.

В этом разделе описывается, как создавать общие типы записей NDEF, которые помогут вам при записи в теги NFC. Начиная с Android 4.0 (уровень API 14), доступен метод createUri() , который помогает автоматически создавать записи URI. Начиная с Android 4.1 (уровень API 16), доступны createExternal() и createMime() , которые помогут вам создавать записи MIME и NDEF внешнего типа. По возможности используйте эти вспомогательные методы, чтобы избежать ошибок при создании записей 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
    )
}

Ява

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 будет выглядеть следующим образом:

<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>

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"))
)

Ява

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

Ява

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 будет выглядеть следующим образом:

<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>

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

Ява

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 будет выглядеть следующим образом:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="text/plain" />
</intent-filter>

TNF_WELL_KNOWN с RTD_URI

Запись TNF_WELL_KNOWN NDEF можно создать следующими способами:

Используя метод createUri(String) :

Котлин

val rtdUriRecord1 = NdefRecord.createUri("https://example.com")

Ява

NdefRecord rtdUriRecord1 = NdefRecord.createUri("https://example.com");

Используя метод createUri(Uri) :

Котлин

val rtdUriRecord2 = Uri.parse("https://example.com").let { uri ->
    NdefRecord.createUri(uri)
}

Ява

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)

Ява

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 будет выглядеть следующим образом:

<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>

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)

Ява

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
)

Ява

byte[] payload;
...
NdefRecord extRecord = new NdefRecord(
    NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType".getBytes(Charset.forName("US-ASCII")),
    new byte[0], payload);

Фильтр намерений для предыдущей записи NDEF будет выглядеть следующим образом:

<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>

Используйте 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 (AAR), представленная в Android 4.0 (уровень API 14), обеспечивает большую уверенность в том, что ваше приложение запускается при сканировании метки NFC. AAR содержит имя пакета приложения, встроенное в запись NDEF. Вы можете добавить AAR к любой записи NDEF вашего сообщения NDEF, поскольку Android ищет AAR во всем сообщении NDEF. Если он находит AAR, он запускает приложение на основе имени пакета внутри AAR. Если приложение отсутствует на устройстве, запускается Google Play для его загрузки.

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

Если тег содержит AAR, система отправки тегов осуществляет отправку следующим образом:

  1. Попробуйте запустить действие, используя фильтр намерений, как обычно. Если действие, соответствующее намерению, также соответствует AAR, запустите действие.
  2. Если действие, которое фильтрует намерение, не соответствует AAR, если несколько действий могут обработать намерение или если ни одно действие не обрабатывает намерение, запустите приложение, указанное в AAR.
  3. Если ни одно приложение не может запуститься с AAR, перейдите в Google Play, чтобы загрузить приложение на основе AAR.

Примечание. Вы можете переопределить AAR и систему отправки намерений с помощью системы отправки на переднем плане , которая позволяет активности на переднем плане иметь приоритет при обнаружении метки NFC. При использовании этого метода действие должно быть на переднем плане, чтобы переопределить AAR и систему отправки намерений.

Если вы по-прежнему хотите фильтровать сканированные теги, не содержащие AAR, вы можете объявить фильтры намерений обычными. Это полезно, если ваше приложение заинтересовано в других тегах, не содержащих AAR. Например, возможно, вы хотите гарантировать, что ваше приложение обрабатывает собственные теги, которые вы развертываете, а также общие теги, развернутые третьими лицами. Имейте в виду, что AAR специфичны для устройств Android 4.0 или более поздних версий, поэтому при развертывании тегов вы, скорее всего, захотите использовать комбинацию AAR и типов/URI MIME для поддержки самого широкого спектра устройств. Кроме того, при развертывании тегов 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")
        )
)

Ява

NdefMessage msg = new NdefMessage(
        new NdefRecord[] {
            ...,
            NdefRecord.createApplicationRecord("com.example.android.beam")}
        );
)