Strange character on Android NDEF record payload
Asked Answered
H

3

14

I just started coding with Android NFC, i've successfully read and write NDEF data into mifare classic tag. The problem is when app read the payload from ndef record, it always contain character '*en' at the beginning of the text. I think it is language character, but how to get the real text message without that character?

This is the screenshot what app read from the tag, the actual text is 'Hello World'

enter image description here Here is the code to read

@Override
public void onNewIntent(Intent intent) {
    Log.i("Foreground dispatch", "Discovered tag with intent: " + intent);
   // mText.setText("Discovered tag NDEF " + ++mCount + " with intent: " + intent);

    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);

        if (rawMsgs != null) {
            NdefMessage[] msgs = new NdefMessage[rawMsgs.length];

            for (int i = 0; i < rawMsgs.length; i++) {
                msgs[i] = (NdefMessage) rawMsgs[i];
            }

            NdefMessage msg = msgs[0];

            try {
            mText.setText(new String(msg.getRecords()[0].getPayload(), "UTF-8"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
Holms answered 27/10, 2011 at 14:36 Comment(4)
I think "en" comes from "English". I'm almost sure you've accidentally added the language code. If you change the language tag in your xml you might get another character sequence. Please try that, because this way at least you'll know where does en come from and you can search on google for a solution.Verdie
If you could post the code that writes the tag, it would be helpful. Have you tried using someone else's app to read your tag to see if it is in how you wrote the tag, or if it is in how you are reading it? (If it displays the same info as being in the Ndef Message, it is a write problem, if it displays only "Hello World..." then it is a read problem.)Waterfall
Lajos, Ben...thanks for your comments, i've tried using other app, NFC Tag info, the app shows 'Hello World'.Btw I've found the problem, as Nils Pipenbrik explains below. This link code.google.com/p/openmobster/wiki/NFC shows how to read the payload data correctly.Holms
Try parsing the NdefMessage using code.google.com/p/ndef-tools-for-androidDanyluk
L
16

What you're seeing is the raw data of an NDef text-record converted to UTF8.

The NDef text-record is build like this:

First byte: Control-Byte

Bit 7: 0: The text is encoded in UTF-8 1: The text is encoded in UTF16

Bit 6: RFU (MUST be set to zero)

Bit 5..0: The length of the IANA language code.

This is followed by the language code, stored in US-ASCII (en in your case) as defined in RFC 3066. The length of the language-code is given in the control-byte.

And this is followed by the text in the format as specified by bit 7 of the control-byte.

The empty square character comes from your conversion of raw data into UTF-8. I'm almost sure that the control-byte in your case has the numeric value 2. Since there is no printable character for this numeric value it gets replaced with the non-printable placeholder character from the unicode-set. This is usually displayed as an empty square.

Lignin answered 27/10, 2011 at 16:11 Comment(3)
Hi Nils, thank you for your answer, now i know how to read the payload data correctly, this link code.google.com/p/openmobster/wiki/NFC shows how to do it. ;)Holms
Also, here is the NDEF Text Record Type definition, hope it helps others..maintag.fr/fichiers/pdf-fr/nfcforum-ts-rtd-text-1-0.pdfHolms
Next time, please copy and paste the values into your answer rather than linking. Both links are dead!!Katharina
H
3

Here's what I did in Kotlin on API 29:

// ... in the onIntent(...) method
val parcelables = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)

parcelables?.let {
    try {
        val inNdefMessage = parcelables[0] as NdefMessage
        val inNdefRecords = inNdefMessage.records

        // convert the payload to string and drop 3 characters to get
        // rid of the " en" prefix
        val payload = inNdefRecords[0].payload

        // figure out if we need to take out the " en" at the beginning
        val textEncoding = if(payload[0] and 128.toByte() == 0.toByte()) "UTF-8" else "UTF-16"
        val langCodeLength = payload[0] and 63.toByte()

        // create a string starting by skipping the first 3 characters
        // based on the language code length
        var inMessage = String(
            payload,
            langCodeLength + 1,
            payload.count() - langCodeLength - 1,
            charset(textEncoding))

        // try to convert the message to json
        try {
            val json = JsonParser().parse(inMessage)

            // ... use json or whatever here
        } catch (error: Exception) {
            println("NFC tag data seems to invalid:\n\n$inMessage\n\n${error.localizedMessage}")
        }

        // ... do whatever
    } catch (error: Exception) {
        println("Error attempting to pull tag info: ${error.localizedMessage}")
    }
}
Halpern answered 14/10, 2020 at 1:51 Comment(1)
This should be the accepted answer: working code with comments explaining what we are doing!Alberik
F
1

Here is an Answer I found on a post similar to this.

When reading the NFC tag this will isolate the message and exclude the language code in the beginning of the message.

            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);

Strange character when reading NFC tag

Fovea answered 13/11, 2020 at 9:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.