第二章:JavaCard开发环境搭建
好,咱们正式开始动手了。
上一章聊了JavaCard是什么、能干什么。这一章,咱们把开发环境搭起来,写一个真正的Applet,然后把它装到卡片上。
我个人习惯先把环境搞利索再写代码。你想想看,如果环境配不好,后面调试起来会非常痛苦。我在项目中遇到过好几次,明明代码没问题,结果是因为SDK版本不对,折腾了一整天。
2.1 安装JavaCard SDK
JavaCard SDK是Oracle官方提供的开发工具包。目前最新的稳定版本是3.x,但很多实际项目还在用2.2.2或3.0.4。为什么?因为卡片厂商的底层支持往往滞后。
下载地址:Oracle官网(需要注册账号,免费)
安装步骤:
- 下载
java_card_kit-3_0_5-win32-bin.zip(Windows为例) - 解压到
C:\JavaCardKit\(路径不要有中文和空格) - 设置环境变量
JC_HOME=C:\JavaCardKit\java_card_kit-3_0_5 - 将
%JC_HOME%\bin加入PATH
C:\jc 或 D:\jc。
2.2 配置开发工具
说实话,JavaCard开发不需要什么花哨的IDE。记事本都能写,但效率太低。
我推荐的工具组合:
| 工具 | 用途 | 我的建议 |
|---|---|---|
| Eclipse / IntelliJ IDEA | 代码编辑 | 用你熟悉的就行,我习惯Eclipse |
| Ant / Maven | 构建工具 | Ant在JavaCard圈更常见 |
| GPJ(GlobalPlatform Pro) | 卡片管理 | 装Applet必备 |
| JCDK自带的工具 | 模拟器、转换器 | SDK自带,不用额外装 |
Eclipse配置步骤:
- 安装Eclipse IDE for Java Developers
- 新建Java项目,取消勾选“Use default location”,选择SDK下的
samples目录 - 添加
jc.jar到Build Path(在%JC_HOME%\lib\下) - 安装
JCDE插件(可选,但能提供语法高亮)
api 目录设为源码根目录,不然很多类会报红。嗯,这里要注意。
2.3 编写第一个Applet
好了,环境搭好了。咱们写一个最简单的Applet——它什么都不做,只是响应一个“Hello”命令。
import javacard.framework.*;
public class HelloApplet extends Applet {
private static final byte[] HELLO_MSG = {'H', 'e', 'l', 'l', 'o'};
private static final byte CLA = (byte) 0x00;
private static final byte INS_HELLO = (byte) 0x01;
public static void install(byte[] bArray, short bOffset, byte bLength) {
new HelloApplet().register();
}
public void process(APDU apdu) {
if (selectingApplet()) {
return;
}
byte[] buffer = apdu.getBuffer();
// 检查CLA和INS
if (buffer[ISO7816.OFFSET_CLA] != CLA) {
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
}
if (buffer[ISO7816.OFFSET_INS] != INS_HELLO) {
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
// 返回"Hello"
apdu.setOutgoingAndSend((short) 0, (short) HELLO_MSG.length);
Util.arrayCopyNonAtomic(HELLO_MSG, (short) 0, buffer, (short) 0, (short) HELLO_MSG.length);
}
}
这段代码我解释一下:
install()是入口,每个Applet必须实现。说白了就是卡片的构造函数。process()处理APDU命令。APDU是卡片和终端通信的协议单元。selectingApplet()判断当前是不是选择命令。如果是,直接返回,不处理。
核心要点:
- 所有Applet必须继承
javacard.framework.Applet - 必须实现
install()和process() - APDU缓冲区是共享的,操作要小心
2.4 编译与安装
写完了代码,怎么把它弄到卡片上?
第一步:编译
JavaCard的编译和普通Java不一样。它需要两步:
- 先用普通javac编译成.class文件
- 再用
converter工具转换成CAP文件(JavaCard的可执行文件)
我一般写一个Ant脚本来自动化这个过程:
<project name="HelloApplet" default="build">
<property name="jc.home" value="C:/JavaCardKit/java_card_kit-3_0_5"/>
<target name="build">
<!-- 第一步:javac编译 -->
<exec executable="javac">
<arg value="-cp"/>
<arg value="${jc.home}/lib/jc.jar"/>
<arg value="-d"/>
<arg value="build/classes"/>
<arg value="src/HelloApplet.java"/>
</exec>
<!-- 第二步:converter转换 -->
<exec executable="${jc.home}/bin/converter">
<arg value="-classdir"/>
<arg value="build/classes"/>
<arg value="-d"/>
<arg value="build/cap"/>
<arg value="-applet"/>
<arg value="0x01:0x02:0x03:0x04:0x05:0x06:0x07:0x08:HelloApplet"/>
<arg value="-out"/>
<arg value="CAP"/>
<arg value="HelloApplet"/>
</exec>
</target>
</project>
第二步:安装到卡片
安装需要用到GlobalPlatform命令。我常用 gp 工具(GlobalPlatform Pro):
# 加载CAP文件到卡片
gp --install build/cap/HelloApplet.cap
# 列出已安装的Applet
gp --list
# 删除Applet(如果装错了)
gp --delete 0x01:0x02:0x03:0x04:0x05:0x06:0x07:0x08
2.5 验证安装是否成功
装好了怎么知道它跑起来了?用APDU测试工具发个命令试试。
我推荐 JCIDE 自带的APDU工具,或者用Python写个脚本:
import smartcard.System
# 连接卡片
readers = smartcard.System.readers()
reader = readers[0]
connection = reader.createConnection()
connection.connect()
# 选择Applet
SELECT = [0x00, 0xA4, 0x04, 0x00, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
data, sw1, sw2 = connection.transmit(SELECT)
print(f"选择结果: {sw1:02X} {sw2:02X}")
# 发送Hello命令
HELLO = [0x00, 0x01, 0x00, 0x00, 0x00]
data, sw1, sw2 = connection.transmit(HELLO)
print(f"返回数据: {bytes(data)}")
print(f"状态字: {sw1:02X} {sw2:02X}")
如果返回 Hello 且状态字是 90 00,恭喜你,第一个Applet跑起来了!
2.6 本章知识体系
下面这张图总结了开发环境搭建的完整流程:
这张图把整个流程串起来了。从安装SDK到验证Applet,每一步都有坑。但只要你按这个流程走,基本不会出大问题。
好了,环境搭好了,第一个Applet也跑起来了。接下来你就可以开始折腾更复杂的功能了。记住,JavaCard开发的核心就是APDU通信,把这条线抓住了,后面就顺了。
公众号:蓝海资料掘金营,微信deep3321