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

Android Kotlin下HCE模拟NFC卡无响应问题求助

Android HCE模拟NFC卡无响应问题排查

我在Android应用中尝试通过HCE模拟NFC卡,使用另一台安装了NFC Tools应用的手机作为读卡器时,无法读取任何内容,且Apdu服务接收不到任何命令。测试设备为搭载Android 12的Galaxy A31,已完成以下配置:

Manifest配置

<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/hce_service" />
</service>

MyHostApduService代码

class MyHostApduService : HostApduService() {

    companion object {
        val TAG = "Host Card Emulator"
        val STATUS_SUCCESS = "9000"
        val STATUS_FAILED = "6F00"
        val CLA_NOT_SUPPORTED = "6E00"
        val INS_NOT_SUPPORTED = "6D00"
        val AID = "A0000002471001"
        val SELECT_INS = "A4"
        val DEFAULT_CLA = "00"
        val MIN_APDU_LENGTH = 12
    }

    override fun processCommandApdu(commandApdu: ByteArray, extras: Bundle?): ByteArray? {
        Log.i(TAG, "APDU Command Received: ${commandApdu.joinToString()}")

        val hexCommandApdu = toHex(commandApdu)
        if (hexCommandApdu.length < MIN_APDU_LENGTH) {
            return hexStringToByteArray(STATUS_FAILED)
        }

        if (hexCommandApdu.substring(0, 2) != DEFAULT_CLA) {
            return hexStringToByteArray(CLA_NOT_SUPPORTED)
        }

        if (hexCommandApdu.substring(2, 4) != SELECT_INS) {
            return hexStringToByteArray(INS_NOT_SUPPORTED)
        }

        if (hexCommandApdu.substring(10, 24) == AID)  {
            return hexStringToByteArray(STATUS_SUCCESS)
        } else {
            return hexStringToByteArray(STATUS_FAILED)
        }
    }

    override fun onDeactivated(reason: Int) {
        Log.d(TAG, "Deactivated: $reason")
    }

    private val HEX_CHARS = "0123456789ABCDEF"
    private fun hexStringToByteArray(data: String) : ByteArray {

        val result = ByteArray(data.length / 2)

        for (i in data.indices step 2) {
            val firstIndex = HEX_CHARS.indexOf(data[i]);
            val secondIndex = HEX_CHARS.indexOf(data[i + 1]);

            val octet = firstIndex.shl(4).or(secondIndex)
            result.set(i.shr(1), octet.toByte())
        }

        return result
    }

    private val HEX_CHARS_ARRAY = "0123456789ABCDEF".toCharArray()
    private fun toHex(byteArray: ByteArray) : String {
        val result = StringBuffer()

        byteArray.forEach {
            val octet = it.toInt()
            val firstIndex = (octet and 0xF0).ushr(4)
            val secondIndex = octet and 0x0F
            result.append(HEX_CHARS_ARRAY[firstIndex])
            result.append(HEX_CHARS_ARRAY[secondIndex])
        }

        return result.toString()
    }
}

hce_service.xml配置

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/service_name"
    android:requireDeviceUnlock="false">
    <aid-group android:description="@string/service_name"
        android:category="other">
        <aid-filter android:name="F0010203040506"/>
        <aid-filter android:name="F0394148148100"/>
    </aid-group>
</host-apdu-service>

问题排查与解决步骤

  • 核心问题:AID不匹配
    你在Service代码中硬编码的AID是A0000002471001,但xml配置里的AID过滤器是F0010203040506和F0394148148100,两者完全不匹配。读卡器(NFC Tools)只会发送匹配你xml中注册AID的SELECT指令,而你的Service只响应A0000002471001,自然收不到任何命令。
    解决:将xml里的AID过滤器修改为与Service中一致的A0000002471001,或者调整Service中的AID常量匹配xml里的任意一个AID。

  • 确认HCE服务的优先级与默认设置
    Android系统会优先选择优先级更高的HCE服务,可在xml的<aid-group>标签中添加android:priority="1000"(数值越高优先级越高),确保你的服务被系统选中。另外,进入设备系统设置的「NFC」-「卡模拟」选项,确认你的应用已设置为默认卡模拟服务,部分设备需要手动指定。

  • 调整NFC Tools的测试方式
    NFC Tools的默认「读取NFC卡」功能通常只会扫描标准卡的AID,不会主动触发自定义HCE服务。你需要手动创建「读取自定义AID」任务,输入你注册的AID值后再进行测试。

  • 验证设备兼容性与物理操作
    确认Galaxy A31的NFC功能已开启,测试时两台手机的NFC天线(通常位于顶部或背部中心)对齐,保持近距离接触,避免因天线位置不对导致通信失败。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 09:05:19