0. 先看结果:这套方案解决了什么
如果你也在做 RN + Android 的本地人脸识别,通常会踩这几个坑:
- 密钥硬编码,安全和运维都很被动。
- 激活偶发卡住,前端一直 loading。
- 识别链路断点多,定位问题全靠猜。
- 页面代码和原生代码耦合严重,后续改动风险大。
这篇文章给出的方案,核心是三件事:
- 配置收敛:激活参数改成"配置文件优先,接口兜底"。
- 职责拆分:RN 负责流程与状态,Kotlin 负责引擎与特征处理。
- 排障前置:超时、错误码、脱敏日志、缓存兜底都做在链路里。
1. 一张图看完整链路
业务页面
RobotMatchUserTrtcScreen
useArcsoftSdk
arcsoftSdkService
配置来源
本地配置文件
后端接口 types=6
AsyncStorage 缓存
ArcFace.initArcFace
ArcFaceModule.kt
ArcFaceConfig.update
ensureActivated
activeOffline / activeOnline
ArcFaceCameraView
ArcFaceCameraController
featureBase64
ArcFace.validFaceLocal
FaceFeatureStore
FaceImageFeatureExtractor
compareFaceFeature
score 与 threshold 比较
2. 先把地基打牢:Android 工程集成
2.1 SDK 包与 ABI
文件:android/app/build.gradle
gradle
dependencies {
implementation files('libs/arcsoft_face.jar')
implementation files('libs/arcsoft_image_util.jar')
}
android {
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "arm64-v8a"
}
}
packagingOptions {
pickFirst '**/*.so'
}
}
实战建议:
abiFilters必须和你实际放入libs的 so 架构一致。- 新机器型上线前,先用 release 包做一次 so 完整性检查。
- 如果后续接入更多原生 SDK,优先排查
pickFirst是否掩盖冲突。
2.2 权限与 Manifest
文件:android/app/src/main/AndroidManifest.xml
最小相关权限:
xml
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
说明:
CAMERA用于预览帧提取特征。- 在线激活必须有网络权限。
- 离线 license 若走外部存储,再按设备策略补权限。
2.3 混淆保留
文件:android/app/proguard-rules.pro
proguard
-keep class com.arcsoft.face.** { *; }
-keep class com.arcsoft.imageutil.** { *; }
-keep class com.yog_lanzhou_robot_app.ArcFaceConfig { *; }
-keep class com.yog_lanzhou_robot_app.ArcFaceModule { *; }
-keep class com.yog_lanzhou_robot_app.ArcFaceCameraController { *; }
2.4 包注册
文件:android/app/src/main/java/com/yog_lanzhou_robot_app/MainApplication.kt
kotlin
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
add(ArcFacePackage())
}
3. 原生桥接怎么拆,后续才不痛苦
3.1 原生分层职责
ArcFaceConfig.kt:参数容器 + 激活策略 + 阈值/活体开关。ArcFaceModule.kt:RN 暴露方法,负责初始化与比对。ArcFaceCameraController.kt:相机帧检测、活体、实时特征抽取。FaceFeatureStore.kt:本地特征持久化。FaceImageFeatureExtractor.kt:注册图下载与增强提特征。ArcFaceCameraView.kt+ArcFaceCameraViewManager.kt:RN 可挂载的 Native View。
3.2 初始化时序(真实链路)
FaceEngine ArcFaceConfig.kt ArcFaceModule.kt ArcFaceModule.ts arcsoftSdkService useArcsoftSdk 页面 FaceEngine ArcFaceConfig.kt ArcFaceModule.kt ArcFaceModule.ts arcsoftSdkService useArcsoftSdk 页面 进入页面 initArcsoftSdkForRobot(robotId) ArcFace.initArcFace(config) initArcFace(config) update(appId/sdkKey/activeKey/...) ensureActivated(context) activeOffline 或 activeOnline 激活结果码 MOK/错误码 Promise resolve/reject 初始化结果 initialized/error
3.3 识别链路(实时帧 + 本地 1:N)
渲染错误: Mermaid 渲染失败: Parse error on line 6: ...-> F[loadFeatureList(depId)] F --> G -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'
链路亮点(来自当前工程代码):
- 初始化和比对都有超时/异常保护。
- 特征库缺失时可自动下载头像并注册。
- 活体可配置开关,不同业务可做差异化策略。
- 比对结果结构对齐
ApiEnvelope,RN 层处理成本低。
4. RN 侧怎么写,代码才"顺手"
4.1 三层封装
- Native 层适配:
src/nativeModules/ArcFaceModule.ts、src/nativeModules/ArcFaceCameraView.tsx - 服务层:
src/services/arcsoft/index.ts - 页面 Hook:
src/hooks/useArcsoftSdk.ts
你可以把它理解成:
- Native 层做"能力出口"。
- 服务层做"配置、容错、兜底"。
- Hook 做"页面状态协议"(
initialized/loading/error/reinit)。
4.2 页面实战调用(当前项目)
文件:src/robot_screens/RobotMatchUserTrtcScreen.tsx
核心过程:
useArcsoftSdk()先把引擎拉起。- 点击验证后挂载
ArcFaceCameraView。 - 收到
featureBase64调ArcFace.validFaceLocal。 - 根据
code/data.success触发业务后续动作。
这一层做得好的关键点是:UI 流程和 SDK 细节解耦。
5. 重点改造:激活和配置改成"配置文件方式"
当前仓库是"后端下发 + 本地缓存"模式,已经可用。如果你希望更可控(离线部署、工厂预置、多环境切换),推荐升级成:
- 配置文件优先
- 接口兜底
- 缓存保底
5.1 配置文件结构(脱敏模板)
文件建议:
config/arcsoft/arcsoft-sdk.template.json(入库)config/arcsoft/arcsoft-sdk.local.json(不入库)
json
{
"activationMode": "online",
"appId": "<ARCSOFT_APP_ID>",
"sdkKey": "<ARCSOFT_SDK_KEY>",
"activeKey": "<ARCSOFT_ACTIVE_KEY>",
"authFilePath": "",
"deviceCode": "<DEVICE_CODE>",
"threshold": 0.5,
"enableLiveness": true,
"expireTime": "2099-12-31T23:59:59+08:00"
}
字段解释:
authFilePath存在时优先离线激活。activeKey用于在线激活。threshold建议从0.5起做业务调优。enableLiveness根据业务安全等级控制。
5.2 配置加载决策图
是
否
是
否
是
否
需要初始化 ArcFace
读取本地配置文件
配置合法且未过期?
initArcFace
请求后端配置
成功?
写入缓存/可回写文件
读取 AsyncStorage 缓存
可用?
初始化失败并提示重试
5.3 服务层改造点(在现有代码上无侵入增强)
文件:src/services/arcsoft/index.ts
你只需要在 initArcsoftSdkForRobot 前加一个"本地配置加载器":
ts
type ArcsoftFileConfig = {
appId: string;
sdkKey: string;
activeKey?: string;
authFilePath?: string;
deviceCode?: string;
threshold?: number;
enableLiveness?: boolean;
expireTime?: string;
};
const loadArcsoftConfigFromFile = async (): Promise<ArcsoftFileConfig | null> => {
try {
// 示例:可用 react-native-fs 或 NativeModule 读取 app 私有目录
// const raw = await RNFS.readFile('/data/user/0/<pkg>/files/arcsoft/arcsoft-sdk.local.json');
// return JSON.parse(raw);
return null;
} catch {
return null;
}
};
推荐优先级:
- 本地配置文件
- 后端接口
getRobotEquipmentDetail(robotId, 6) - AsyncStorage 缓存
5.4 原生侧无需大改
因为 ArcFaceConfig.ensureActivated 已经支持:
activeOffline(context, authFilePath)(优先)activeOnline(context, activeKey, appId, sdkKey)(次优)
也就是说,配置来源怎么变,原生激活策略不用推倒重来。
6. 这套方案为什么不枯燥:它能对真实问题给出答案
6.1 典型故障处理图
初始化
实时识别
比对异常
初始化/识别失败
失败阶段
检查配置完整性
检查激活模式与网络/文件
查看 active 结果码
检查相机帧与 onFaceResult
是否拿到 featureBase64
检查 depId 对应特征库
必要时触发重新注册
检查特征长度与阈值
清理旧特征库后重试
6.2 踩坑清单(可直接贴到排障手册)
| 现象 | 常见根因 | 处理建议 |
|---|---|---|
| 一直 loading | 激活卡住或配置为空 | 检查 initArcFace 超时日志与配置解析 |
ARCFACE_ACTIVE_FAILED |
appId/sdkKey/activeKey 错误或过期 |
先用脱敏日志核验配置来源,再核对控制台 |
NO_LIVE_FACE 高频 |
光照差、镜头抖动、活体策略过严 | 调整拍摄引导,必要时分场景开关活体 |
FEATURE_LEN_MISMATCH |
SDK 版本变更导致历史特征不可用 | 清理 face_feature_store,重新注册 |
| 识别率不稳定 | 阈值不合适/注册图质量低 | 从 0.5 起逐步调优,提升注册图质量 |
7. 敏感信息屏蔽规范(发布必做)
7.1 日志只允许脱敏输出
当前项目已有脱敏实现:
- JS:
src/services/arcsoft/index.ts的safeLogConfig - Kotlin:
android/app/src/main/java/com/yog_lanzhou_robot_app/ArcFaceModule.kt的mask
要求:
- 任何环境都不要打印明文
appId/sdkKey/activeKey。 - 错误日志可保留错误码,不保留原始密钥。
7.2 配置文件入库规则
.gitignore 建议加入:
gitignore
config/arcsoft/arcsoft-sdk.local.json
android/app/src/main/assets/arcsoft/arcsoft-sdk.local.json
7.3 文档示例统一占位
统一用:
<ARCSOFT_APP_ID><ARCSOFT_SDK_KEY><ARCSOFT_ACTIVE_KEY><DEVICE_CODE><ROBOT_ID>
8. 给新项目的迁移清单(一步步照做)
- 拷贝 Android 侧 ArcFace 核心类并替换包名。
- 接入
build.gradle、Manifest、Proguard、ArcFacePackage注册。 - 拷贝 RN
nativeModules + service + hook三层封装。 - 把配置源改成"配置文件优先,接口兜底,缓存保底"。
- 在业务页接入
useArcsoftSdk + ArcFaceCameraView + validFaceLocal。 - 完成脱敏日志、
.gitignore、release 前配置检查。
9. 最后的工程建议
如果你计划把这套能力平台化,建议拆成两个可复用模块:
@company/rn-arcface-bridge负责 Native Module、CameraView、TS 类型定义。@company/arcsoft-config-runtime
负责配置文件加载、后端兜底、缓存和脱敏日志。
这样,后续新项目接入时,你只需要关注业务流程,不再重复造桥接轮子。