Hi Steve,
We suspect that your problem is related to the smartphone's presence check. The smartphone will periodically check if something is present in the RF field and, when a tag is found, it will also check periodically if it is still present. The presence check usually happens every 130ms. The difficulty is that each phone has a different way of handling the RF object detection, the anti collision and the inventory. So different phones may behave differently and may lead to different results.
If a presence check command happens during an I2C command, it will fail with a TimeOut because the NFC Tag will not be able to answer it. This can cause some problems during your sequence because the smartphone may think that the tag is gone (and this is here that different phone will behave differently).
In a previous project, we had such problem and here is how we have worked it around:
Instead of using the standard mode we have used a reader mode (see this link) which allows to control the periodicity of the presence checks thanks to EXTRA_READER_PRESENCE_CHECK_DELAY. By increasing the presence check period to 500 ms we avoided the problem.
It seems that this mode is also available on Flutter: https://pub.dev/packages/nfc_manager
You may want to try it.
FYI, I would like also to mention that the ST25DV has a Fast Transfer Mode feature that is well adapted to bidirectional communication and much faster than communication via tag's EEPROM memory. It uses a RAM of 256 bytes present in the ST25DV. When some data are put in this mailbox, the MCU can be informed by the interruption so it avoids that the MCU does some polling to know if an NDEF has been written.
Our ST25SDK has an API to simplify the use of this Fast Transfer Mode. A single API function can be called to send or receive data of any size. The ST25SDK will take care of the transmission.
This looks well adapted to your need, unfortunately it is not available by default on Flutter so some porting is necessary.
Regards
Olivier