Насколько зрела поддержка Android NFC ISODep?
Я понимаю, что это тема для обсуждения, на которую нет однозначного ответа, но мне бы очень хотелось получить отзывы о том, чего ожидать при разработке приложений NFC для Android, в частности, об использовании IsoDep для связи с картами DESFire с использованием фреймов APDU.
- Можно ли ожидать, что одни и те же кадры APDU, отправленные на конкретную карту DESFire, одинаково реагируют на устройства и версии Android?
- Какие версии Android и устройства я должен тестировать как минимум, чтобы быть достаточно хорошо покрытыми?
- Это часто встречается с ошибками или регрессиями в драйверах Android или я могу ожидать, что они давно устранены?
- Какую самую раннюю версию Android вы рекомендуете поддерживать, чтобы избежать лишних проблем?
Пока что мой опыт был на удивление неоднозначным (3 устройства, 3 отличия), и мне бы очень хотелось услышать мнение других разработчиков. Например: те же самые команды APDU, которые работают на S3 (Android 4.1.2), не работают на S4 (Android 4.3) (ошибка "неправильной длины" при 3-м рукопожатии при аутентификации, все в порядке до тех пор). Эти телефоны имеют разные чипсеты NFC, но я не ожидал отличий в уровне абстракции кадров APDU.
2 ответа
Это действительно тема для обсуждения, но я думаю, что она актуальна для разработчиков Android NFC, и поэтому я приведу свой опыт здесь:
- Можно ли ожидать, что одни и те же кадры APDU, отправленные на конкретную карту DESFire, одинаково реагируют на устройства и версии Android?
Да, но только для команд APDU, которые соответствуют требованиям ISO/IEC 7816-4 с некоторыми дополнительными ограничениями (например, не все устройства поддерживают APDU расширенной длины, у некоторых устройств, похоже, возникают проблемы с APDU варианта 1).
Также есть некоторые известные ошибки в последней версии стека Broadcom NFC (см. Ниже).
- Какие версии Android и устройства я должен тестировать как минимум, чтобы быть достаточно хорошо покрытыми?
Большинство проблем, с которыми я сталкивался до сих пор, были с устройствами Samsung с чипсетом Broadcom NFC. Хотя они не связаны с APDU, особенно когда речь идет об использовании MIFARE Classic, они ведут себя совершенно иначе, чем другие устройства с чипсетом Broadcom. Например, S4 блокирует классические теги MIFARE на системном уровне и, следовательно, не позволяет читать теги (N)UID. (Чтение данных из MF Classic было бы невозможно с чипсетами Broadcom в любом случае...)
Что касается тестирования, я бы поэтому предложил по крайней мере одно устройство Nexus для каждого контроллера NFC (т.е. одно с набором микросхем NXP и одно с набором микросхем Broadcom) и то же самое для одного или двух других производителей мобильных телефонов. (Для Samsung устройства с набором микросхем NXP ведут себя очень похоже на устройства Nexus, поэтому я полагаю, что вы Nexus S/Galaxy Nexus и, например, S3 можно рассматривать как эквивалентные, когда дело доходит до режима чтения / записи NFC.)
Что касается платформ Android, я бы придерживался тех платформ, на которых у вас больше всего пользователей. (А также те платформы, где у вас высокие показатели удаления.)
- Это часто встречается с ошибками или регрессиями в драйверах Android или я могу ожидать, что они давно устранены?
Как я уже говорил, есть некоторые известные проблемы со стеком Broadcom NFC. В частности, когда речь идет о MIFARE DESFire, существует известная проблема, заключающаяся в том, что стек NFC отправляет произвольные команды на основе APDU на карту после передачи ее в приложение. Как следствие, эти команды могут мешать текущему обмену данными между картой и этим приложением (например, включить режим связи на основе APDU вместо основного командного режима, изменить выбор приложения / файла и т. Д.). См. Этот отчет об ошибке и этот вопрос о стекопереработке для получения дополнительной информации.
И, глядя через багтрекер, определенно есть еще нерешенные проблемы.
- Какую самую раннюю версию Android вы рекомендуете поддерживать, чтобы избежать лишних проблем?
Что касается связи на основе APDU (с DESFire или с другими картами), API 10 (Android 2.3.3) и выше работают нормально. Когда дело доходит до удобства использования NFC API (помимо простого обмена APDU) и хорошего дизайна приложений, я бы остановился на Android 4.0.3 и более поздних версиях. Но имейте в виду, что на новейших платформах, в частности, Android 4.3 и Android 4.4, появилось много странных поведений / ошибок /("функций"?).
Чтобы понять, какие версии Android есть у пользователей с NFC-устройствами, я поделюсь текущим дистрибутивом установки устройств для NFC TagInfo (хотя это может быть слегка предвзятым, поскольку NFC TagInfo не предназначен для обычного пользователя):
- Android 4.1: 36%
- Android 4.3: 21%
- Android 4.2: 19%
- Android 4.4: 18%
- Android 4.0.3 - 4.0.4: 4%
- Android 2.3.3 - 2.3.7: 2%
- Android 4.0 - 4.0.2: 0%
- Android 3.2: 0%
Этот ответ связан с вашей конкретной проблемой с APDU, работающими на одном устройстве, но не работающими на других. Как отметил Майкл Роланд, существует проблема, связанная с тем, что устройства, использующие стек NCI NFC, часто отправляют APDU, которые могут мешать APDU, отправляемым вашим приложением. Проблема связана с неправильной реализацией проверки присутствия в этом стеке и задокументирована здесь. Это особенно проблематично при выполнении процедуры аутентификации на картах DESFire, поскольку она состоит из нескольких APDU и завершится ошибкой, если будет прервана несвязанными APDU. Однако существует обходной путь для устройств, работающих на Android версии>= 4.4 (уровень API>= 19). На этих устройствах вы можете использовать метод enableReaderMode с дополнительным параметром EXTRA_READER_PRESENCE_CHECK_DELAY для настройки частоты проверки присутствия. Увеличив задержку, вы можете уменьшить вероятность вмешательства в APDU вашего приложения.
Например:
Bundle options = new Bundle();
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 5000);
getNfcAdapter().enableReaderMode(
this,
new ReaderCallback() {
@Override
public void onTagDiscovered(final Tag tag) {
// ... authenticate ...
}
},
NfcAdapter.FLAG_READER_NFC_A
| NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, options);