Android设备下如何获取读卡器连接的多张卡片名称
如何在Android上获取读卡器中多张卡片的名称
嘿,这个问题我之前帮不少开发者处理过——核心是得通过APDU指令序列主动和读卡器交互,毕竟大多数支持多卡片的读卡器不会主动推送所有卡片信息,得你一步步去问它。以下是具体的实现思路和步骤:
1. 先让读卡器告诉你有几张卡片
首先你得枚举读卡器内的所有卡片,这一步要发送读卡器对应的枚举指令。不同厂商的读卡器指令可能略有差异,但大部分兼容PC/SC标准的读卡器,你可以试试这些操作:
- 先发送初始化指令:
00 A4 04 00 08 A0 00 00 00 03 00 00 00,让读卡器进入可交互状态 - 再发送卡片数量查询指令:
FF 00 48 00 00,读卡器会返回响应,你从中解析出当前连接的卡片数量
如果你的读卡器是自定义指令集,一定要参考厂商提供的开发文档,别硬套标准指令哦。
2. 逐个选中卡片,建立专属通信
拿到卡片数量后,你需要逐个选中每张卡片——只有选中特定卡片后,后续的指令才会作用于它。选中卡片的核心是用卡片的UID(唯一标识)来指定目标,比如标准的选中指令格式是:00 A4 00 00 [UID长度字节] [UID的字节数组]。
举个例子,如果某张卡片的UID是12 34 56 78,那选中指令就是00 A4 00 00 04 12 34 56 78。发送这个指令后,读卡器就会把通信目标切换到这张卡片上。
3. 查询卡片名称(或类型/应用名称)
选中卡片后,就可以发送指令查询它的名称了,常见的两种方式:
- 查询默认应用名称:发送
00 A4 04 00 00(空AID查询指令),读卡器会返回卡片上默认应用的信息,其中通常包含应用名称(如果卡片支持的话) - 通过厂商信息映射名称:先发送
FF CA 00 00 00获取卡片UID,再发送FF 00 00 00 00读取制造商信息,然后根据厂商代码(比如NXP对应MIFARE系列)映射出卡片的常见名称
4. 维护多卡片的动态列表
如果读卡器支持卡片热插拔(插入/移除),你需要定期轮询卡片数量,更新你的卡片列表:
- 每隔几秒重新发送卡片数量查询指令
- 对比新老列表,新增或移除对应的卡片信息
- 所有USB通信操作都要放在子线程里,别阻塞UI线程!
简化代码示例
这里给你一个核心逻辑的代码片段,实际要根据你的读卡器指令调整:
// 假设已经拿到UsbDeviceConnection conn和对应的UsbEndpoint endpoint // 1. 查询卡片数量 byte[] getCardCountCmd = hexStringToByteArray("FF 00 48 00 00"); byte[] countResponse = sendApdu(conn, endpoint, getCardCountCmd); int cardCount = parseCardCount(countResponse); // 自己实现响应解析逻辑 // 2. 遍历每张卡片查询信息 for (int i = 0; i < cardCount; i++) { // 获取当前卡片的UID byte[] getUidCmd = hexStringToByteArray("FF CA 00 00 00"); byte[] uidResponse = sendApdu(conn, endpoint, getUidCmd); String cardUid = bytesToHexString(uidResponse); // 选中该卡片 byte[] selectCmd = buildSelectCardCmd(cardUid); // 构建选中指令,传入UID生成对应字节数组 sendApdu(conn, endpoint, selectCmd); // 查询卡片名称 byte[] getNameCmd = hexStringToByteArray("00 A4 04 00 00"); byte[] nameResponse = sendApdu(conn, endpoint, getNameCmd); String cardName = parseCardName(nameResponse); // 解析响应中的名称字段 // 打印或保存卡片信息 Log.d("CardManager", "卡片UID: " + cardUid + ",名称: " + cardName); } // 辅助方法:十六进制字符串转字节数组 private 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; }
关键提醒
- 一定要看读卡器文档:不同厂商的读卡器指令差异很大,比如有些国产读卡器用自定义指令枚举多卡片,别盲目用标准PC/SC指令
- APDU响应要先判断状态码:响应的最后两个字节是状态码,
90 00表示操作成功,其他码都是失败,要先判断再解析数据 - 线程安全很重要:USB通信是同步阻塞的,所有指令发送和解析都要放在子线程,避免ANR
内容的提问来源于stack exchange,提问作者Rishwanth L
相关产品推荐
相关产品推荐

