0

I want to write simple text data to my NXP MiFARE DesFire EV1 (NDEF Type 4 Tag). However, the writing process always fails with an IOExcetion

For writing I get the NFC-Tag I use the function write:

private void write(String mimeType, String text, Tag tag) throws IOException, FormatException {
    NdefRecord[] records = {createRecord(mimeType, text)};
    NdefMessage message = new NdefMessage(records);
    Ndef ndef = Ndef.get(tag);
    ndef.connect();
    ndef.writeNdefMessage(message);
    ndef.close();
}

The result in the third line (Ndef ndef = Ndef.get(tag)) is the following:

TAG: Tech [android.nfc.tech.IsoDep, android.nfc.tech.NfcA, android.nfc.tech.Ndef]

From this I assumed, the Tag is formatted correclty (as NDEF). Now, when calling ndef.connect() it just says java.io.exception without any additional information about the error. The other parts of the code, that get called is appended.

@Override
public void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    String action = intent.getAction();
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
        tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        if (tag != null) {
            String serialId = Utility.bytesToHex(tag.getId());
            Log.d("[WriteCard]", "Serial Number: " + serialId);
            Toast.makeText(this, serialId, Toast.LENGTH_SHORT).show();
        }
    }
}

// When the write Button is clicked
public void onClick(View view)    {
    if (nfc_adapter == null) {
        Toast.makeText(this, "No NFC", Toast.LENGTH_SHORT).show();
        return;
    } 
    int id = view.getId();
    Intent intent = getIntent();
    try {
        write("type/1", spinner_location.toString(), tag);
    }
    catch(Exception e)  {
        Log.d("[WriteCard]", e.toString());
        Toast.makeText(this,  e.toString(), Toast.LENGTH_SHORT).show();
    }
}

The NXP Tag Info App reports the following:

  • IC Type: MiFARE DESFire EV1
  • Type 4 Tag
  • NFC data set access: Read&Write

Additional Info: The writing process with Android-Apps like NFC TagWriter by NXP or wakdev NFC Tools works without any problem, thus I assume, the Tag is working correctly.

agentsmith
  • 1,226
  • 1
  • 14
  • 27

1 Answers1

1

Really trying to write to a Tag on a Button click will always be unreliable and also using enableForeGroundDispatch is also unreliable in real life as it is highly likely that the Tag will be moved slightly that it will go out of range and thus generate I/O errors. The two Apps you mention don't do it the way you are trying to do.

Also the documentation says connect and writeNdefMessage

May cause RF activity and may block. Must not be called from the main application thread.

and you are calling these from the main (UI) thread.

Your button just needs to setup the action that "when Tag comes in to range, immediately write text"

e.g. some thing like

private String text;

@Override
public void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    String action = intent.getAction();
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
        tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        if (tag != null) {
            if(text.isEmpty()) {
               // Nothing to write so read
               String serialId = Utility.bytesToHex(tag.getId());
               Log.d("[WriteCard]", "Serial Number: " + serialId);
               Toast.makeText(this, serialId, Toast.LENGTH_SHORT).show();
             } else {
               // Have some text to write 
               try {
                  write("type/1", text, tag);
                } catch(Exception e)  {
                  Log.d("[WriteCard]", e.toString());
                  Toast.makeText(this,  e.toString(), Toast.LENGTH_SHORT).show();
                }
               // Reset the write trigger
               text = "";
        }
    }
}

// When the write Button is clicked
public void onClick(View view)    {
    text = spinner_location.toString();
}

Also you really need to check that your Tag is a Formatted Ndef Tag before your try and write to it.

e.g. something like

private void write(String mimeType, String text, Tag tag) throws IOException, FormatException {
    NdefRecord[] records = {createRecord(mimeType, text)};
    NdefMessage message = new NdefMessage(records);
    Ndef ndef = Ndef.get(tag);
    if(ndef != null) {
       // It's an already formatted Ndef Tag
       ndef.connect();
       ndef.writeNdefMessage(message);
       ndef.close();
    } else {
       // Try and format at write
       .... "get(tag)" for Ndef formattable type and check not null
    }
}

The final point is using the old enableForegroundDispatch is unreliable, so use the Newer and better enableReaderMode and onTagDiscovered API instead.

This also solves the calling connect etc on the wrong thread as onTagDiscovered is automatically in it's own thread.

Also enableReaderMode when you disable the "Platform" sounds it does not prompt the user to remove the Tag from range before you have had a chance to write to it (You can play your own sound after a successful write)

See https://stackoverflow.com/a/64921434/2373819 for an example of enableReaderMode

Andrew
  • 8,198
  • 2
  • 15
  • 35
  • Hi, well I think this is a good explanation of how to do it right and I totally agree with you, considering your answer. I guess this would solve similar problems, but somehow mine seems different. The reason is, that I can successfully write other types of tags (like an Ultralight) but not this, although it is discovered as NDEF-formatted. From this, I assume now that my problem more refers to the tag itself (and why I receive an Exception without any additional info), than the code I useed for writing (which somehow works). However, I will try to implement it. – agentsmith Mar 12 '22 at 12:08
  • Different Tag chips have different antenna performance characteristics and the Ultralight and Desfire might be implemented with different antenna designs. So for example Tags in the small round stickers are much more sensitive to movement than the credit card sized Tags. Also as the power to run the chips is provided by the RF field, the power consumption of the Tag also plays a part in how range sensitive it is, I guess as the Desfire as a more complex chip might need more power. There are also some other differences that affect the sensitivity to movement between the 2 chips. – Andrew Mar 13 '22 at 17:29