Reputation: 1326
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:
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.
Upvotes: 0
Views: 1287
Reputation: 10152
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
Upvotes: 1