sendApdu sends one. The full API, including
chaining and the 61xx/6Cxx follow-ups it handles for you, is in
Tag protocols.
The iOS rule that catches everyone
Android has no such restriction, so the same code works there with no declaration at all. That asymmetry is why this is easy to ship and hard to diagnose.Expo
app.json
0x, no spaces, no separators. The
plugin rejects anything else, and anything outside the 5-to-16-byte range ISO
7816-4 allows, because Apple rejects those when the profile is built — a long way
from where the mistake was made.
A trap worth knowing about
Declaring
D2760000850101, the NDEF application AID, changes how iOS presents cards
that support it: a DESFire card then arrives as an ISO 7816 tag rather than a MIFARE
one, so tag.is('mifareUltralight') and the MIFARE-specific commands stop matching.That is a legitimate thing to want and a baffling thing to trip over, so the plugin
warns when it sees it.Bare React Native
ios/<App>/<App>.entitlements
ios/<App>/Info.plist
<string> per AID your app selects. A card whose AID is not listed is
never handed over.
android/app/src/main/AndroidManifest.xml
Timeouts
Crypto takes longer than the platform’s default patience. DESFire authentication and GlobalPlatform key derivation both routinely exceed Android’s 125 ms presence check, and the OS then declares the tag lost part-way through an exchange that was going fine:On iOS the equivalent limits are the session’s 60 seconds and roughly 20 seconds of connected tag.
Neither can be extended, so a long personalisation sequence has to be split across sessions.
Next
Tag protocols
Command builders, chaining, and status words.
Card emulation
The other side: answering a terminal’s SELECT.