您现在的位置: 万盛学电脑网 >> 程序编程 >> 网络编程 >> 安卓开发 >> 正文

移动支付之智能IC卡与Android手机的NFC通信如何实现

作者:佚名    责任编辑:admin    更新时间:    2015-10-21 14:40:26

这是我们为大家提供的一篇介绍移动支付之智能IC卡与Android手机的NFC通信如何实现的文章,接下来就让我们一起来了解一下吧!

目前常见的智能IC卡运行着JavaCard虚拟机,智能IC卡上可以运行由精简后的Java语言编写的卡应用(简称Applet)。智能IC卡的Applet不能自己启动,必须由外部终端(例如POS机,地铁刷卡终端等)向卡片发送Select命令,由此选中卡片的Applet,Applet才能运行。Appplet侧重于数据的处理,没有花销的I/O功能。Applet的程序有生命周期和指定入口,其中最主要的几个方法如下:

public static void install(byte[] bArray, short bOffset, byte bLength)

构建了Applet子类的实例,JCRE将会最先调用这个;所有的初始化和分配内存的操作应该在这个里面实现;可以获取卡外实体传进来的一些应用初始化参数。

public void process(APDU apdu)

类似于正常java class的main,在安装后,APDU的执行将在这里实现。

protected final void register()

applet用来在JCRE中注册该applet实例

register(byte[] bArray, short bOffset, byte bLength)

register( )功能一样,增加了可以分配其特定的AID的功能。

public boolean select()

JCRE一旦接收到SELECT[by name]命令时,将寻找命令中指示的AID对应的Applet,使之处于活跃状态,接收并处理接下来的APDU命令;在选择新的Applet前,JCRE先调用当前Applet的 deselect 方法;Applet可以拒绝被选择,此时 select 方法返回false;SELECT[by name]命令本身也将传递给applet处理,此时通过 selectingApplet 用以判断当前状态。

本文的DEMO运行效果如下,包含一个JavaCard的Applet实现和一个Android端的NFC读写程序,实现智能IC卡与Android手机的简单通信。

移动支付之智能IC卡与Android手机的NFC通信

接下来贴段简单的Applet 源码,下载地址:http://download.csdn.net/detail/hellogv/8090041。

大概的思路是:Applet定义了2个开头标识皆为CMD_CLA的自定义命令CMD_INS_1和CMD_INS_2,当Android手机通过NFC分别发送CMD_INS_1和CMD_INS_2,Applet分别返回strHello和strWorld。

核心源码如下:

[java] view plaincopyprint?

在CODE上查看代码片

派生到我的代码片

 

private static final byte[] strHello= { (byte) 'H', (byte) 'e',

(byte) 'l', (byte) 'l', (byte) 'o'};

private static final byte[] strWorld = {(byte) 'W',

(byte) 'o', (byte) 'r', (byte) 'l', (byte) 'd', };

private static final byte CMD_CLA = (byte) 0x80;

private static final byte CMD_INS_1 = (byte) 0x10;

private static final byte CMD_INS_2 = (byte) 0x20;

public static void install(byte[] bArray, short bOffset, byte bLength) {

// GP-compliant JavaCard applet registration

new mytest().register(bArray, (short) (bOffset + 1), bArray[bOffset]);

}

/*

* 当Java卡Applet被选中时,由JCRE调用。Java卡Applet可以定义select()完成初始化,

* 否则,JCRE调用父类的select()。

* @see javacard.framework.Applet#select()

*/

public boolean select() {

short debug=100;

debug++;//用于断点调试,当被select时触发。

return super.select();

}

/*

* 当Java卡Applet被放弃时,由JCRE调用。Java卡Applet可以定义deselect()完成清除,

* 否则,JCRE调用父类的deselect()。

* @see javacard.framework.Applet#deselect()

*/

public void deselect() {

short debug=100;

debug++;//用于断点调试

super.deselect();

}

/*

* 每次收到APDU命令,都会执行

* @see javacard.framework.Applet#process(javacard.framework.APDU)

*/

public void process(APDU apdu) {

if (selectingApplet()) {

return;

}

//获取外部终端发过来的数据

byte[] buffer = apdu.getBuffer();

//获取第一位数据

byte CLA = (byte) (buffer[ISO7816.OFFSET_CLA] & 0xFF);

//获取第二位数据

byte INS = (byte) (buffer[ISO7816.OFFSET_INS] & 0xFF);

if (CLA != CMD_CLA) {//格式不对

ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);

}

switch (INS) {

case CMD_INS_1:

sendBytes(apdu,strHello);

break;

case CMD_INS_2:

sendBytes(apdu,strWorld);

break;

default:

ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);

}

}

private void sendBytes(APDU apdu,byte[] arrays) {

byte[] buffer = apdu.getBuffer();

short length = (short) arrays.length;

Util.arrayCopyNonAtomic(arrays, (short) 0, buffer, (short) 0,

(short) length);

apdu.setOutgoingAndSend((short) 0, length);

}

}

接下来贴出Android端的核心代码,下载地址:http://download.csdn.net/detail/hellogv/8090053。

大概的思路是:Android端的NFC读写程序定义1个Applet的ID(AID),SELECT命令的报文头(SELECT_APDU_HEADER),2个自定义命令CMD_INS_1和CMD_INS_2。首先使用AID和SELECT_APDU_HEADER生成完整的SELECT命令,transceive(发送)到卡片,用于启动卡片里的AID对应的Applet。启动卡片里的Applet后,NFC读写程序发送SAMPLE_COMMAND里面的2条自定义命令,Applet分别返回"Hello""World"。

核心源码如下:

[java] view plaincopyprint?

在CODE上查看代码片

派生到我的代码片

 

private static final String TAG = "LoyaltyCardReader";

// AID for our loyalty card service.

private static final String SAMPLE_CARD_AID = "1122001122";

// ISO-DEP command HEADER for selecting an AID.

// Format: [Class | Instruction | Parameter 1 | Parameter 2]

private static final String SELECT_APDU_HEADER = "00A40400";

// "OK" status word sent in response to SELECT AID command (0x9000)

private static final byte[] SELECT_OK_SW = {(byte) 0x90, (byte) 0x00};

//自定义的命令

private static final String[] SAMPLE_COMMAND={"8010000000",//卡片收到后返回"Hello"

"8020000000"};//卡片收到后返回"World"

public static String[][] TECHLISTS;

public static IntentFilter[] FILTERS;

static {

try {

//the tech lists used to perform matching f