老版人脸核身兼容升级
适用平台:仅 Android 端。iOS 老版本已在早期文档中要求配置
NSMicrophoneUsageDescription、NSCameraUsageDescription、allowsInlineMediaPlayback,无需额外改造;鸿蒙端此前不存在。
本文档面向继续使用老版 WBH5FaceVerifySDK 的 Android 存量客户,提供两项兼容性改造:
- 慧眼新域名
faceid兼容:电子签人脸核身服务已迁移到慧眼新域名,老 SDK 域名白名单需追加faceid才能识别刷脸页面。 - 核身 + 视频 / 朗读模式音频权限:TRTC 双录模式需同时申请相机与麦克风权限,老 SDK 仅申请相机,导致
getUserMedia卡死。
SDK 源码与兼容包下载:android-h5faceverify-trtc-compatibility-upgrade.zip | SHA256 校验
1. 改造方案概览(二选一)
| 方案 | 说明 | 适用场景 |
|---|---|---|
mini-change | 兼容 faceid 域名 + TRTC 模式固定申请相机+麦克风 | 改动最小,快速上线 |
mini-permission(推荐) | 在 mini-change 基础上:按 H5 请求资源动态映射权限 + 避免 PermissionRequest 泄露 | 权限更精准,H5 端不卡死 |
附件 zip 包内包含两个源码目录:
mini-change-src/对应mini-change方案,mini-permission-src/对应mini-permission(推荐)方案。
mini-permission包含mini-change的全部改动,建议直接采用mini-permission。
2. mini-change:慧眼新域名 faceid 兼容
2.1 人脸核身兼容慧眼新域名 faceid
在 WBH5FaceVerifySDK.isTencentH5FaceVerify 函数中,新增对 faceid 域名的兼容判断。涉及文件:app/src/main/java/com/wb/testcloud/WBH5FaceVerifySDK.java(两个重载方法)。
// 新增条件:|| thirdName.contains("faceid")
if (thirdName.contains("kyc") || thirdName.contains("ida") || thirdName.contains("faceid"))
2.2 核身 + 视频 / 朗读模式:新增音频权限申请
2.2.1 AndroidManifest.xml — 添加麦克风权限声明
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
2.2.2 MainActivity.java — requestCameraPermission 方法整体替换
TRTC 模式同时检查相机和麦克风权限,任意缺失则申请所需权限:
public void requestCameraPermission(boolean trtc, boolean belowApi21) {
this.belowApi21 = belowApi21;
if (trtc) {
// TRTC 模式:同时需要相机和麦克风权限
boolean hasCamera = checkSdkPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
boolean hasAudio = checkSdkPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
if (hasCamera && hasAudio) {
Log.d(TAG, "checkSelfPermission true (trtc)");
webViewClient.enterTrtcFaceVerify();
} else {
Log.d(TAG, "checkSelfPermission false (trtc), hasCamera=" + hasCamera + ", hasAudio=" + hasAudio);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
java.util.ArrayList<String> needPermissions = new java.util.ArrayList<>();
if (!hasCamera) needPermissions.add(Manifest.permission.CAMERA);
if (!hasAudio) needPermissions.add(Manifest.permission.RECORD_AUDIO);
ActivityCompat.requestPermissions(this,
needPermissions.toArray(new String[0]),
PERMISSION_QUEST_TRTC_CAMERA_VERIFY);
} else {
openAppDetail(PERMISSION_QUEST_TRTC_CAMERA_VERIFY);
}
}
} else {
// 录制模式:仅需要相机权限,保持原有逻辑
if (checkSdkPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "checkSelfPermission false");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
PERMISSION_QUEST_OLD_CAMERA_VERIFY);
} else {
openAppDetail(PERMISSION_QUEST_OLD_CAMERA_VERIFY);
}
} else {
Log.d(TAG, "checkSelfPermission true");
webViewClient.enterOldModeFaceVerify(belowApi21);
}
}
}
2.2.3 onRequestPermissionsResult — 替换 PERMISSION_QUEST_TRTC_CAMERA_VERIFY 分支
支持多个权限(相机 + 麦克风)的回调处理:
case PERMISSION_QUEST_TRTC_CAMERA_VERIFY: // TRTC 模式(相机 + 麦克风)
if (grantResults.length > 0) {
boolean allGranted = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break;
}
}
if (allGranted) {
Log.d(TAG, "onRequestPermissionsResult camera+audio all granted");
webViewClient.enterTrtcFaceVerify();
} else {
boolean deniedForever = false;
for (String p : permissions) {
if (checkSdkPermission(p) != PackageManager.PERMISSION_GRANTED
&& !ActivityCompat.shouldShowRequestPermissionRationale(this, p)) {
deniedForever = true;
break;
}
}
if (deniedForever) {
Log.d(TAG, "onRequestPermissionsResult camera/audio denied forever");
openAppDetail(PERMISSION_QUEST_TRTC_CAMERA_VERIFY);
} else {
Log.d(TAG, "onRequestPermissionsResult deny but not forever");
askPermissionError();
}
}
}
break;
3. mini-permission:按需权限申请 + 避免 PermissionRequest 泄露(推荐)
在 mini-change 基础上进一步优化权限申请流程。
3.1 改动概览
| 文件 | 改动 |
|---|---|
H5FaceWebChromeClient.java | onPermissionRequest 按 resources 动态映射权限;所有分支必 grant/deny;新增 denyPermissionRequest();enterTrtcFaceVerify 简化 |
MainActivity.java | 新增 checkPermissionsGranted() / requestFacePermissions();拒绝分支增加 denyPermissionRequest() 调用 |
3.2 H5FaceWebChromeClient.onPermissionRequest — 按需权限申请
H5 端 getUserMedia 请求的资源由 PermissionRequest.getResources() 给出,动态映射系统权限:
PermissionRequest.RESOURCE_VIDEO_CAPTURE→CAMERAPermissionRequest.RESOURCE_AUDIO_CAPTURE→RECORD_AUDIO
关键原则:所有分支必须有 grant() 或 deny() 出口,避免 H5 端 Promise 永远挂起。
@Override
public void onPermissionRequest(PermissionRequest request) {
if (request == null) return;
final PermissionRequest req = request;
String origin = req.getOrigin() != null ? req.getOrigin().toString() : "null";
Log.d(TAG, "onPermissionRequest origin=" + origin);
if (activity == null) {
req.deny();
return;
}
// 按 H5 请求的资源动态映射系统权限
java.util.List<String> needPerms = new java.util.ArrayList<>();
if (req.getResources() != null) {
for (String res : req.getResources()) {
if (PermissionRequest.RESOURCE_VIDEO_CAPTURE.equals(res)) {
needPerms.add(android.Manifest.permission.CAMERA);
} else if (PermissionRequest.RESOURCE_AUDIO_CAPTURE.equals(res)) {
needPerms.add(android.Manifest.permission.RECORD_AUDIO);
}
}
}
if (needPerms.isEmpty()) {
req.deny();
return;
}
if (activity.checkPermissionsGranted(needPerms)) {
// 权限已有,同步 grant
req.grant(req.getResources());
} else {
// 权限缺失,异步申请
this.request = req;
activity.requestFacePermissions(needPerms.toArray(new String[0]));
}
}
优点
- 不硬编码申请相机+麦克风,H5 只请求视频就不申请麦克风。
- 权限已有同步 grant,不覆盖
this.request字段。 - 每个分支都 grant 或 deny,H5 端不会卡死。
3.3 新增 H5FaceWebChromeClient.denyPermissionRequest()
权限被拒绝时主动 deny H5 的 PermissionRequest,确保 getUserMedia Promise 收到 rejection 回调:
public void denyPermissionRequest() {
if (request != null) {
request.deny();
request = null;
}
}
在 MainActivity.onRequestPermissionsResult 的 TRTC 拒绝分支调用:
if (deniedForever) {
webViewClient.denyPermissionRequest(); // 新增
openAppDetail(PERMISSION_QUEST_TRTC_CAMERA_VERIFY);
} else {
webViewClient.denyPermissionRequest(); // 新增
askPermissionError();
}
3.4 H5FaceWebChromeClient.enterTrtcFaceVerify 简化
去掉二次域名判断,直接 grant,grant 后置空 this.request 避免残留:
public void enterTrtcFaceVerify() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
if (request != null) {
request.grant(request.getResources());
this.request = null; // grant 后置空,避免泄露
}
}
}
3.5 MainActivity 新增方法
// 批量检查权限,供 onPermissionRequest 同步判断
public boolean checkPermissionsGranted(java.util.List<String> permissions) {
for (String p : permissions) {
if (checkSdkPermission(p) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
// 异步申请权限
public void requestFacePermissions(String[] permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ActivityCompat.requestPermissions(this, permissions, PERMISSION_QUEST_TRTC_CAMERA_VERIFY);
} else {
openAppDetail(PERMISSION_QUEST_TRTC_CAMERA_VERIFY);
}
}
4. 两种方案差异总结
| 方面 | mini-change | mini-permission |
|---|---|---|
| 权限申请方式 | 硬编码 trtc=true,固定申请相机+麦克风 | 按 H5 resources 动态映射 |
| PermissionRequest 生命周期 | 只赋值,不置空 | grant/deny 后置空,避免泄露 |
| 拒绝时通知 H5 | 不 deny,getUserMedia 卡死 | 主动 deny,H5 收到回调 |
| 权限已有 | 走异步流程,覆盖 this.request | 同步 grant,不覆盖 |
| 域名判断 | onPermissionRequest + enterTrtcFaceVerify 双重检查 | 不做域名白名单,直接处理所有请求 |
5. 升级操作步骤
- 下载附件 android-h5faceverify-trtc-compatibility-upgrade.zip,解压后进入
mini-permission-src/目录(推荐方案)。 - 参考目录内
README.md配置local.properties(sdk.dir指向 Android SDK)。 - 执行
bash setup.sh初始化环境,再执行bash build.sh打包 Debug APK。 - APK 输出路径:
app/build/outputs/apk/debug/app-debug.apk。 - 将 Demo 中
WBH5FaceVerifySDK.java、H5FaceWebChromeClient.java、MainActivity.java的改动合并到您的工程对应文件;AndroidManifest.xml追加RECORD_AUDIO/MODIFY_AUDIO_SETTINGS权限。 - 联调验证:卸载原先应用后重新安装改造后的 APK,在联调环境使用电子签签署链接对人脸流程进行回归,确认刷脸页面正常识别、TRTC 双录权限正常申请、业务涉及的人脸流程完整通过。
- 应用上线:验证无问题后,将改造后的应用发布上线。
- 通知线上策略调整:应用上线后,通知腾讯电子签对接人员,调整对应企业的线上环境人脸策略,完成升级。
6. 权限说明
应用需要以下运行时权限(TRTC 模式同时需要相机 + 麦克风):
| 权限 | 用途 |
|---|---|
CAMERA | 人脸核身拍照/录像 |
RECORD_AUDIO | TRTC 实时音视频模式录音 |
MODIFY_AUDIO_SETTINGS | TRTC 模式音频路由切换及音频参数调节(录音/朗读场景) |
INTERNET | H5 页面加载 |
ACCESS_NETWORK_STATE | 网络状态检测 |
- Android 6.0+ (API 23+):通过
ActivityCompat.requestPermissions动态弹窗申请。 - Android 5.x (API 21-22):安装时授予,若未授予则引导用户跳转系统设置页手动开启。
7. 两种刷脸模式
| 模式 | 说明 | 权限 | 系统要求 |
|---|---|---|---|
| 录制模式 (OLD) | 调用系统相机录制视频 | 仅相机 | Android 5.0+ (API 21) |
| TRTC 模式 (NEW) | 实时音视频人脸核身 | 相机 + 麦克风 | Android 7.0+ (API 24) |
注意:
- 系统兼容性:电子签页面与人脸核身 TRTC 仅兼容 Android 7.0+ (API 24) 的系统。
- 回退机制说明:录制模式 (OLD) 仅在 APP 未进行相应的兼容性配置(如缺少摄像头权限或配置有误)时才会作为备用回退方案。请确保按本文档完成配置,从而稳定使用 TRTC 模式。
模式由 H5 页面通过 WebChromeClient 的 onPermissionRequest 回调触发,Demo 根据域名判断是否为腾讯 H5 刷脸页面后发起对应权限申请。
8. 环境要求
| 依赖 | 版本 |
|---|---|
| JDK | 1.8 |
| Android Gradle Plugin | 3.2.0 |
| compileSdkVersion / targetSdkVersion | 27 |
| minSdkVersion | 24(电子签与人脸核身 TRTC 模式,需 Android 7.0+) |
| Build Tools | 27.0.3 |
| Android Support Library | 27.0.1 |
本项目依赖 Java 8 编译,请确保本地已安装 JDK 8。使用阿里云 Maven 镜像加速依赖下载,无需科学上网。
9. 演示截图
以下为老 SDK 改造后的实际签署 + 刷脸效果。普通核身只有一次录制;核身+视频/朗读,才有两次录制。

10. 新一代 SDK 参考
本兼容升级方案面向继续使用老版 WBH5FaceVerifySDK 的存量客户,可保障当前线上业务持续可用。
若您未来考虑升级到腾讯电子签官方提供的新一代 WebView 容器 SDK(TencentQianWebView),可参考以下对比:
| 维度 | 老 SDK(WBH5FaceVerifySDK) | 新 SDK(TencentQianWebView) |
|---|---|---|
| 平台 | 仅 Android | Android / iOS / HarmonyOS 三端 |
| 集成成本 | 需自行维护 WebView 兼容性 | 最少 10 行代码,SDK 封装全部兼容细节 |
| 维护 | patch 方式增量改造,后续需持续跟进 | 官方持续维护,版本迭代 |
| 能力 | 人脸核身权限适配 | 人脸核身 + 文件选择器 + Scheme 拦截 + 下载 + qianapp:// 协议 + Cookie 持久化等全链路 |
| 鸿蒙 | 不支持 | 支持 HarmonyOS NEXT |
两种集成模式:
- 容器模式:全新页面,1 行代码打开签署 H5,自带顶栏 / 进度条 / 关闭确认 UI。
- 配置模式:保留您自有 WebView 与 UI,只叠加 SDK 兼容性能力。
详细指引请参阅 跳转电子签H5 -> App集成电子签H5兼容性适配。
评估建议
- 短期:先完成本文档的兼容升级,保障线上人脸核身可用。
- 中期:在新功能迭代或新增 iOS / 鸿蒙支持时,评估迁移到新 SDK,降低长期 WebView 兼容性维护成本。