toBytes method
Encodes this message in the NFC Forum wire format.
Chunking is never produced: every record is written whole, which is what real readers expect and what both platforms do.
Implementation
Uint8List toBytes() {
final out = BytesBuilder(copy: false);
for (var i = 0; i < records.length; i++) {
final record = records[i];
final isShort = record.payload.length < 256;
// The specification always writes the ID length byte for an empty record.
final hasId = record.identifier.isNotEmpty || record.typeNameFormat == NdefTypeNameFormat.empty;
var header = record.typeNameFormat.index & _maskTypeNameFormat;
if (i == 0) header |= _flagMessageBegin;
if (i == records.length - 1) header |= _flagMessageEnd;
if (isShort) header |= _flagShortRecord;
if (hasId) header |= _flagIdLengthPresent;
// TYPE_LENGTH and ID_LENGTH are one byte each on the wire. The validating constructor
// already refuses anything longer, but NdefRecord.fromParts -- the decode path, which
// has to represent whatever a tag holds -- does not, so a hand-built record can still
// reach here. `addByte` would take the low eight bits and produce a message that encodes
// without complaint and that nothing can read back, which is the failure the constructor
// rejects these lengths to prevent.
if (record.type.length > 255) {
throw ArgumentError.value(
record.type.length,
'records[$i].type',
'does not fit the one-byte TYPE_LENGTH field',
);
}
if (record.identifier.length > 255) {
throw ArgumentError.value(
record.identifier.length,
'records[$i].identifier',
'does not fit the one-byte ID_LENGTH field',
);
}
out.addByte(header);
out.addByte(record.type.length);
if (isShort) {
out.addByte(record.payload.length);
} else {
final length = record.payload.length;
out.add([(length >> 24) & 0xFF, (length >> 16) & 0xFF, (length >> 8) & 0xFF, length & 0xFF]);
}
if (hasId) out.addByte(record.identifier.length);
out.add(record.type);
out.add(record.identifier);
out.add(record.payload);
}
return out.takeBytes();
}