Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
282 views
in Technique[技术] by (71.8m points)

android - How to detect the type of an NFC chip

Does anyone know how I can find out via the Android NFC API which NFC chip is used in a tag which I am reading? Ideally I like to get the both the chip model and the manufacturer.

Is that available somewhere in the Tag object?

For clarification, I don't mean the reader chip in the phone, but the chip in the NFC tag.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I'm developing an application in Android for NFC read/write/authentication operations. Here are some code parts you would like.

Android has 3 main types determined for cards, those are Mifare Classic, Mifare Ultralight and Isodep (this is the type of Desfire and Desfire EV1). So, as I get a tag touched, I run this operation:

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) + "
" +
              "UID In Dec: " + Utils.convertByteArrayToDecimal(uid) + "

";

    // 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) + "

";

    // 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 + "
";

            // Size Info
            info[0] += "Size: " + mifareClassicTag.getSize() + " bytes 
" +
                    "Sector Count: " + mifareClassicTag.getSectorCount() + "
" +
                    "Block Count: " + mifareClassicTag.getBlockCount() + "
";
        } 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 + "
";
        } else if(techList[i].equals(IsoDep.class.getName())) {
            info[1] = "IsoDep";
            IsoDep isoDepTag = IsoDep.get(tag);
            info[0] += "IsoDep 
";
        } else if(techList[i].equals(Ndef.class.getName())) {
            Ndef ndefTag = Ndef.get(tag);
            info[0] += "Is Writable: " + ndefTag.isWritable() + "
" +
                    "Can Make ReadOnly: " + ndefTag.canMakeReadOnly() + "
";
        } else if(techList[i].equals(NdefFormatable.class.getName())) {
            NdefFormatable ndefFormatableTag = NdefFormatable.get(tag);
        }
    } 

    return info;
}

However, this doesn't directly get the type of Desfire and Desfire EV1. For that you need to send some bytes to card:

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

After you initialize the Manufacturing data, you can easily reach its parts. DesfireManufacturingData class is for evaluating the response from the tag into meaningful parts, but I'll only give link of it: Desfire Manufacturing Data. Also, I must say this is the most all-around project I have found in the Internet with open source, but it only has reading operations for Desfire tags, not write and authenticate. Hope this helps!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...