活体检测
2025.04.09 10:38:50
根据提示做出相应动作,SDK 实时采集动态信息,判断用户是否为活体、真人
兼容性
条目 | 说明 |
---|---|
适配版本 | HarmonyOS 12 及以上版本 |
资源引入
远程仓库依赖(推荐)
活体检测共享包 HAR 发布在 OpenHarmony 三方库中心仓,需要从 OpenHarmony 三方库中心仓引用
方式一 在 Terminal 窗口中,执行如下命令安装三方包,DevEco Studio 会自动在工程的 oh-package.json5 中自动添加三方包依赖
ohpm install @yidun/alive
方式二 在工程的 oh-package.json5 中设置三方包依赖
"dependencies": {
"@yidun/alive": "^1.0.3"
}
各种配置
权限配置
共享包依赖相机和文件存储权限,请在 module.json5 中配置
"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
快速调用示例
NisCameraPreview 是活体检测自定义组件,需要将它嵌入页面中
注意点
- 为了避免在某些中低端机型上检测卡顿,建议 NisCameraPreview 的宽与高不要设置为全屏,过大的预览控件会导致处理的数据过大,降低检测流畅度
- 预览宽高不要随意设置,请遵守大部分相机支持的预览宽高比,3:4 或 9:16
- 最好限制竖屏,横屏会影响效果
示例
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,可以根据需要设置它的位置
build() {
RelativeContainer() {
NisCameraPreview({ previewWidth: 1080, previewHeight: 1440 })
.alignRules({
top: { anchor: "statusBar", align: VerticalAlign.Bottom },
middle: { anchor: "__container__", align: HorizontalAlign.Center }
})
}
}
1.活体检测初始化
代码说明
AliveDetect.getInstance().init(this.context, "844f553a25034a3ab5f38fcd386305d2")
参数说明
参数 | 类型 | 是否必填 | 默认值 | 描述 |
---|---|---|---|---|
context | common.UIAbilityContext | 是 | 无 | 上下文 |
businessId | String | 是 | 无 | 活体检测业务 id |
2. 设置回调监听
代码说明
代码添加在 init 之后 startDetect 之前调用
AliveDetect.getInstance().setDetectedListener(listener: DetectedListener)
参数说明
参数 | 类型 | 是否必填 | 默认值 | 描述 |
---|---|---|---|---|
listener | DetectedListener | 是 | 无 | 监听接口 |
DetectedListener 接口说明
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 之后调用
代码说明
AliveDetect.getInstance().startDetect()
4. 停止活体检测
代码说明
AliveDetect.getInstance().stopDetect()