Android 6+设备HCE服务BIND_NFC_SERVICE权限授权失败求助
解决Android 6.0+ HCE应用权限被拒(返回6999)的问题
兄弟,我一看你的问题就知道踩了Android权限管控的坑——BIND_NFC_SERVICE这个权限根本不是给普通第三方HCE应用用的!先给你拆解清楚问题根源,再给你一步步的解决方案:
问题核心:你误解了HCE所需的权限
Android 6.0+对系统特权权限的管控变得极严,BIND_NFC_SERVICE属于signature|privileged级别的权限:
- 要么你的应用用系统签名打包,
- 要么得把应用放到
/system/priv-app目录下,
普通第三方应用哪怕Root后手动授予,重启后系统也会自动收回这个权限,因为它本来就不是给咱们普通开发者用的。
更关键的是:开发HCE应用根本不需要这个权限!你大概率是误加了这个权限,反而导致系统拒绝你的NFC请求,返回6999状态码。
正确的HCE应用配置步骤
1. 修正AndroidManifest.xml配置
把错误的BIND_NFC_SERVICE权限删掉,换成HCE应用真正需要的配置:
<!-- 基础NFC权限 --> <uses-permission android:name="android.permission.NFC" /> <!-- 声明设备必须支持HCE --> <uses-feature android:name="android.hardware.nfc.hce" android:required="true" /> <application ...> <!-- HCE服务核心配置 --> <service android:name=".YourHostApduService" <!-- 替换成你的HCE服务类名 --> android:exported="true" <!-- 这里用HOST_APDU_SERVICE权限,而不是BIND_NFC_SERVICE --> android:permission="android.permission.HOST_APDU_SERVICE"> <intent-filter> <!-- HCE服务的标准Action --> <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" /> </intent-filter> <!-- 指向HCE服务的AID配置文件 --> <meta-data android:name="android.nfc.cardemulation.host_apdu_service" android:resource="@xml/apduservice" /> </service> </application>
2. 配置AID列表(res/xml/apduservice.xml)
这个文件用来定义你的HCE应用响应的AID,必须和外部设备发送的SELECT AID命令匹配:
<?xml version="1.0" encoding="utf-8"?> <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/hce_service_desc" android:requireDeviceUnlock="false"> <!-- 是否需要解锁设备才能响应 --> <aid-group android:description="@string/aid_group_desc" android:category="other"> <!-- category根据你的场景选,比如"payment"是支付类 --> <!-- 替换成你实际使用的AID,多个AID可以加多个<aid-filter> --> <aid-filter android:name="F0010203040506" /> </aid-group> </host-apdu-service>
3. 检查你的HCE服务类实现
确保你的服务类继承自HostApduService,并且正确重写核心方法:
public class YourHostApduService extends HostApduService { private static final String SELECT_AID_APDU = "00A4040007F001020304050600"; @Override public byte[] processCommandApdu(byte[] apdu, Bundle extras) { String apduHex = Hex.encodeHexString(apdu); if (SELECT_AID_APDU.equals(apduHex)) { // 返回成功响应,比如9000 return Hex.decodeHex("9000".toCharArray()); } else { // 其他命令的处理逻辑,这里示例返回"文件未找到" return Hex.decodeHex("6A82".toCharArray()); } } @Override public void onDeactivated(int reason) { // 服务被停用的回调,比如NFC连接断开时的清理逻辑 } }
调试与验证步骤
- 检查系统设置:确保设备NFC已开启,并且你的HCE应用在系统NFC设置中被选中(部分设备需要在“默认付款应用”里切换到你的应用)。
- Logcat排查:过滤关键词
HostApduService或NFC,查看有没有服务注册失败、AID不匹配的日志。 - 验证APDU命令:确保外部设备发送的SELECT AID命令和你配置的AID完全一致(注意大小写、长度)。
关于Root设备的额外说明
如果你的场景确实需要系统级NFC权限(99%的普通HCE应用不需要),那必须:
- 把应用安装到
/system/priv-app目录下, - 用对应设备的系统签名打包应用,
否则重启后权限一定会被系统回收,这是Android 6.0+的安全机制决定的。
内容的提问来源于stack exchange,提问作者engineer0815




