Android平台基于Flutter实现NFC标签模拟(HCE)技术求助
Android平台Flutter实现NFC HCE标签模拟方案
核心前提确认
- 设备兼容性:仅支持具备
NFC HCE功能的Android设备,可通过原生代码检查PackageManager.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION) - 门禁协议适配:HCE仅支持ISO 14443-4标准的AID模拟,无法兼容MIFARE Classic(需硬件加密模块支持),先确认门禁系统使用的NFC协议类型
关键实现步骤
1. 配置AndroidManifest.xml
添加NFC权限、声明HCE服务及AID过滤规则:
<!-- 基础权限与特性声明 --> <uses-permission android:name="android.permission.NFC" /> <uses-feature android:name="android.hardware.nfc" android:required="true" /> <uses-feature android:name="android.hardware.nfc.hce" android:required="true" /> <!-- HCE服务声明 --> <service android:name=".HceService" 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/apduservice"/> </service>
在res/xml目录下创建apduservice.xml,配置门禁系统对应的AID:
<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"> <!-- 替换为门禁系统识别的真实AID --> <aid-filter android:name="F0010203040506"/> </aid-group> </host-apdu-service>
2. 实现原生HCE服务
创建HceService类继承HostApduService,处理门禁读卡器的APDU命令:
import android.nfc.cardemulation.HostApduService; import android.os.Bundle; import java.util.Arrays; public class HceService extends HostApduService { // 门禁读卡器发送的SELECT AID命令(需与真实卡片的命令匹配) private static final byte[] SELECT_APDU = { (byte)0x00, (byte)0xA4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xF0, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x00 }; // 模拟门禁授权成功的响应 private static final byte[] SUCCESS_RESPONSE = { (byte)0x90, (byte)0x00 }; // 命令不匹配时的失败响应 private static final byte[] FAILURE_RESPONSE = { (byte)0x6A, (byte)0x82 }; @Override public byte[] processCommandApdu(byte[] apdu, Bundle extras) { // 匹配读卡器的SELECT命令,返回模拟卡片的响应 if (Arrays.equals(apdu, SELECT_APDU)) { return SUCCESS_RESPONSE; } return FAILURE_RESPONSE; } @Override public void onDeactivated(int reason) { // 处理卡片模拟失活的逻辑(比如重置状态) } }
3. Flutter与原生层交互(可选)
若需在Flutter端动态修改模拟数据,通过MethodChannel实现跨层通信:
Flutter端代码:
import 'package:flutter/services.dart'; class HceController { static const MethodChannel _channel = MethodChannel('hce_control_channel'); /// 更新门禁响应数据 static Future<void> updateResponse(List<int> responseBytes) async { await _channel.invokeMethod('updateResponse', {'data': responseBytes}); } }
原生层HceService中添加MethodChannel处理:
import io.flutter.plugin.common.MethodChannel; public class HceService extends HostApduService { private static byte[] customResponse = SUCCESS_RESPONSE; @Override public void onCreate() { super.onCreate(); new MethodChannel(getApplicationContext(), "hce_control_channel") .setMethodCallHandler((call, result) -> { if (call.method.equals("updateResponse")) { List<Integer> dataList = call.argument("data"); byte[] newResponse = new byte[dataList.size()]; for (int i = 0; i < dataList.size(); i++) { newResponse[i] = dataList.get(i).byteValue(); } customResponse = newResponse; result.success(null); } else { result.notImplemented(); } }); } @Override public byte[] processCommandApdu(byte[] apdu, Bundle extras) { if (Arrays.equals(apdu, SELECT_APDU)) { return customResponse; } return FAILURE_RESPONSE; } // ...其他代码 }
常见问题排查
- AID不匹配:用NFC工具读取真实门禁卡的AID,确保与配置的
aid-filter完全一致 - 设备不支持:部分低端Android设备无HCE功能,可在系统设置中查看是否有"NFC卡片模拟"选项
- 权限问题:确保APP已获取NFC权限,且运行时处于前台状态
- MIFARE Classic限制:若门禁使用该协议,HCE无法模拟,需更换支持ISO 14443-4的门禁系统或设备
内容的提问来源于stack exchange,提问作者Jude Dcoutho
相关产品推荐
相关产品推荐

