Реалізація читання/запису NFC-міток через мобільний застосунок
Ми часто стикаємося з ситуацією, коли 30–40% перших запитів до NFC-мітки повертають NFCReaderError.readerTransceiveErrorTagConnectionLost на iOS або IOException: Tag lost на Android. Причина — надто коротке утримання телефону, interference від металевих поверхонь або неправильний тайм-аут сесії. Без системного підходу інтеграція перетворюється на нескінченне налагодження.
Чому виникають помилки читання NFC?
iOS: обмеження CoreNFC
CoreNFC з'явився відносно давно, але повноцінне читання та запис NDEF стало доступним лише в пізніших версіях iOS. Якщо проект таргетує старі версії, половина користувачів залишиться без NFC. Другий камінь — NFCNDEFReaderSession проти NFCTagReaderSession. Перший працює тільки з NDEF-сумісними мітками. Якщо клієнт приніс Mifare Classic, він просто не запрацює: Apple не підтримує цей протокол з міркувань безпеки. Потрібно заздалегідь перевірити тип мітки та використовувати NFCTagReaderSession з NFCMiFareTag для Mifare Ultralight або NFCISO7816Tag для смарт-карт.
Ще одне вузьке місце — Background Tag Reading. Застосунок не запущено, користувач підносить телефон до мітки — система читає NDEF-URI та запускає застосунок. Виглядає магічно, але вимагає com.apple.developer.nfc.readersession.formats в entitlements з NDEF, плюс URL-схему або Universal Link. Якщо забути додати домен в apple-app-site-association, deep link просто не відкриється.
Android: фрагментація NFC-стека
На Android NfcAdapter.ACTION_NDEF_DISCOVERED, ACTION_TAG_DISCOVERED, ACTION_TECH_DISCOVERED — три різних інтенти з різним пріоритетом. Якщо оголосити тільки NDEF, то мітка без NDEF-структури піде в інший застосунок. Foreground dispatch через enableForegroundDispatch() вирішує це, але вимагає чіткого життєвого циклу: вмикати в onResume, вимикати в onPause. Один пропущений виклик — і застосунок починає отримувати NFC-інтенти навіть коли не активний.
Для запису NDEF: якщо мітка write-protected або відформатована під інший тип, tag.connect() зависне або викине IOException. Потрібен явний тайм-аут через tag.setTimeout() і retry-логіка з експоненційним backoff. Наш досвід показує, що грамотна обробка помилок скорочує кількість збоїв втричі.
Як забезпечити стабільне читання NFC на обох платформах?
iOS
Працюємо з CoreNFC через NFCNDEFReaderSession для стандартних сценаріїв та NFCTagReaderSession для нестандартних форматів. Для запису створюємо NFCNDEFMessage з потрібними NFCNDEFPayload. Використовуємо NFCNDEFPayload.wellKnownTypeURIPayload() для URI-записів — це виключає помилки TNF-заголовків. Сесію обгортаємо в async/await через Continuation, щоб не тягнути delegate-ланцюжок. Помилки мапимо на зрозумілі стани — sessionTimeout, tagNotCompatible, writeProtected — і показуємо через нативний alert або власний UI. Середній час читання мітки — 0.3 секунди, 98% сесій завершуються успішно при правильному утриманні.
Android
Використовуємо Ndef та NdefFormatable tech-класи через Tag.getTechList(). Перед записом перевіряємо ndef.isWritable() та ndef.maxSize() — типова помилка: намагатися записати 500 байт на 144-байтну Ntag213. Для форматування чистих міток використовуємо NdefFormatable.format() з мінімальним початковим повідомленням.
Весь NFC-код виносимо в NfcRepository з Flow<NfcEvent>, UI-шар підписується через collectLatest. При повороті екрана сесія не переривається — foreground dispatch відновлюється в onResume. Такий підхід випробуваний на 15+ проектах. Гарантуємо стабільність сесії навіть на складних конфігураціях.
Підтримувані формати міток
| Тип мітки | iOS | Android | Примітки |
|---|---|---|---|
| NDEF (Ntag213/215/216) | ✓ | ✓ | Найпоширеніші |
| Mifare Ultralight | ✓ (ISO7816) | ✓ | Вимагає NFCTagReaderSession на iOS |
| Mifare Classic | ✗ | ✓ | Apple не підтримує |
| ISO 15693 | ✓ (iOS 14+) | ✓ | Для промислових міток |
| FeliCa | ✓ (тільки Японія) | ✓ | Транспортні картки |
Порівняння iOS та Android
| Аспект | iOS | Android |
|---|---|---|
| Стабільність сесії | Висока, але жорсткі обмеження за типами | Нижча через фрагментацію, але гнучкіша |
| Підтримка типів міток | Обмежена (без Mifare Classic) | Широка, включаючи всі популярні |
| Background reading | iOS 13+, вимагає entitlements | Android 10+, Beam застарів |
| Складність конфігурації | Вища (entitlements, provisioning) | Нижча (маніфест + dispatch) |
Типові помилки та як їх уникнути
- Tag Lost на iOS: збільшити тайм-аут, додати retry, інформувати користувача.
- Write захищеної мітки: перевіряти
isWritable()та повідомляти. - Переривання сесії при повороті екрана Android: винос логіки в репозиторій з Flow.
- Несумісність типів міток: проводити аудит перед розробкою.
Що входить в роботу
- Аудит: визначаємо типи міток, обсяг даних, чи потрібен background reading, платформи. Враховуємо комерційну економію бюджету до 20% за рахунок правильного вибору стека.
- Проектування: вибір tech-класів, архітектура (репозиторій з Flow/async/await).
- Реалізація: unit-тести на mock-тегах (NFCNDEFReaderSessionMock на iOS, MockNdefTag на Android).
- Тестування на реальних мітках NXP, Broadcom, ST Microelectronics.
- Документація з інтеграції та інструкція для користувачів.
- Супровід протягом 30 днів після здачі.
Отримайте консультацію щодо вашого проекту — оцінимо обсяг і терміни. Замовте аудит NFC-інтеграції: ми проаналізуємо ваші мітки, платформи та сценарії використання.
Процес роботи
- Вивчення — аналіз вимог, типів міток, умов використання.
- Проектування — вибір стека, створення прототипу сесії.
- Розробка — реалізація з тестами на емуляторах та реальних пристроях.
- Тестування — на 10+ зразках міток різних виробників.
- Запуск — публікація в App Store / Google Play, налаштування background reading.
Терміни та вартість
Базова інтеграція читання/запису NDEF на одній платформі займає 3–5 робочих днів. Якщо потрібні нестандартні формати, background reading або підтримка кількох типів міток — від 2 тижнів. Точну оцінку даємо після аудиту.
Посилання:







