跳到主要内容

老版人脸核身兼容升级

适用平台:仅 Android 端。iOS 老版本已在早期文档中要求配置 NSMicrophoneUsageDescriptionNSCameraUsageDescriptionallowsInlineMediaPlayback,无需额外改造;鸿蒙端此前不存在。

本文档面向继续使用老版 WBH5FaceVerifySDK 的 Android 存量客户,提供两项兼容性改造:

  1. 慧眼新域名 faceid 兼容:电子签人脸核身服务已迁移到慧眼新域名,老 SDK 域名白名单需追加 faceid 才能识别刷脸页面。
  2. 核身 + 视频 / 朗读模式音频权限:TRTC 双录模式需同时申请相机与麦克风权限,老 SDK 仅申请相机,导致 getUserMedia 卡死。

SDK 源码与兼容包下载android-h5faceverify-trtc-compatibility-upgrade.zipSHA256 校验


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.javaonPermissionRequest 按 resources 动态映射权限;所有分支必 grant/deny;新增 denyPermissionRequest()enterTrtcFaceVerify 简化
MainActivity.java新增 checkPermissionsGranted() / requestFacePermissions();拒绝分支增加 denyPermissionRequest() 调用

3.2 H5FaceWebChromeClient.onPermissionRequest — 按需权限申请

H5 端 getUserMedia 请求的资源由 PermissionRequest.getResources() 给出,动态映射系统权限:

  • PermissionRequest.RESOURCE_VIDEO_CAPTURECAMERA
  • PermissionRequest.RESOURCE_AUDIO_CAPTURERECORD_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-changemini-permission
权限申请方式硬编码 trtc=true,固定申请相机+麦克风按 H5 resources 动态映射
PermissionRequest 生命周期只赋值,不置空grant/deny 后置空,避免泄露
拒绝时通知 H5不 deny,getUserMedia 卡死主动 deny,H5 收到回调
权限已有走异步流程,覆盖 this.request同步 grant,不覆盖
域名判断onPermissionRequest + enterTrtcFaceVerify 双重检查不做域名白名单,直接处理所有请求

5. 升级操作步骤

  1. 下载附件 android-h5faceverify-trtc-compatibility-upgrade.zip,解压后进入 mini-permission-src/ 目录(推荐方案)。
  2. 参考目录内 README.md 配置 local.propertiessdk.dir 指向 Android SDK)。
  3. 执行 bash setup.sh 初始化环境,再执行 bash build.sh 打包 Debug APK。
  4. APK 输出路径:app/build/outputs/apk/debug/app-debug.apk
  5. 将 Demo 中 WBH5FaceVerifySDK.javaH5FaceWebChromeClient.javaMainActivity.java 的改动合并到您的工程对应文件;AndroidManifest.xml 追加 RECORD_AUDIO / MODIFY_AUDIO_SETTINGS 权限。
  6. 联调验证:卸载原先应用后重新安装改造后的 APK,在联调环境使用电子签签署链接对人脸流程进行回归,确认刷脸页面正常识别、TRTC 双录权限正常申请、业务涉及的人脸流程完整通过。
  7. 应用上线:验证无问题后,将改造后的应用发布上线。
  8. 通知线上策略调整:应用上线后,通知腾讯电子签对接人员,调整对应企业的线上环境人脸策略,完成升级。

6. 权限说明

应用需要以下运行时权限(TRTC 模式同时需要相机 + 麦克风):

权限用途
CAMERA人脸核身拍照/录像
RECORD_AUDIOTRTC 实时音视频模式录音
MODIFY_AUDIO_SETTINGSTRTC 模式音频路由切换及音频参数调节(录音/朗读场景)
INTERNETH5 页面加载
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)

注意

  1. 系统兼容性:电子签页面与人脸核身 TRTC 仅兼容 Android 7.0+ (API 24) 的系统。
  2. 回退机制说明:录制模式 (OLD) 仅在 APP 未进行相应的兼容性配置(如缺少摄像头权限或配置有误)时才会作为备用回退方案。请确保按本文档完成配置,从而稳定使用 TRTC 模式。

模式由 H5 页面通过 WebChromeClient 的 onPermissionRequest 回调触发,Demo 根据域名判断是否为腾讯 H5 刷脸页面后发起对应权限申请。


8. 环境要求

依赖版本
JDK1.8
Android Gradle Plugin3.2.0
compileSdkVersion / targetSdkVersion27
minSdkVersion24(电子签与人脸核身 TRTC 模式,需 Android 7.0+)
Build Tools27.0.3
Android Support Library27.0.1

本项目依赖 Java 8 编译,请确保本地已安装 JDK 8。使用阿里云 Maven 镜像加速依赖下载,无需科学上网。


9. 演示截图

以下为老 SDK 改造后的实际签署 + 刷脸效果。普通核身只有一次录制;核身+视频/朗读,才有两次录制。

人脸验证流程


10. 新一代 SDK 参考

本兼容升级方案面向继续使用老版 WBH5FaceVerifySDK 的存量客户,可保障当前线上业务持续可用。

若您未来考虑升级到腾讯电子签官方提供的新一代 WebView 容器 SDK(TencentQianWebView),可参考以下对比:

维度老 SDK(WBH5FaceVerifySDK)新 SDK(TencentQianWebView)
平台仅 AndroidAndroid / iOS / HarmonyOS 三端
集成成本需自行维护 WebView 兼容性最少 10 行代码,SDK 封装全部兼容细节
维护patch 方式增量改造,后续需持续跟进官方持续维护,版本迭代
能力人脸核身权限适配人脸核身 + 文件选择器 + Scheme 拦截 + 下载 + qianapp:// 协议 + Cookie 持久化等全链路
鸿蒙不支持支持 HarmonyOS NEXT

两种集成模式:

  • 容器模式:全新页面,1 行代码打开签署 H5,自带顶栏 / 进度条 / 关闭确认 UI。
  • 配置模式:保留您自有 WebView 与 UI,只叠加 SDK 兼容性能力。

详细指引请参阅 跳转电子签H5 -> App集成电子签H5兼容性适配

评估建议

  • 短期:先完成本文档的兼容升级,保障线上人脸核身可用。
  • 中期:在新功能迭代或新增 iOS / 鸿蒙支持时,评估迁移到新 SDK,降低长期 WebView 兼容性维护成本。