Java发送APDU指令是智能卡应用开发中的核心环节,其过程涉及指令结构解析、环境搭建、数据封装及通信流程等多个关键步骤,要准确实现APDU指令的发送,需从指令规范、开发环境、代码实现及错误处理等方面系统把握。

APDU指令基础:明确指令结构
APDU(Application Protocol Data Unit)是智能卡与应用程序间通信的基本单元,分为命令APDU(由主机发送)和响应APDU(由卡返回),命令APDU的标准结构为:CLA(1字节)| INS(1字节)| P1(1字节)| P2(1字节)| Lc(1字节,可选,指示数据字段长度)| Data(0-255字节,可选)| Le(1字节,可选,指示期望响应长度)。
确定指令时,需根据智能卡的功能规范(如ISO/IEC 7816-4)明确各字段含义:
- CLA:指令类,区分不同应用或协议;
- INS:指令码,如“读取二进制文件”(0xB0)、“写入数据”(0xD6);
- P1/P2:参数,通常指定文件偏移量、操作模式等;
- Lc/Le:数据长度和期望响应长度,若无数据则省略Lc,无响应则省略Le。
读取起始地址为0x00、长度为0x10的二进制文件,命令APDU可构造为00 B0 00 10 10(CLA=00,INS=B0,P1=00,P2=10,Le=10)。
Java环境准备:依赖与工具配置
Java发送APDU指令需借助智能卡通信接口,常用方案为PC/SC(Personal Computer/Smart Card),通过javax.smartcardio包(Java标准库)实现,无需额外依赖,仅需确保JDK版本≥1.6,并检查系统是否安装PC/SC驱动(如Windows的Smart Card Service,Linux的pcscd)。
开发时需导入核心类:

TerminalFactory:读卡器工厂,用于获取读卡器实例;CardTerminal:智能卡读卡器,代表物理读卡设备;Card:智能卡对象,封装卡连接与通信;CommandAPDU:命令APDU封装类,自动处理字节转换;ResponseAPDU:响应APDU封装类,解析卡返回数据。
指令构建与发送:代码实现流程
建立读卡器连接
通过TerminalFactory获取系统读卡器列表,选择可用读卡器并连接智能卡:
TerminalFactory factory = TerminalFactory.getInstance("PC/SC", null);
List<CardTerminal> terminals = factory.terminals().list();
if (terminals.isEmpty()) throw new Exception("未找到读卡器");
CardTerminal terminal = terminals.get(0); // 选择第一个读卡器
Card card = terminal.connect("*"); // "*"表示协议无关,返回Card对象
封装命令APDU
使用CommandAPDU类直接构造指令,避免手动字节转换错误,上述读取文件的指令可封装为:
CommandAPDU command = new CommandAPDU(0x00, 0xB0, 0x00, 0x10, 0x10);
若需发送数据(如写入文件),可通过构造函数的Data参数传入:
byte[] data = {0x01, 0x02, 0x03}; // 待写入数据
CommandAPDU command = new CommandAPDU(0x00, 0xD6, 0x00, 0x00, data, 0x00); // Le=00表示无预期响应
发送指令并接收响应
通过Card对象获取CardChannel(通信通道),调用transmit方法发送指令并获取响应:
CardChannel channel = card.getBasicChannel(); ResponseAPDU response = channel.transmit(command);
响应APDU包含状态字(SW1+SW2)和可选数据,可通过response.getBytes()获取完整响应,response.getSW()获取状态字(如0x6985表示“条件不满足”)。

错误处理与调试:确保指令准确性
发送APDU时常见错误包括指令格式错误、读卡器未连接、卡片无响应等,需通过以下方式排查:
- 状态字解析:根据ISO/IEC 7816-3标准,状态字
SW1=6X表示“执行错误”,SW1=9X表示“成功部分执行”。SW1=6A82(P2参数无效)、SW1=6985(拒绝执行),需对照卡片规范调整指令参数。 - 读卡器调试:通过
terminal.isCardPresent()检查卡片是否在读卡器中,或使用List<CardTerminal>打印所有可用读卡器名称。 - 日志输出:打印发送的APDU指令(
command.getBytes())和响应数据,对比预期结果定位问题。
注意事项
- 字节序与编码:APDU指令为大端序(高位在前),Java的
byte数组需确保顺序正确,避免使用String直接转换字节(如"00B00010"需转为new byte[]{0x00, (byte)0xB0, 0x00, 0x10})。 - 协议匹配:连接卡片时需指定正确协议(如
T=0或T=1),部分卡片仅支持特定协议。 - 资源释放:通信完成后需调用
card.disconnect(true)断开连接,释放读卡器资源。
通过以上步骤,可系统完成Java环境下APDU指令的确定与发送,确保与智能卡的稳定通信,实际开发中需结合具体卡片文档调整指令参数,并结合调试工具逐步优化流程。



















