【问题标题】:Strange character when reading NFC tag读取 NFC 标签时出现奇怪的字符
【发布时间】:2018-04-15 12:01:09
【问题描述】:

我正在尝试使用 Android 读取 NFC 标签。我是养蜂人,这是为了在我接近蜂巢时识别它们。我在这里搜索过,但在阅读标签时仍然遇到问题。我想阅读文本,但是当它阅读时,在所需文本之前有一个方形字符和显示为“十”的字符。

这是我正在使用的代码。我知道有效负载字节必须是正确的,我尝试更改它们但无济于事。

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

【问题讨论】:

    标签: android character-encoding format nfc ndef


    【解决方案1】:

    由于您尝试将整个原始 NDEF 记录显示为文本字符串(使用一些奇怪的解码方法),因此在显示消息时您会收到奇怪的附加字符:

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

    这有几个问题。首先,您通常希望使用与编写文本相同的编码来解码文本。例如,如果你使用了

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

    要为给定的文本字符串获取 US-ASCII 编码的字节数组,您还需要使用相同的 US-ASCII 编码再次将字节转换为文本字符串:

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

    其次,您将整个 NDEF 消息解释为文本字符串。但是,您存储在标签上的文本通常仅包含在 NDEF 记录的有效负载中。在您的情况下,前缀“十”表明您使用了带有语言指示“en”(英语)的 NFC 论坛文本记录(类型名称“T”)。因此,您需要在 NDEF 消息中搜索 Text 记录:

    for (NdefRecord r : messages[0].getRecords()) {
        if (r.getTnf() == NdefRecord.TNF_WELL_KNOWN) {
            if (Arrays.equals(r.getType(), NdefRecord.RTD_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);
            }
        }
    }
    

    【讨论】:

    • 您的字符串语言代码未在您的代码 sn-p 中使用。它的目的是什么?
    • @ZeekAran 这是一个 IANA 语言代码(实际上是 IETF 语言标签),用于指示编写文本的语言。
    • 可以,但代码中不再引用它。
    • @ZeekAran 正确,我的示例显示了如何正确解码文本记录。 OP 似乎并不关心他们代码中的那个元素。因此,我也没有在我的示例中“使用”它。
    猜你喜欢
    • 2014-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多