這是我們為大家提供的一篇介紹移動支付之智能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手機的簡單通信。
接下來貼段簡單的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?
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?
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