为什么在使用Android手机读取NFCtag时会得到与使用专用阅读器读取时不同的标签ID?

时间:2019-12-13 09:24:40

标签: android nfc rfid

我正在使用Android Cilico F750,专用的RFID阅读器是CF-RS103。 RFID标签类型为MIFARE Ultralight类型C。

使用专用读卡器进行读取时,标签的ID为:2054270212(10位数字)。

但是,使用Android手机读取时,id为:36113912876727556(17位数字),而反向ID为:1316602805183616(16位数字)。

有人知道为什么会这样吗,以及是否有可能将10位ID转换为17位ID,反之亦然。

我使用意图来检测标签并解决意图,我使用了这个:

public void resolveIntent(Intent intent){

    String action = intent.getAction();

    if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
            ||NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
            ||NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action))

    {
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        NdefMessage[] msgs;

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

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

        else
        {
            byte[] empty = new byte[0];
            byte[] id = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);
            Tag tag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            byte[] payload = dumpTagData(tag).getBytes();
            NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN,empty,id,payload);
            NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
            msgs= new NdefMessage[] {msg};
        }
        displayMsgs(msgs);
    }}

这是我的助手功能:

private void displayMsgs(NdefMessage[] msgs)
{
    if(msgs==null || msgs.length==0) {
        return;
    }

    StringBuilder builder = new StringBuilder();
    List<ParsedNdefRecord> records= NdefMessageParser.parse(msgs[0]);
    final int size = records.size();

    for(int i=0;i<size;i++)
    {
        ParsedNdefRecord record = records.get(i);
        String str = record.str();
        builder.append(str).append("\n");
    }

    text.setText(builder.toString());
}



private String dumpTagData(Tag tag) {
StringBuilder sb = new StringBuilder();
byte[] id = tag.getId();
sb.append("ID (hex): ").append(toHex(id)).append('\n');
sb.append("ID (reversed hex):").append(toReversedHex(id)).append('\n');
sb.append("ID (dec): ").append(toDec(id)).append('\n');
sb.append("ID (reversed dec):").append(toReversedDec(id)).append('\n');

String prefix = "android.nfc.tech.";
sb.append("Technologies: ");
for (String tech: tag.getTechList()) {
    sb.append(tech.substring(prefix.length()));
    sb.append(", ");
}

sb.delete(sb.length() - 2, sb.length());

for (String tech: tag.getTechList()) {
    if (tech.equals(MifareClassic.class.getName())) {
        sb.append('\n');
        String type = "Unknown";

        try {
            MifareClassic mifareTag = MifareClassic.get(tag);

            switch (mifareTag.getType()) {
                case MifareClassic.TYPE_CLASSIC:
                    type = "Classic";
                    break;
                case MifareClassic.TYPE_PLUS:
                    type = "Plus";
                    break;
                case MifareClassic.TYPE_PRO:
                    type = "Pro";
                    break;
            }
            sb.append("Mifare Classic type: ");
            sb.append(type);
            sb.append('\n');

            sb.append("Mifare size: ");
            sb.append(mifareTag.getSize() + " bytes");
            sb.append('\n');

            sb.append("Mifare sectors: ");
            sb.append(mifareTag.getSectorCount());
            sb.append('\n');

            sb.append("Mifare blocks: ");
            sb.append(mifareTag.getBlockCount());
        } catch (Exception e) {
            sb.append("Mifare classic error: " + e.getMessage());
        }
    }

    if (tech.equals(MifareUltralight.class.getName())) {
        sb.append('\n');
        MifareUltralight mifareUlTag = MifareUltralight.get(tag);
        String type = "Unknown";
        switch (mifareUlTag.getType()) {
            case MifareUltralight.TYPE_ULTRALIGHT:
                type = "Ultralight";
                break;
            case MifareUltralight.TYPE_ULTRALIGHT_C:
                type = "Ultralight C";
                break;
        }
        sb.append("Mifare Ultralight type: ");
        sb.append(type);
    }
}

return sb.toString();
}

private String toHex(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (int i = bytes.length - 1; i >= 0; --i) {
        int b = bytes[i] & 0xff;
        if (b < 0x10)
            sb.append('0');
        sb.append(Integer.toHexString(b));
        if (i > 0) {
            sb.append(" ");
        }
    }
    return sb.toString();
}

private String toReversedHex(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < bytes.length; ++i) {
        if (i > 0) {
            sb.append(" ");
        }
        int b = bytes[i] & 0xff;
        if (b < 0x10)
            sb.append('0');
        sb.append(Integer.toHexString(b));
    }
    return sb.toString();
}

private long toDec(byte[] bytes) {
    long result = 0;
    long factor = 1;
    for (int i = 0; i < bytes.length; ++i) {
        long value = bytes[i] & 0xffl;
        result += value * factor;
        factor *= 256l;
    }
    return result;
}

private long toReversedDec(byte[] bytes) {
    long result = 0;
    long factor = 1;
    for (int i = bytes.length - 1; i >= 0; --i) {
        long value = bytes[i] & 0xffl;
        result += value * factor;
        factor *= 256l;
    }
    return result;
}`

编辑:我设法通过将7字节的十六进制ID截断为4字节来解决此问题。 如果十进制ID的总长度小于10位,则使用以下语句对十进制ID进行格式化:如果DEC ID小于10位,则基本上从左侧添加零:

String strFinal=String.format("%010d", Long.parseLong(str));

这份描述ID如何从HEX8转换为DEC10的文档也对我有很大帮助:https://www.batag.com/download/rfidreader/LF/RAD-A200-R00-125kHz.8H10D.EM.V1.1.pdf

非常感谢@Andrew和@Karam帮助我解决了这个问题!

3 个答案:

答案 0 :(得分:0)

我不知道您为什么总是尝试始终转换为十进制? 并且请尝试说明有关用于读取UID的代码的更多信息。

关于您的电话号码,并将17位数字转换为10位数字;我将它们都转换为十六进制:

  

36139312876727556(17位数)以十六进制表示:8064837A71AD04。

     

2054270212(10位数),以十六进制表示:7A71AD04

您会注意到,您只需修剪前三个字节即可获得10位数字。

而且我确实相信他们都不是UID。但正如Andrew所说的7字节,您已经在您的照片中阅读了它:(04:B5:71:7A:83:64:80)

答案 1 :(得分:0)

所以我认为答案是,因为您将7字节ID转换为十进制,所以由于转换为十进制,所以得到的数字长度是可变的。

“字节数据类型是一个8位带符号的二进制补码整数。最小值为-128,最大值为127(包括127)。”

来自https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

可以生成一个具有1,2或3个字符的十进制数字,因此id的长度可以不同。

从理论上讲,转换也应该出现负数,这似乎也出错了。

如果您希望它可以被人类阅读,则最好将其作为十六进制字符串处理。

Java中将ID的2页转换为十六进制的正确方法是

StringBuilder Uid;
for (int i = 0; i < result.length; i++) {
                        // byte 4 is a check byte
                        if (i == 3) continue;
                        Uid.append(String.format("%02X ", result[i]));
                    }

根据卡https://www.nxp.com/docs/en/data-sheet/MF0ICU2_SDS.pdf的规格表进行注释(第7.3.1节)

有一个校验字节是ID的一部分,尽管在同一张卡上它始终是相同的,并且仍然会为您提供唯一的ID,但从技术上讲,它不是ID的一部分。

或者如果阅读水平不高

https://developer.android.com/reference/android/nfc/Tag#getId()

将为您获取ID。

请注意,“ 36139312876727556(17digit)和反向ID”在转换为十六进制并反向实际时为7个字节,并以正确的数字开头。

10位数字看起来像7字节数字的前4个字节也被反转了。

答案 2 :(得分:0)

PC上的读卡器配置错误,默认情况下,将其配置为当卡具有7字节ID时将ID显示为10位十进制数字(4字节)。

因此,它必须丢失一些数据,它是通过将ID截断为7字节ID的前4个字节来实现的

使用PC上的软件将输出格式更改为适合Mifare Ultralight C卡(8 Hex?)上的ID大小

请改用Mifare Classic卡,因为它们的ID为4字节

将7个字节的ID截断为4个字节,例如将代码中的bytes.length更改为4(硬编码为7字节ID中的前4个字节),并处理以下事实:存在大量(大约1670万)的Mifare Ultralight C看起来与您要显示的ID相同的卡片

这是因为规格是卖家在亚马逊https://www.amazon.co.uk/Chafon-CF-RS103-Multiple-Support-Compatible-Black/dp/B017VXVZ66上提供的(我无法在制造商的网站上找到任何详细信息)

它说:“默认输出10位十进制,通过软件控制输出格式。”

“支持Windows,Linux和android系统,但只能在Windows pc中设置输出格式。无需编程和软件,只需即插即用。”

唯一明智的答案是移动所有内容以使用7字节ID。