Ad

Strange Character When Reading NFC Tag

I am trying to read an NFC tag using Android. I'm a beekeeper and this is to ID my hives when I approach them. I have searched here but I am still having issues reading the tag. I want to read the text, but when it reads, there is a square-like character and characters displayed like " Ten" before the desired text.

Here is the code I'm using. I know that the payload bytes have to be correct and I have tried changing them but to no avail.

private static NdefMessage getTestMessage() {
    byte[] mimeBytes = "application/com.android.cts.verifier.nfc"
            .getBytes(Charset.forName("US-ASCII"));
    byte[] id = new byte[] {1, 3, 3, 7};
    byte[] payload = "CTS Verifier NDEF Push Tag".getBytes(Charset.forName("US-ASCII"));
    return new NdefMessage(new NdefRecord[] {
            new NdefRecord(NdefRecord.TNF_MIME_MEDIA, mimeBytes, id, payload)
    });
}

@Override
protected void onResume() {
    super.onResume();

    mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
    mNfcAdapter.setNdefPushMessageCallback(this, this);
}

// sending message
@Override
public NdefMessage createNdefMessage(NfcEvent event) {
    return getTestMessage();
}


private NdefMessage[] getNdefMessages(Intent intent) {
    Parcelable[] rawMessages = intent
      .getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
    if (rawMessages != null) {
        NdefMessage[] messages = new NdefMessage[rawMessages.length];
        for (int i = 0; i < messages.length; i++) {
            messages[i] = (NdefMessage) rawMessages[i];
        }
        return messages;
    } else {
        return null;
    }
}

static String displayByteArray(byte[] bytes) {
    String res="";
    StringBuilder builder = new StringBuilder().append("");
    for (int i = 0; i < bytes.length; i++) {
        res+=(char)bytes[i];
    }
    return res;

}

// displaying message
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);

    NdefMessage[] messages = getNdefMessages(intent);
    edtUser.setText(displayByteArray(messages[0].toByteArray()));

    Toast.makeText(this, "NFC tag entered", Toast.LENGTH_LONG).show();
}
Ad

Answer

You are getting odd additional characters when displaying the message since you try to display the whole raw NDEF record as text string (using some odd decoding method):

NdefMessage[] messages = getNdefMessages(intent);
edtUser.setText(displayByteArray(messages[0].toByteArray()));

There are several problems with this. First of all, you would typically want to decode the text using the same encoding that you used to write the text. For instance, if you used

String text = "...";
byte[] bytes = text.getBytes(Charset.forName("US-ASCII"));

to get a byte array in US-ASCII encoding for a given text string, you would also want to use that same US-ASCII encoding to translate the bytes into a text string again:

byte[] bytes = ...;
String text = new String(bytes, "US-ASCII");

Second, you are interpreting the whole NDEF message as a text string. However, the text that you stored on the tag is typically only contained inside the payload of an NDEF record. In your case, the prefix "Ten" suggests that you used an NFC Forum Text record (type name "T") with the language indication "en" (for English). You would, therefore, want to search the NDEF message for the Text record:

for (NdefRecord r : messages[0].getRecords()) {
    if (r.getTnf() == NdefRecord.TNF_WELL_KNOWN) {
        if (Arrays.equals(r.getType(), NdefRecord.RTD_TEXT)) {

Once you found the Text record, you can decode its text payload. The payload consists of a status byte, a language field and the actual text:

            byte[] payloadBytes = ndefRecord.getPayload();
            boolean isUTF8 = (payloadBytes[0] & 0x080) == 0;  //status byte: bit 7 indicates encoding (0 = UTF-8, 1 = UTF-16)
            int languageLength = payloadBytes[0] & 0x03F;     //status byte: bits 5..0 indicate length of language code
            int textLength = payloadBytes.length - 1 - languageLength;
            String languageCode = new String(payloadBytes, 1, languageLength, "US-ASCII");
            String payloadText = new String(payloadBytes, 1 + languageLength, textLength, isUTF8 ? "UTF-8" : "UTF-16");

            edtUser.setText(payloadText);
        }
    }
}
Ad
source: stackoverflow.com
Ad