How do you write a tag so an interrupted write cannot pass for valid?
Set the message length to zero first, write the message, and write the real length last. An interruption before the last step leaves a tag that reads as empty instead of a length that announces bytes that never arrived. Android's open source NFC stack writes NDEF in this order on Type 2, Type 4 and Type 5 tags.
A write is many commands
A Type 2 tag takes four bytes per command. The MifareUltralight reference documents writePage() as writing one page and says the protocol always writes one page at a time, so a message of a hundred bytes takes some twenty five commands. A tag that leaves between two of them keeps the pages already written next to the pages it held before.
What decides the result is the length field. Written first with its new value, it announces the new message while later pages still hold the old one, and a reader parses the mixture as a message: the halfway page describes the tag that then reads as corrupt or stops partway. Written last, it gives a reader nothing to parse until the message is complete.
The order, type by type
Android's open source NFC stack applies the same three steps to each type, and its source shows them:
| Type | Length field | Steps in the stack |
|---|---|---|
| Type 2 | The length of the NDEF TLV block | Writes the block that holds it with a length of zero, then the message, then the block again with the real length, in rw_t2t_ndef.cc |
| Type 4 | NLEN, at the start of the NDEF file | Sets NLEN to 0000, writes the message after it, then writes NLEN, in rw_t4t.cc |
| Type 5 | The length of the NDEF TLV block | Sets the length to zero, writes the message and the Terminator block, then sets the length, in rw_i93.cc |
An interruption after the first step leaves an NDEF message of length zero. Readers report an empty tag, and the app that wrote it can tell that its write did not finish.
The order protects the message, not the page being written when the interruption comes. What a chip holds in a page whose own write was cut is a property of the chip, and the order narrows that risk to the final write, the one that sets the length.
When the platform writes for you
On Android, Ndef.writeNdefMessage() hands the message to the NFC stack, which writes it in the order above, and code that uses it has nothing to add but a read back. A phone maker can ship a modified stack, so the read back is the check that holds on every phone.
On iOS, Apple's reference for writeNDEF does not describe the order its writer uses. An app learns of a failed update through ndefReaderSessionErrorTagUpdateFailure or a lost connection, as the iOS writing page explains, and reads the tag back to know what it now holds.
When your code writes the pages
Code that writes raw pages, to write a protected tag after authenticating or to store data that is not NDEF, takes over the stack's job. For NDEF, it follows the table: zero the length, write the message, write the length. The page that holds the length usually holds the first bytes of the message too, so the last write rewrites that page with both, as the Android stack does.
For data that is not NDEF, the same idea needs a field of the app's own, a length, a version or a checksum written after the data, which the reading code checks before trusting anything. Without it, a torn write looks exactly like data.
Then read back and compare. A write whose last command ended in an exception has an unknown outcome, and the halfway page explains why reading comes before any retry.
Frequently asked questions
Does Ndef.writeNdefMessage already write in this order?
In Android's open source NFC stack, yes, on Type 2, Type 4 and Type 5 tags. Read the tag back anyway, since a phone maker can modify the stack.
What does a reader see after an interrupted write?
An NDEF message of length zero, when the interruption came between the first and the last step. Applications report it as an empty tag.
Can the final length write itself be interrupted?
Yes, and no order protects that one command. The order narrows the risk to a single write, and what a page cut during its own write holds depends on the chip.
Does iOS write NDEF in the same order?
Apple's reference does not say. Check the result by reading the tag back after writing.