nfc_in_flutter icon indicating copy to clipboard operation
nfc_in_flutter copied to clipboard

Writing to tag in iOS throw an exception PlatformException(NFCTagUnavailable, the tag is unavailable for writing, null)

Open Moujarkash opened this issue 4 years ago • 4 comments

void _ndefWrite(NDEFMessage message) { if(!message.tag.writable){ result.value = NfcResponse.error(Strings.NFC_TAG_NOT_WRITABLE); return; }

List<NDEFRecord> newRecords = new List();
newRecords.add(NDEFRecord.plain(jsonEncode(widget._ticket)));

if (message.records.isNotEmpty) newRecords.addAll(message.records);

NDEFMessage newMessage = NDEFMessage.withRecords(newRecords);

message.tag.write(newMessage).then((value) {
  result.value = NfcResponse.success(null);
  widget.ticketsProvider.startTicket(widget._ticket.id);
}, onError: (error) {
  String errorMessage = Strings.SOMETHING_WRONG_HAPPENED_MESSAGE;

  if(error is Exception)
    errorMessage = error.toString();

  result.value = NfcResponse.error(errorMessage);
});

}

the Android version worked, the issue only appeared in iOS

Moujarkash avatar Apr 01 '20 15:04 Moujarkash

A few insights from my testing:

  1. it seems like timing might be one of the issues, but I cannot absolutely confirm this. I was able to get some successful writes using the following code:

      await Future<void>.delayed(const Duration(milliseconds: 5000));
      final Stream<NDEFMessage> stream = NFC.readNDEF(throwOnUserCancel: true);
      await Future<void>.delayed(const Duration(milliseconds: 5000));
      writeSub = stream.listen((NDEFMessage message) {
        final NDEFMessage newMessage = NDEFMessage.withRecords([NDEFRecord.text('hello world')]);
        try {
          message.tag.write(newMessage).then((dynamic dummy) {
            writeSub.cancel();
            verifyTag(newPoint, room.roomId);
          });
        } catch (e) {
          writeSub.cancel();
          String errStr2 = e.toString();
          String exStr2 = e.runtimeType.toString();
          int xxx2 = 0;
          print(errStr2);
          print(exStr2);
        }
      }, onError: (Object error) {
        writeSub.cancel();
        print('On error called');
      }, onDone: () {
        writeSub.cancel();
        print('On done called');
      }, cancelOnError: true);

  1. When writes fail, they leave the tag empty. When I erase a tag with NFCTools, it places an empty Record 0 on the tag, after a failed write, this record is gone.

  2. There may be some indication in my testing that the more complex the message, the higher the failure rate. I was able to successfully write "hello world" more often than I was able to successfully write two records with the following text:

Record 0 contains: R2W:eRfKwMPjeX Record 1 contains: roomId:FF288C53-FF8E-427E-97C5-83238B7646AE

NOTE: It works fine in Android, so I don't suspect that the content of record itself is a problem, although the length might be an issue (14 + 43 = 57 bytes)?

Any help would be greatly appreciated!

James-A-White avatar Apr 25 '20 09:04 James-A-White

Ahhh… an interesting insight from my testing. When I write using Android, the payload is encoded with UTF-8 (and everything works fine). When I write with iOS, the payload is encoded with UTF-16.

Android can read either the UTF-8 or UTF-16 in the data field, although the payload field does not decode correctly. iOS can read only the UTF-8 encoded tags but not the UTF-16 tags.

Using NFC Tools, I can read both tags (that’s how I know that iOS is encoding using UTF-16) and the payload is correct for both encoding schemes. When reading the UTF-16 tag on Android, here’s what I get; notice that the data field is correct, but the payload field has what appears to be Japanese characters.

image

When I read the same UTF-16 tag on iOS, the tag reads as empty.

So, it looks like there may be two issues here. One is the ability to read tags with UTF-16 on both iOS and Android platforms. The other is the ability to have a deterministic write function across both the iOS and Android platforms so that the behavior is the same.

I have worked around the problem by adding NDEF records to the message using the "plain" factory constructor as opposed to using the "text" factory constructor.

NDEFRecord.plain(myMessage);

versus

NDEFRecord.text(myMessage);

By doing this, no text encoding is applied and all works as expected.

James-A-White avatar May 05 '20 09:05 James-A-White

I'm having the same problems in IOS, In android all works fine, but not in iOS. Any good advice? I need to read a tag, and update its value (write a code) thanks so much

mavbcn avatar Jun 02 '20 17:06 mavbcn

I'm having the same problems in IOS, In android all works fine, but not in iOS. Any good advice? I need to read a tag, and update its value (write a code) thanks so much

do you get how to solve? same problem to me

mahirandigital avatar Dec 26 '23 08:12 mahirandigital