NFC Tag Read/Write Implementation via Mobile Application
NFC tags are not about "tap and it works". In practice, 30–40% of first requests to a tag return NFCReaderError.readerTransceiveErrorTagConnectionLost on iOS or IOException: Tag lost on Android before even reading NDEF header. Reason — too brief phone contact with tag, interference from metal surfaces or incorrect session timeout.
Where Integration Most Often Breaks
iOS: CoreNFC Limitations and Tag Types
Apple added CoreNFC in iOS 11, but full read/write NDEF appeared only in iOS 13. Still encounter projects targeting iOS 12 unable to explain why half users' tags "don't read".
Second issue — NFCNDEFReaderSession vs NFCTagReaderSession. First type works only with NDEF-compatible tags. If client brings Mifare Classic — simply won't work: Apple doesn't support this protocol for security reasons. Must check tag type early and use NFCTagReaderSession with NFCMiFareTag for Mifare Ultralight or NFCISO7816Tag for smart cards with APDU commands.
Another painful point — Background Tag Reading available since iOS 13 on iPhone XS/XR+. App not running, user holds phone to tag — system reads NDEF-URI and launches app. Looks magical. But requires com.apple.developer.nfc.readersession.formats in entitlements with NDEF, plus URL scheme or Universal Link. Forgetting to add domain to apple-app-site-association — deep link simply won't open.
Android: NFC Stack Fragmentation
On Android NfcAdapter.ACTION_NDEF_DISCOVERED, ACTION_TAG_DISCOVERED, ACTION_TECH_DISCOVERED — three different intents with different dispatch priority. Declaring only NDEF_DISCOVERED means NDEF-format tag intercepted correctly, but "raw" tag without NDEF structure goes to another app or nowhere.
Foreground dispatch via NfcAdapter.enableForegroundDispatch() solves this, but requires strict lifecycle: enable in onResume, disable in onPause. One missed disableForegroundDispatch — app starts receiving NFC intents even when inactive, breaking UX.
For NDEF writing on Android: if tag write-protected or formatted differently — tag.connect() hangs or throws IOException. Need explicit timeout via tag.setTimeout() for specific tech class and retry logic with exponential backoff.
How We Implement
iOS — Stack and Approach
Work with CoreNFC via NFCNDEFReaderSession for standard scenarios and NFCTagReaderSession for non-standard formats. For writing — create NFCNDEFMessage with needed NFCNDEFPayload, use NFCNDEFPayload.wellKnownTypeURIPayload() for URI entries instead of manual byte encoding, eliminating TNF header errors.
Wrap session in async/await via Continuation to avoid delegate chains through ViewModel. Map errors to user-friendly states — sessionTimeout, tagNotCompatible, writeProtected — show via native NFCReaderSession alert or custom UI.
Android — Stack and Approach
Use Ndef and NdefFormatable tech classes via Tag.getTechList(). Before writing check ndef.isWritable() and ndef.maxSize() — typical error: trying to write 500 bytes to 144-byte Ntag213. For formatting blank tags use NdefFormatable.format() with minimal initial message.
Extract all NFC code to NfcRepository with Flow<NfcEvent>, UI subscribes via collectLatest. Configuration change (screen rotation) doesn't interrupt session — Activity reopens, foreground dispatch restored in onResume.
Supported Tag Formats
| Tag Type | iOS | Android | Notes |
|---|---|---|---|
| NDEF (Ntag213/215/216) | ✓ | ✓ | Most common |
| Mifare Ultralight | ✓ (ISO7816) | ✓ | Requires NFCTagReaderSession on iOS |
| Mifare Classic | ✗ | ✓ | Apple doesn't support |
| ISO 15693 | ✓ (iOS 14+) | ✓ | For industrial tags |
| FeliCa | ✓ (Japan only) | ✓ | Transport cards |
Work Process
Start with audit: which tag types used, what data volume written, need background reading, need write or read-only. This determines tech class choice and entitlements/manifest permissions.
Then — development with unit tests on mock tags via NFCNDEFReaderSessionMock (iOS) and MockNdefTag (Android). Final testing — on real tags from different makers: NXP, Broadcom, ST Microelectronics behave slightly differently even within one standard.
Timeframes
Basic read/write NDEF integration on one platform — 3–5 work days. Non-standard formats, background reading, multiple tag type support — from 2 weeks. Estimate after requirements analysis.







