根据提示做出相应动作,SDK 实时采集动态信息,判断用户是否为活体、真人 ## 兼容性 条目 | 说明 适配版本 | HarmonyOS 12 及以上版本 ## 资源引入 ### 远程仓库依赖(推荐) 活体检测共享包 HAR 发布在 OpenHarmony 三方库中心仓,需要从 OpenHarmony 三方库中心仓引用 方式一 在 Terminal 窗口中,执行如下命令安装三方包,DevEco Studio 会自动在工程的 oh-package.json5 中自动添加三方包依赖 Code: ohpm install @yidun/alive 方式二 在工程的 oh-package.json5 中设置三方包依赖 Code: "dependencies": { "@yidun/alive": "^1.0.3" } ## 各种配置 ### 权限配置 共享包依赖相机和文件存储权限,请在 module.json5 中配置 Code ( ): "requestPermissions": [ { "name": "ohos.permission.CAMERA", "reason": "$string:reason", "usedScene": { "abilities": [ "EntryAbility" ], "when": "always" } }, { "name": "ohos.permission.WRITE_MEDIA", "reason": "$string:reason", "usedScene": { "abilities": [ "EntryAbility" ], "when": "always" } }, { "name": "ohos.permission.READ_MEDIA", "reason": "$string:reason", "usedScene": { "abilities": [ "EntryAbility" ], "when": "always" } } ], 并且需要在代码中动态授权,具体可参考官方文档 https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/request-user-authorization-V5 (https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/request-user-authorization-V5) ## 快速调用示例 ### NisCameraPreview 是活体检测自定义组件,需要将它嵌入页面中 #### 注意点 - 为了避免在某些中低端机型上检测卡顿,建议 NisCameraPreview 的宽与高不要设置为全屏,过大的预览控件会导致处理的数据过大,降低检测流畅度 - 预览宽高不要随意设置,请遵守大部分相机支持的预览宽高比,3:4 或 9:16 - 最好限制竖屏,横屏会影响效果 #### 示例 Code: import common from '@ohos.app.ability.common' import { ActionType, AliveDetect, Logger, NisCameraPreview } from '@yidun/alive' @Component export default struct Test { private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext @State currentTip: string = "请正视前方" @State pic: string = "app.media.pic_front_2x" private logger: Logger = new Logger("AliveDetectDemo") initAlive() { AliveDetect.getInstance().init(this.context, "844f553a25034a3ab5f38fcd386305d2") AliveDetect.getInstance().setDetectedListener({ onReady: (isInitSuccess: boolean) => { if (isInitSuccess) { this.logger.debug("引擎初始化成功") } }, onActionCommands: (_: ActionType[] | null): void => { this.logger.debug("获取配置成功") }, onStateTipChanged: (actionType: ActionType, stateTip: string, _: number): void => { switch (actionType) { case ActionType.ACTION_ERROR: // 更新错误提示语 this.currentTip = stateTip break; case ActionType.ACTION_TURN_HEAD_TO_LEFT: this.currentTip = stateTip this.pic = "app.media.turn_left" // 左转头 break; case ActionType.ACTION_TURN_HEAD_TO_RIGHT: this.currentTip = stateTip this.pic = "app.media.turn_right" // 右转头 break; case ActionType.ACTION_OPEN_MOUTH: this.currentTip = stateTip this.pic = "app.media.open_mouth" // 张张嘴 break; case ActionType.ACTION_BLINK_EYES: this.currentTip = stateTip this.pic = "app.media.open_eyes" // 眨眨眼 break; } }, onPassed: (isPassed: boolean, token: string): void => { AlertDialog.show({ title: '活体检测', message: `活体检测结果${isPassed} Token is:${token}` }) }, onCheck: (): void => { }, onError: (_: number, msg: string): void => { // 检测异常 this.logger.error(msg) }, onOverTime: (): void => { // 检测超时 AlertDialog.show({ title: '活体检测', message: '检测超时了' }) } }) AliveDetect.getInstance().startDetect() } onPageShow(): void { this.initAlive() } build() { RelativeContainer() { NisCameraPreview({ previewWidth: 1080, previewHeight: 1440 }) .alignRules({ top: { anchor: "statusBar", align: VerticalAlign.Bottom }, middle: { anchor: "__container__", align: HorizontalAlign.Center } }) Image($r('app.media.alive_bg')) .alt('背景图') .width('100%') .height('100%') .objectFit(ImageFit.Contain) .alignRules({ left: { anchor: '__container__', align: HorizontalAlign.Start }, top: { anchor: '__container__', align: VerticalAlign.Top } }) Image($r(this.pic)) .alt('动作提示图') .width('140vp') .height('140vp') .interpolation(ImageInterpolation.Medium) .objectFit(ImageFit.Contain) .margin({ bottom: '50vp' }) .alignRules({ bottom: { anchor: '__container__', align: VerticalAlign.Bottom }, left: { anchor: '__container__', align: HorizontalAlign.Start }, right: { anchor: '__container__', align: HorizontalAlign.End } }) .onComplete(() => { this.logger.info("动作提示图加载完成") }) .id('action') Text(this.currentTip) .fontSize('18fp') .fontColor('#ff000000') .textAlign(TextAlign.Center) .fontWeight(600) .margin({ bottom: '16vp' }) .alignRules({ bottom: { anchor: 'action', align: VerticalAlign.Top }, left: { anchor: '__container__', align: HorizontalAlign.Start }, right: { anchor: '__container__', align: HorizontalAlign.End } }) } .height('100%') .width('100%') } } ## 共享包方法说明 首先需要在页面中嵌入 NisCameraPreview 组件,NisCameraPreview 的 id 是 NTSCamera,可以根据需要设置它的位置 Code: build() { RelativeContainer() { NisCameraPreview({ previewWidth: 1080, previewHeight: 1440 }) .alignRules({ top: { anchor: "statusBar", align: VerticalAlign.Bottom }, middle: { anchor: "__container__", align: HorizontalAlign.Center } }) } } ### 1.活体检测初始化 #### 代码说明 Code: AliveDetect.getInstance().init(this.context, "844f553a25034a3ab5f38fcd386305d2") #### 参数说明 参数 | 类型 | 是否必填 | 默认值 | 描述 context | common.UIAbilityContext | 是 | 无 | 上下文 businessId | String | 是 | 无 | 活体检测业务 id ### 2. 设置回调监听 #### 代码说明 代码添加在 init 之后 startDetect 之前调用 Code: AliveDetect.getInstance().setDetectedListener(listener: DetectedListener) #### 参数说明 参数 | 类型 | 是否必填 | 默认值 | 描述 listener | DetectedListener | 是 | 无 | 监听接口 #### DetectedListener 接口说明 Code: interface DetectedListener { /** * 活体检测引擎初始化时回调 * * @param isInitSuccess 活体检测引擎是否初始化成功: * 1)true,初始化完成可以开始检测 * 2)false,初始化失败,可尝试重新启动活体检测流程 {@link AliveDetector#startDetect()} */ onReady: (isInitSuccess: boolean) => void; /** * 此次活体检测下发的待检测动作指令序列,{@link ActionType} * * @param actionTypes */ onActionCommands: (actionTypes: ActionType[] | null) => void; /** * 活体检测状态是否改变,当引擎检测到状态改变时会回调该接口 * * @param actionType 当前动作类型,枚举值,总共6种类型: * ACTION_STRAIGHT_AHEAD("0", "正视前方"), * ACTION_TURN_HEAD_TO_RIGHT("1", "向右转头"), * ACTION_TURN_HEAD_TO_LEFT("2", "向左转头"), * ACTION_OPEN_MOUTH("3", "张嘴动作"), * ACTION_BLINK_EYES("4", "眨眼动作"), * ACTION_ERROR("5", "动作错误"), * ACTION_PASSED("6", "动作通过") * * @param stateTip 引擎检测到的实时状态 * @param code 错误码,在ACTION_ERROR时用于国际化使用(1:请移动人脸到摄像头视野中间、2:环境光线暗、3:环境光线过亮、4:图像质量模糊) */ onStateTipChanged: (actionType: ActionType, stateTip: string, code: number) => void; /** * 活体检测是否通过回调 * * @param isPassed 活体检测是否通过,true:通过,false:不通过 * @param token 此次活体检测返回的易盾token */ onPassed: (isPassed: boolean, token: string) => void; /** * 活体检测本地检测通过 * 启动远程检测 */ onCheck: () => void /** * 活体检测过程中出现错误时回调 * * @param code 错误码 * -1001:获取配置失败 -1002:打开相机失败 -1003:上传图片失败 -1004:云端检测失败 * @param msg 出错原因 */ onError: (code: number, msg: string) => void; /** * 活体检测过程超时回调 */ onOverTime: () => void } ### 3. 开始活体检测 代码添加在 init 之后调用 #### 代码说明 Code: AliveDetect.getInstance().startDetect() ### 4. 停止活体检测 #### 代码说明 Code: AliveDetect.getInstance().stopDetect()