本文来自http://blog.csdn.net/hellogv/ 。引用必须注明出处。
       眼下常见的智能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手机的简单通信。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGVsbG9ndg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

接下来贴段简单的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。

核心源代码例如以下:

public class mytest extends Applet {

	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"。

核心源代码例如以下:

public final class CardReader {
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 for dispatching of the ACTION_TECH_DISCOVERED intent
TECHLISTS = new String[][] { { IsoDep.class.getName() }}; FILTERS = new IntentFilter[] { new IntentFilter(
NfcAdapter.ACTION_TECH_DISCOVERED, "*/*") };
} catch (Exception e) {
}
} static public String tagDiscovered(Tag tag) {
Log.e(TAG, "New tag discovered"); String strResult="";
IsoDep isoDep = IsoDep.get(tag);
if (isoDep != null) {
try {
// Connect to the remote NFC device
isoDep.connect(); //发送select 命令,卡片会返回SELECT_OK_SW(90 00)
byte[] cmdSelect = BuildSelectApdu(SAMPLE_CARD_AID);
Log.e(TAG, "Sending: " + ByteArrayToHexString(cmdSelect));
byte[] result = isoDep.transceive(cmdSelect);
Log.e(TAG, "Receive: " + ByteArrayToHexString(result));
byte[][] response = getResponse(result);
byte[] statusWord =response[0]; if (Arrays.equals(SELECT_OK_SW, statusWord) == false)
return ""; //循环发送自己定义命令
for(int i=0;i<SAMPLE_COMMAND.length;i++){
String command = SAMPLE_COMMAND[i];
result = HexStringToByteArray(command);
Log.e(TAG, "Sending: " + command); result = isoDep.transceive(result);
Log.e(TAG, "Receive: " + ByteArrayToHexString(result));
response = getResponse(result);
byte[] body =response[1]; strResult=strResult+new String(body)+":"+ByteArrayToHexString(body)+"\r\n";
} return strResult; } catch (IOException e) {
Log.e(TAG, "Error communicating with card: " + e.toString());
}
}
return null;
} /***
* 分解卡片返回的数据
* @param b
* @return [0]表示返回的状态值,[1]表示返回的正文
*/
private static byte[][] getResponse(byte[] b){
byte[][] result = new byte[2][]; int length = b.length;
byte[] status = { b[length - 2],b[length - 1] }; byte[] body = Arrays.copyOf(b, length - 2); result[0]=status;
result[1]=body;
return result;
} public static String load(Parcelable parcelable) {
// 从Parcelable筛选出各类NFC标准数据
final Tag tag = (Tag) parcelable;
return tagDiscovered(tag);
} /**
* Build APDU for SELECT AID command. This command indicates which service a reader is
* interested in communicating with. See ISO 7816-4.
*
* @param aid Application ID (AID) to select
* @return APDU for SELECT AID command
*/
public static byte[] BuildSelectApdu(String aid) {
// Format: [CLASS | INSTRUCTION | PARAMETER 1 | PARAMETER 2 | LENGTH | DATA]
return HexStringToByteArray(SELECT_APDU_HEADER + String.format("%02X", aid.length() / 2) + aid);
} /**
* Utility class to convert a byte array to a hexadecimal string.
*
* @param bytes Bytes to convert
* @return String, containing hexadecimal representation.
*/
public static String ByteArrayToHexString(byte[] bytes) {
final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] hexChars = new char[bytes.length * 2];
int v;
for ( int j = 0; j < bytes.length; j++ ) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
} /**
* Utility class to convert a hexadecimal string to a byte string.
*
* <p>Behavior with input strings containing non-hexadecimal characters is undefined.
*
* @param s String containing hexadecimal characters to convert
* @return Byte array generated from input
*/
public static byte[] HexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}

移动支付之智能IC卡与Android手机进行NFC通信的更多相关文章

  1. "软掩膜"和“硬掩膜”-智能IC卡

    目录 一.“软掩膜”和“硬掩膜”... 2 二.EMV迁移进程... 3 三.PBOC规范和EMV规范对比... 3 四.总结... 5 五.关于SDA和DDA. 6 一.“软掩膜”和“硬掩膜” “软 ...

  2. 智能IC卡中的文件系统

    1.文件系统是COS的重要模块之一,它负责组织.管理.维护IC卡内存储的所有数据. 文件系统的设计和实现既是COS系统中最灵活.最有个性的部分,也是对系统整体结构影响最大的模块之一. 2.在IC卡内, ...

  3. 智能IC卡与终端(读卡器)之间的传输协议

    1.有两种协议 T=0,异步半双工字符传输协议 T=1,异步半双工块传输协议 终端一般都支持这两种协议,IC卡可以选择支持其中的一种.(因为终端可能需要面对各种类型的卡片,所以必须两种协议都支持,而卡 ...

  4. WIFI环境下Android手机和电脑通信

    前面已经写过一篇java实现最基础的socket网络通信,这篇和之前那篇大同小异,只是将客户端代码移植到手机中,然后获取本机IP的方法略有不同. 先讲一下本篇中用到Android studio的使用吧 ...

  5. IC卡

    本词条由“科普中国”百科科学词条编写与应用工作项目 审核 . IC卡 (Integrated Circuit Card,集成电路卡),也称智能卡(Smart card).智慧卡(Intelligent ...

  6. IC卡读卡器在安卓(android)下的开发

    友我科技推出IC卡读卡器的Android开发包,软件工程师只需要导入jar类库文件,就可以在App中操作IC卡读卡器了. 目前IC卡读卡器的Android开发包开放操作的卡类型有:M1, S50, U ...

  7. 电感耦合非接触IC卡系统的EMI问题

    射频识别(RFID)技术近年来发展迅速,并获得了广泛应用.但作为一种无线射频技术,其电磁兼容(EMC)性能也越来越受到人们的关注.RFID涉及的频率范围甚广,包括低于135kHz.13.56MHz.4 ...

  8. IC卡制作常识概述

    ic卡主要有9种:    1.接触型IC卡:    2.非接触型IC卡:    3.串行传输型IC卡:    4.并行传输型IC卡:    5.存储型IC卡:    6.智能型IC卡:    7.超级 ...

  9. 磁条卡,IC卡,ID卡,信用卡芯片卡,信用卡磁条卡 等等的区别

    1.条码卡:该卡卡面上有一串条码,通过扫描枪或者相应的条码读卡器读出该条码卡的卡号.根据条码的不同又分为39码等其它码.条码卡仅仅是一个编号,不存蓄其它内容.特点:价格便宜类似磁卡. 2.磁条卡:类似 ...

随机推荐

  1. 简学LINGO(三)——实例篇

    1. 装配线平衡模型 一个装配线含有一系列的工作站.在终于产品的加工过程中每一个工作站运行一种或者是几种特定的任务.装配线周期是指全部工作站完毕分配给他们各自任务所花费时间的最大值.平衡装配线的目标是 ...

  2. Android 编程下 Activity 的创建和应用退出时的销毁

    为了确保对应用中 Activity 的创建和销毁状态进行控制,所以就需要一个全局的变量来记录和销毁这些 Activity.这里的大概思路是写一个类继承 Application,并使获取该 Applic ...

  3. oracle函数之replace

    replace('将要更改的字符串','被替换掉的字符串','替换字符串'): ','****') from tmall_tcmessage; 输出为 '158****3367'

  4. Java ----------- SQL语句总结(更新中。。。。。。)

    #对数据库的操作 *创建数据库 CREATE DATABASE database_name:database_name为创建的数据库的变量名称. #对表的操作

  5. Tomcat 7.0 进入项目管理页面时的密码问题

    tomcat7 这个版本,官方网下载的原始包项目管理页面的权限和之前版本的配置有点区别. 到Tomcat的conf文件夹下找到tomcat-users.xml文件,有配置权限的配置文件.     ma ...

  6. mysqlbinlog详解

    mysqlbinlog用于处理二进制日志文件的实用工具详解mysqlbinlog从二进制日志读取语句的工具.在二进制日志文件中包含的执行过的语句的日志可用来帮助从崩溃中恢复. binlog日志打开方法 ...

  7. iOS图片拉伸技巧—— resizableImageWithCapInsets

    http://blog.csdn.net/chaoyuan899/article/details/19811889

  8. python之简单入门01

     python简单的介绍使用: 一.个人感觉写Python程序,最好用的工具就是pycharm了,自动补全功能可以满足大多数不太喜欢记忆的人群: 安装pycharm之前应该先安装python解释器,目 ...

  9. 利用WSGI来部署你的网站

    利用WSGI来部署你的网站 当需要部署你的django项目的时候,可以使用apache+python来部署访问你的网站. 由于网上的有关的都是老版本的.所以这里使用apache2.4和python3. ...

  10. IOS 音频播放

    iOS音频播放 (一):概述 前言 从事音乐相关的app开发也已经有一段时日了,在这过程中app的播放器几经修改我也因此对于iOS下的音频播放实现有了一定的研究.写这个系列的博客目的一方面希望能够抛砖 ...