8

有谁知道我如何通过 Android NFC API 找出我正在阅读的标签中使用了哪个 NFC 芯片?理想情况下,我喜欢同时获得芯片型号和制造商。

在 Tag 对象的某处可用吗?

为澄清起见,我不是指手机中的读取器芯片,而是 NFC 标签中的芯片。

4

2 回答 2

20

我正在 Android 中开发一个用于 NFC 读/写/身份验证操作的应用程序。这是您想要的一些代码部分。

Android 有 3 种主要类型的卡,分别是 Mifare Classic、Mifare Ultralight 和 Isodep(这是 Desfire 和 Desfire EV1 的类型)。所以,当我接触到一个标签时,我运行这个操作:

private String[] getTagInfo(Intent intent) {
    Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    String prefix = "android.nfc.tech.";
    String[] info = new String[2];

    // UID
    byte[] uid = tag.getId();
    info[0] = "UID In Hex: " + Utils.convertByteArrayToHexString(uid) + "\n" +
              "UID In Dec: " + Utils.convertByteArrayToDecimal(uid) + "\n\n";

    // Tech List
    String[] techList = tag.getTechList();
    String techListConcat = "Technologies: ";
    for(int i = 0; i < techList.length; i++) {
        techListConcat += techList[i].substring(prefix.length()) + ",";
    }
    info[0] += techListConcat.substring(0, techListConcat.length() - 1) + "\n\n";

    // Mifare Classic/UltraLight Info
    info[0] += "Card Type: ";
    String type = "Unknown";
    for(int i = 0; i < techList.length; i++) {
        if(techList[i].equals(MifareClassic.class.getName())) {
            info[1] = "Mifare Classic";
            MifareClassic mifareClassicTag = MifareClassic.get(tag);

            // Type Info
            switch (mifareClassicTag.getType()) {
            case MifareClassic.TYPE_CLASSIC:
                type = "Classic";
                break;
            case MifareClassic.TYPE_PLUS:
                type = "Plus";
                break;
            case MifareClassic.TYPE_PRO:
                type = "Pro";
                break;
            }
            info[0] += "Mifare " + type + "\n";

            // Size Info
            info[0] += "Size: " + mifareClassicTag.getSize() + " bytes \n" +
                    "Sector Count: " + mifareClassicTag.getSectorCount() + "\n" +
                    "Block Count: " + mifareClassicTag.getBlockCount() + "\n";
        } else if(techList[i].equals(MifareUltralight.class.getName())) {
            info[1] = "Mifare UltraLight";
            MifareUltralight mifareUlTag = MifareUltralight.get(tag);

            // Type Info
            switch (mifareUlTag.getType()) {
            case MifareUltralight.TYPE_ULTRALIGHT:
                type = "Ultralight";
                break;
            case MifareUltralight.TYPE_ULTRALIGHT_C:
                type = "Ultralight C";
                break;
            }
            info[0] += "Mifare " + type + "\n";
        } else if(techList[i].equals(IsoDep.class.getName())) {
            info[1] = "IsoDep";
            IsoDep isoDepTag = IsoDep.get(tag);
            info[0] += "IsoDep \n";
        } else if(techList[i].equals(Ndef.class.getName())) {
            Ndef ndefTag = Ndef.get(tag);
            info[0] += "Is Writable: " + ndefTag.isWritable() + "\n" +
                    "Can Make ReadOnly: " + ndefTag.canMakeReadOnly() + "\n";
        } else if(techList[i].equals(NdefFormatable.class.getName())) {
            NdefFormatable ndefFormatableTag = NdefFormatable.get(tag);
        }
    } 

    return info;
}

但是,这并不能直接得到 Desfire 和 Desfire EV1 的类型。为此,您需要向卡发送一些字节:

static final byte GET_MANUFACTURING_DATA = (byte) 0x60;

public DesfireManufacturingData getManufacturingData() throws Exception {
    byte[] respBuffer = sendRequest(GET_MANUFACTURING_DATA);
    if (respBuffer.length != 28)
        throw new Exception("Invalid response");
    return new DesfireManufacturingData(respBuffer);
}

private byte[] sendRequest (byte command) throws Exception {
    return sendRequest(command, null);
}

private byte[] sendRequest (byte command, byte[] parameters) throws Exception {
    ByteArrayOutputStream output = new ByteArrayOutputStream();

    byte[] recvBuffer = mTagTech.transceive(Utils.wrapMessage(command, parameters));

    while (true) {
        if (recvBuffer[recvBuffer.length - 2] != (byte) 0x91)
            throw new Exception("Invalid response");

        output.write(recvBuffer, 0, recvBuffer.length - 2);

        byte status = recvBuffer[recvBuffer.length - 1];
        if (status == OPERATION_OK) {
            break;
        } else if (status == ADDITIONAL_FRAME) {
            recvBuffer = mTagTech.transceive(Utils.wrapMessage(GET_ADDITIONAL_FRAME, null));


        } else if (status == PERMISSION_DENIED) {
            throw new Exception("Permission denied");
        }else if (status == LENGTH_ERROR) {
            throw new Exception("Length Error");
        } 
        else if (status == AUTHENTICATION_ERROR) {
            throw new Exception("Authentication error");
        }else if (status == PARAMETER_ERROR) {
            throw new Exception("Parameter Error");
        }else if (status == DUPLICATE_ERROR) {
            throw new Exception("Duplicate Error");
        }else if (status == NO_SUCH_KEY) {
            throw new Exception("No such key");
        }else {
            throw new Exception("Unknown status code: " + Integer.toHexString(status & 0xFF));
        }
    }

    return output.toByteArray();
}

初始化制造数据后,您可以轻松访问其部分。DesfireManufacturingData 类用于将标签的响应评估为有意义的部分,但我只会给出它的链接:Desfire Manufacturing Data。另外,我必须说这是我在互联网上找到的最全能的开源项目,但它只有对 Desfire 标签的读取操作,没有写入和验证。希望这可以帮助!

于 2013-01-17T11:05:18.680 回答
-1

如果您有带 NFC 的 Android 设备,则有各种可用的应用程序可以做到这一点(以及更多),例如NXP TagInfoNFC TagInfo

对于带有桌面阅读器的 PC,也许RFIDIOt可能有用。对于其他平台,可能存在(或可以创建)类似的应用程序,但我不熟悉它们。

于 2012-10-26T18:47:44.983 回答