You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android集成ACR122U NFC读卡器与HCE通信故障排查

问题分析与解决方案

首先,我先梳理下你遇到的核心问题:用ACR122U读卡器连接Android设备后,发送SELECT AID的APDU根本触发不了HCE服务的processCommandApdu方法,不管是贴普通NFC标签还是Android设备,轮询后的SELECT命令都只返回一堆0,完全没法正常通信。

先拆解你的当前情况

  • 目标:用ACR122U连接Android设备,实现和另一台HCE模式设备的数据交互
  • 使用工具:厂商提供的acssmc-1.1.1.jar库
  • 核心操作代码:
    mReader.power(slotNum, Reader.CARD_WARM_RESET); 
    mReader.setProtocol(slotNum, Reader.PROTOCOL_T0 | Reader.PROTOCOL_T1); 
    
    // 轮询ISO14443-4 A的指令
    byte[] w = new byte[255]; 
    int len = mReader.transmit(0, new byte[] { (byte)0xFF, 0x00, 0x00, 0x00, 0x04,(byte)0xD4, 0x4A, 0x01, 0x00}, 9, w, w.length); 
    Log.e("Response", "r: " + NfcUtils.convertBinToASCII(w, 0, len)); 
    
    // 选择AID的APDU
    w = new byte[255]; 
    mReader.transmit(0, new byte[] {0x00, (byte) 0xA4, 0x04, 0x00, 7, (byte)0xF0, 0x01, 0x02, 0x03, 0x04, (byte) 0x05, 0x07, 0}, 13, w, w.length); 
    Log.e("Response", "r: " + Arrays.toString (recvBuffer)); 
    
  • 测试反馈:
    • 贴普通NFC标签:轮询响应为D54B0101440004048853606A9000,但SELECT命令返回一堆0
    • 贴Android设备:轮询响应为D54B6300,SELECT命令同样返回一堆0
  • HCE服务情况:自定义的MyHostApduService中processCommandApdu从未被调用,设备日志无相关记录

核心问题排查与解决建议

1. 轮询指令的兼容性问题

你发送的轮询指令是FF 00 00 00 04 D4 4A 01 00,这个指令是指定只轮询ISO14443-4 Type A的设备,但Android HCE虽然支持Type A,部分设备可能需要更灵活的轮询策略。建议修改轮询指令,试试自动适配波特率的版本:

// 自动适配波特率,查找1个目标设备
mReader.transmit(0, new byte[] { (byte)0xFF, 0x00, 0x00, 0x00, 0x04,(byte)0xD4, 0x4A, 0x00, 0x01}, 9, w, w.length);

另外,D54B6300这个响应代码对应的是轮询失败(未找到符合要求的目标),说明读卡器没正确识别到Android的HCE设备,调整轮询策略大概率能改善这个情况。

2. APDU发送方式错误(最可能的核心问题)

你现在是直接给读卡器发送SELECT APDU,但ACR122U作为PC/SC读卡器,要和HCE设备通信,不能直接发APDU,而是需要通过读卡器的**InDataExchange控制指令(D4 40)**把APDU转发给目标设备。正确的流程应该是:

  1. 轮询目标设备,获取目标的CID(通信ID,从轮询响应中提取)
  2. 用D4 40指令把SELECT APDU转发给目标设备
    示例代码大概是这样:
// 假设轮询成功后,从响应中拿到CID(比如响应里的第5个字节,具体看ACR122U文档)
byte cid = w[4];
// 要发送的SELECT APDU
byte[] selectApdu = new byte[] {0x00, (byte)0xA4, 0x04, 0x00, 0x07, (byte)0xF0, 0x01, 0x02, 0x03, 0x04, (byte)0x05, 0x07, 0x00};
// 组装InDataExchange指令:FF 00 00 00 + 长度 + D4 40 + CID + APDU
byte[] command = new byte[5 + 1 + 1 + selectApdu.length];
command[0] = (byte)0xFF;
command[1] = 0x00;
command[2] = 0x00;
command[3] = 0x00;
command[4] = (byte)(1 + 1 + selectApdu.length); 
command[5] = (byte)0xD4;
command[6] = 0x40;
command[7] = cid;
System.arraycopy(selectApdu, 0, command, 8, selectApdu.length);
// 发送指令
int len = mReader.transmit(0, command, command.length, w, w.length);

3. HCE服务配置与响应问题

检查你的AndroidManifest和HCE配置是否正确:

  • 确保MyHostApduService的声明正确:
    <service
        android:name=".MyHostApduService"
        android:exported="true"
        android:permission="android.permission.BIND_NFC_SERVICE">
        <intent-filter>
            <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
        </intent-filter>
        <meta-data
            android:name="android.nfc.cardemulation.host_apdu_service"
            android:resource="@xml/apdu_service"/>
    </service>
    
  • 确保apdu_service.xml里的AID过滤和你发送的SELECT AID一致:
    <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
        android:description="@string/servicedesc"
        android:requireDeviceUnlock="false">
        <aid-group android:description="@string/aiddesc"
            android:category="other">
            <aid-filter android:name="F0010203040507"/>
        </aid-group>
    </host-apdu-service>
    

另外,你的processCommandApdu返回的是new byte[2],这不符合APDU响应规范,应该返回包含状态码的响应,比如成功时返回new byte[]{(byte)0x90, 0x00},这样读卡器才能识别有效响应。

4. 读卡器固件故障

你提到在Windows、OSX上也无法正常运行,这大概率说明读卡器本身有问题(比如旧固件兼容性差,甚至硬件故障)。建议去ACR122U官方渠道下载最新固件,更新后再测试,很多类似的通信问题都是固件更新后解决的。

内容的提问来源于stack exchange,提问作者cliffroot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 08:57:55