如何创建仅支持单实例安装的JavaCard小程序?删除后可重装
实现单实例JavaCard小程序的方案
要实现同一时间仅能安装一个实例的JavaCard小程序,核心是利用小程序安装阶段的静态检查逻辑,结合卡内持久化存储的标记控制安装流程——删除实例后标记会随私有存储区被自动清除,从而允许重新安装。
基础实现方案
代码示例
package com.yourpackage; import javacard.framework.*; public class SingleInstanceApplet extends Applet { // 存储在EEPROM的实例存在标记,删除小程序时会被卡系统自动清除 private static boolean instanceCreated; protected SingleInstanceApplet() { register(); } public static void install(byte[] bArray, short bOffset, byte bLength) throws ISOException { // 检查是否已有实例存在 if (instanceCreated) { // 抛出标准错误码阻止重复安装 ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); } // 标记实例已创建 instanceCreated = true; // 初始化并注册小程序 new SingleInstanceApplet(); } public void process(APDU apdu) throws ISOException { byte[] buf = apdu.getBuffer(); if (selectingApplet()) { return; } // 处理业务APDU命令 switch (buf[ISO7816.OFFSET_INS]) { case (byte)0x01: // 示例命令逻辑 break; default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } } }
关键逻辑说明
instanceCreated变量:作为静态成员,它会被存储在小程序专属的EEPROM区域。当小程序被删除时,卡系统会回收该区域的所有数据,标记会自动清除,后续可重新安装。- 安装阶段检查:
install方法是静态入口,创建实例前先检查标记,若已存在则抛出0x6A81(功能不支持)的标准ISO错误码,终端可直接识别该错误。 - 实例注册:构造方法中调用
register()是JavaCard小程序的标准初始化步骤,确保实例被卡系统正确注册。
更严谨的注册表方案
如果需要更可靠的实例检查,可以利用JavaCard的系统注册表存储实例引用:
package com.yourpackage; import javacard.framework.*; public class SingleInstanceApplet extends Applet { // 唯一注册表键,避免与其他小程序冲突 private static final byte[] APPLET_INSTANCE_KEY = {(byte)'S',(byte)'I',(byte)'A',(byte)'P'}; protected SingleInstanceApplet() { register(); } public static void install(byte[] bArray, short bOffset, byte bLength) throws ISOException { // 尝试从注册表获取已存在的实例 Object existingInstance = JCSystem.getRegistryEntry(APPLET_INSTANCE_KEY); if (existingInstance != null) { ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); } SingleInstanceApplet applet = new SingleInstanceApplet(); // 将实例存入系统注册表 JCSystem.setRegistryEntry(APPLET_INSTANCE_KEY, applet); } // 可选:手动清除注册表项(卡系统通常会自动处理,此步骤提升兼容性) public void uninstall() { JCSystem.deleteRegistryEntry(APPLET_INSTANCE_KEY); super.uninstall(); } public void process(APDU apdu) throws ISOException { // 业务命令处理逻辑 byte[] buf = apdu.getBuffer(); if (selectingApplet()) { return; } ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } }
方案优势
- 利用系统注册表的全局存储特性,能更精准地检测实例是否存在,避免静态变量可能的意外问题。
- 手动重写
uninstall方法清除注册表项,可确保在不同卡系统中的兼容性,虽然多数卡系统会自动清理关联数据。
内容的提问来源于stack exchange,提问作者1chenar
相关产品推荐
相关产品推荐

