从NFC标签(IsoDep)读取数据。

19

我是 Android NFC API 的新手。

目前,我有一个 NFC 标签,我正在制作一个 Android 应用程序来从中读取数据。当我的手机靠近 NFC 标记时,我的简单应用程序就会启动。但是我不知道如何读取 NFC 标签内部的数据。该标签使用了 IsoDep 技术。

我的当前代码:

@Override
protected void onResume (){
    super.onResume();

    Intent intent = getIntent();
    Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

    IsoDep isoDep = IsoDep.get(tag);

    // How to read data from IsoDep instance?

我在互联网上查到,人们正在发送命令给IsoDep以从 NFC 标签中获取响应,我认为我们可以从响应中解析标签中的数据,我看到人们这样做:

 //What is the 'command' ? How to define the command?
 //e.g.:
 byte command = (byte) 0x6A
 isoDep.transceive(command)

不过,这个命令只是一个byte,对于新手来说,很难理解发生了什么。我不知道如何定义命令以读取数据?有人能向我解释吗?或者有没有文档可以学习这个命令?

通常,我需要一些关于如何定义命令和如何从响应中解析数据的指导,我想要读取存储在标签中的数据,并将数据以字符串格式显示在UI元素(例如TextView)中。

*注意***

我对这些配置(例如AnroidManifest.xml)没有问题,请不要指导我如何配置:)

1个回答

22

IsoDep允许您使用transceive操作在ISO-14443-4连接上进行通信。在此协议中,应用程序数据单元(APDU)进行交换。格式已经指定,您可以在Wikipedia上找到描述。

例如,要选择具有特定应用程序标识符(AID)的智能卡上的应用程序,您将执行以下APDU命令。结果只会简单地指示是否正常(9000)或出现错误。

    byte[] SELECT = { 
        (byte) 0x00, // CLA Class           
        (byte) 0xA4, // INS Instruction     
        (byte) 0x04, // P1  Parameter 1
        (byte) 0x00, // P2  Parameter 2
        (byte) 0x0A, // Length
        0x63,0x64,0x63,0x00,0x00,0x00,0x00,0x32,0x32,0x31 // AID
    };

    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    IsoDep tag = IsoDep.get(tagFromIntent);

    tag.connect();
    byte[] result = tag.transceive(SELECT);
    if (!(result[0] == (byte) 0x90 && result[1] == (byte) 0x00))
        throw new IOException("could not select applet");

应用程序被选择后,您可以执行特定于应用程序的命令。这些程序通常是用遵循GlobalPlatorm规范的JavaCard编写的。以下示例在上述选定的应用程序上执行方法4(0x04),该方法返回最多11个字节的字节数组。然后将此结果转换为字符串。

    byte[] GET_STRING = { 
        (byte) 0x80, // CLA Class        
        0x04, // INS Instruction
        0x00, // P1  Parameter 1
        0x00, // P2  Parameter 2
        0x10  // LE  maximal number of bytes expected in result
    };

    result = tag.transceive(GET_STRING);
    int len = result.length;
    if (!(result[len-2]==(byte)0x90&&result[len-1]==(byte) 0x00))
       throw new RuntimeException("could not retrieve msisdn");

    byte[] data = new byte[len-2];
    System.arraycopy(result, 0, data, 0, len-2);
    String str = new String(data).trim();

    tag.close();

为什么是 "len-2"?响应的结构是如何的,是否有标题?没关系,通过维基百科链接找到了。末尾有2个状态字节。 - pelican_george
一个 APDU 消息的结果包含了响应数据 (应用程序特定的),以及响应 Trailer SW1-SW2,它编码了命令处理的结果,例如成功时的 0x9000。对于响应数据的任何结构都是应用程序特定的(通常使用 TLV 编码)。 - Dominik
嘿,Dominik,你为什么选择“方法4”?它可以是任何字节吗? - cherry-wave
@cherry-wave,是的,它可以是任何其他指令。可用的指令由智能卡应用程序定义,以及要使用的参数。 - Dominik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接