更新记录

1.0.5(2026-07-08)

问题修复

  • 修复 Android 自动录像编译失败:ImaLivenessAnalysisVideoRecorder.ktsynchronized(muxerLock) {} lambda 内直接 break,Kotlin 编译报 'break' or 'continue' jumps across a function or a class boundary;改为锁内返回 shouldBreak 状态,锁外再跳出编码输出循环
  • 同步处理视频轨 / 音频轨 INFO_OUTPUT_FORMAT_CHANGED 分支,避免云打包 / 自定义基座在自动录像相关代码处中断

1.0.4(2026-06-17)

问题修复

  • 修复云打包 / 自定义基座编译失败:index.vuereadRawValueany 使用 plain[key] 动态属性访问,UTS 编译为 Kotlin 时误解析为 String.get,报 index.kt:118 Unresolved reference;改为 JSON.stringify / JSON.parse 转为 UTSJSONObject 后再 .get(key),plain Object 仍可正常解析

1.0.3(2026-06-16)

新增功能

  • 新增属性 actionThresholds(Object):可配置 Native 动作检测阈值(眨眼、张嘴、微笑、摇头/点头、回正等 14 项可选字段);未传或传 {} 时使用 Native 默认值
  • 新增类型 ActionThresholdsutssdk/interface.uts
  • Native 新增 ImaLivenessActionThresholdApplierImaLivenessManager.applyActionThresholds();组件 applyFaceConfig / watch 自动下发
  • 宿主示例:pages/camera/livenessThresholdTune.nvuepagesx/camera/livenessThresholdTune.uvue(步进器调参 + 预设 + remount 重测)
  • readme.md 补充 actionThresholds 字段说明、requiredFrames 与各动作关系及灵敏度调参方向(↑/↓)

问题修复

  • 修复 nvue 下 actionThresholds 普通 Object 桥接至 Kotlin 失败、被静默当作 {} 重置为默认值的问题:index.vue 规范化为 UTSJSONObject 后再调用 Native;解析失败时打 log 且不再误 reset
  • 修复快速眨眼难识别:活体眨眼边沿 + 帧间骤降 + 放宽闭眼阈值;blink 固定 requiredFrames=1;分析帧改为保留最新帧队列,ML Kit 使用 PERFORMANCE_MODE_FAST
  • 修复左转头回正后误触发右转:定向摇头增量 Yaw、baseline 仅在回正时锁定,ensureHeadYawReady 加强
  • 修复 head_shake 只摇一侧即通过:双向摇头三阶段(回正 → 左+右 → 再回正),左/右各需 requiredFrames
  • 修复 nvue 示例「重新开始」调用 $refs.startDetection() 无效:改为 v-if + :key remount(与拍照示例一致)

功能优化

  • 定向摇头 head_shake_left / head_shake_right:须「转 → 回正 → 通过」三阶段状态机(DirectionalHeadShakePhase
  • pages/camera/livenessOnly.nvuepagesx/camera/livenessOnly.uvue:动作序列与 remount 重新开始对齐;首页增加阈值调参入口
  • 调参示例页增加快捷动作(仅眨眼/仅张嘴/仅摇头)、拉大预设差异、展示下发摘要;debug=true 时 logcat 输出已应用阈值
  • Native 阈值变更需重编自定义基座后生效
查看更多

平台兼容性

uni-app(4.87)

Vue2 Vue2插件版本 Vue3 Vue3插件版本 Chrome Safari app-vue app-vue插件版本 app-nvue app-nvue插件版本 Android Android插件版本 iOS 鸿蒙 鸿蒙插件版本
1.0.0 1.0.0 × × 1.0.0 1.0.0 5.0 1.0.0 × 5.0以下(不包括5.0) 1.0.0
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × × × × × × × ×

uni-app x(4.87)

Chrome Safari Android Android插件版本 iOS 鸿蒙 鸿蒙插件版本 微信小程序
× × 5.0 1.0.0 × 5.0以下(不包括5.0) 1.0.0 ×

其他

多语言 暗黑模式 宽屏模式
× ×

离线人脸活体检测,全程离线,无需联网,可自定义页面(ima-liveness)

离线人脸活体检测(ima-liveness) 原生组件,支持 动作活体炫彩活体混合活体,可选 检测过程自动录像预览圆角屏幕最大亮度 等能力。全程离线,无需联网。

⚠️注意️

  • 本插件为 UTS 原生组件,支持 uni-app(nvue)uni-app x(uvue)Android 端需制作自定义基座 后真机调试
  • ⚠️注意️:只能在 .nvue.uvue 页面中使用,不支持 .vue
  • 组件标签为 <ima-liveness>
  • 本插件实现的是 活体检测(Liveness),不是人脸识别、人脸比对、人脸搜索
  • ios端 暂未实现(保留模板)
  • harmony端 兼容式组件不支持
  • 宿主示例页:pages/camera/(uni-app + nvue)、pagesx/camera/(uni-app x + uvue);入口分别为 App.vue/main.jsApp.uvue/main.uts

支持功能

  • open:打开摄像头预览
  • close:关闭摄像头预览
  • reset:重置活体检测状态
  • isOpened:查询摄像头预览是否已打开
  • startDetection:手动开始活体检测(可传入动作列表)
  • restartDetection:停止后重新开始检测
  • 动作活体:眨眼、张嘴、微笑、点头、摇头等(见下方动作列表)
  • 炫彩活体:屏幕白/红/绿/蓝阶段采样,防照片/屏幕攻击
  • 混合活体livenessMode="hybrid",先炫彩后动作(原生协调器顺序)
  • 自动录像autoRecordVideo,采用分析帧录制(Preview + Analysis),避免绑定 VideoCapture 导致预览变暗
  • 正脸拍照returnPhoto + pictureTakenStagebefore / during / after),分析帧 JPEG,拍照前校验正脸
  • 预览圆角previewCornerRadius / previewCornerRadiusRate,支持圆形预览
  • 炫彩展示previewColorFlash="true" 在预览框内 overlay;false 时由页面整页变色
  • 自动最大亮度autoMaxScreenBrightness,检测期间窗口亮度调至最大并保持常亮

活体模式(livenessMode)

说明
action 仅动作活体(默认)
color 仅炫彩活体
hybrid 炫彩通过后继续动作活体

支持的动作(actions)

说明
blink 眨眼
mouth_open 张嘴
smile 微笑
head_nod 点头
head_shake 左右摇头(须先回正 → 左+右均摇 → 再回正后通过)
head_shake_left 向左摇头(须先回正 → 左转 → 再回正后通过)
head_shake_right 向右摇头(须先回正 → 右转 → 再回正后通过)

自定义调整

  • 自定义调整页面地址:uni_modules/ima-liveness/utssdk/app-android/index.vue
  • 炫彩阈值、AWB、采样逻辑等可在 utssdk/app-android/ 下 Kotlin 源文件中调整(修改后需重编自定义基座)
  • 类型定义:uni_modules/ima-liveness/utssdk/interface.uts

需要权限

  • 摄像头(必须)
  • 麦克风(autoRecordVideo + recordAudio 时)
  • 存储 / 相册(saveVideoToGallery 时)
"android.permission.CAMERA"
"android.permission.RECORD_AUDIO"
"android.permission.READ_MEDIA_VIDEO"
"android.permission.READ_EXTERNAL_STORAGE"
"android.permission.WRITE_EXTERNAL_STORAGE"
  • 插件已在 AndroidManifest.xml 中声明上述权限;宿主 manifest.jsondistribute.android.permissions 需同步配置
// 活体检测必须
<uses-permission android:name="android.permission.CAMERA" />
// 自动录像且含音频时需要
<uses-permission android:name="android.permission.RECORD_AUDIO" />
// 保存录像到相册时需要
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

使用示例【此示例仅实现基础动作活体,更多示例请导入宿主工程】

  • 新建一个 liveness.nvue 文件
  • ⚠️注意️:只能在 .nvue.uvue 的文件后缀下才生效,不支持 .vue
<template>
  <view class="page">
    <text class="title">请将正脸置于框内</text>
    <text class="tip">{{ actionTip }}</text>

    <view class="camera-wrap">
      <ima-liveness
        ref="livenessRef"
        class="camera-view"
        facing="front"
        :enabled="true"
        :actions="livenessActions"
        :requiredFrames="5"
        :autoStart="true"
        :previewCornerRadiusRate="0.5"
        @onCameraOpened="onCameraOpened"
        @onActionChange="onActionChange"
        @onLivenessPass="onLivenessPass"
        @onFaceError="onFaceError"
      />
    </view>

    <text class="status">{{ statusText }}</text>
  </view>
</template>

<script>
export default {
  data() {
    return {
      livenessActions: ['blink', 'mouth_open'],
      actionTip: '请保持正脸',
      statusText: '准备开始检测',
    }
  },
  methods: {
    onCameraOpened() {
      this.statusText = '相机已打开,请完成活体动作'
    },
    onActionChange(e) {
      const detail = e.detail || {}
      this.actionTip = detail.tip || '请完成动作'
      this.statusText = '动作 ' + ((detail.index || 0) + 1) + '/' + (detail.total || 0)
    },
    onLivenessPass(e) {
      console.log('活体通过', e.detail)
      this.statusText = '活体检测通过'
      uni.showToast({ title: '验证通过', icon: 'success' })
      // 可将结果回传上一页
      const pages = getCurrentPages()
      if (pages.length >= 2) {
        const prev = pages[pages.length - 2]
        if (prev.$vm && prev.$vm.onLivenessResult) {
          prev.$vm.onLivenessResult({ passed: true, ...(e.detail || {}) })
        }
      }
      uni.navigateBack()
    },
    onFaceError(e) {
      console.warn('检测错误', e.detail)
    },
  },
}
</script>

<style>
.page {
  flex: 1;
  align-items: center;
  padding: 40rpx;
}
.title {
  font-size: 32rpx;
  font-weight: 600;
}
.tip {
  margin-top: 24rpx;
  color: #1677ff;
}
.camera-wrap {
  margin-top: 40rpx;
  width: 620rpx;
  height: 620rpx;
}
.camera-view {
  width: 500rpx;
  height: 500rpx;
}
.status {
  margin-top: 40rpx;
  font-size: 28rpx;
}
</style>

炫彩活体示例(片段)

<ima-liveness
  facing="front"
  livenessMode="color"
  :colorPhaseDuration="600"
  :previewColorFlash="false"
  :actions="['blink']"
  :autoStart="true"
  @onColorPhaseChange="onColorPhaseChange"
  @onColorLivenessPass="onColorLivenessPass"
  @onColorLivenessFail="onColorLivenessFail"
  @onLivenessPass="onLivenessPass"
/>

自动录像示例(片段)

<ima-liveness
  facing="front"
  :actions="['blink', 'mouth_open']"
  :autoRecordVideo="true"
  :recordAudio="true"
  :saveVideoToGallery="true"
  @onVideoRecordStart="onVideoRecordStart"
  @onVideoRecordEnd="onVideoRecordEnd"
  @onVideoRecordError="onVideoRecordError"
  @onLivenessPass="onLivenessPass"
/>

正脸拍照示例(片段)

<ima-liveness
  facing="front"
  :actions="['blink', 'mouth_open']"
  :returnPhoto="true"
  pictureTakenStage="after"
  :photoQuality="90"
  @onPictureTaken="onPictureTaken"
  @onPictureTakenError="onPictureTakenError"
  @onPictureTakenReady="onPictureTakenReady"
  @onLivenessPass="onLivenessPass"
/>
onPictureTaken(e) {
  this.photoPath = e.detail?.path || ''
  this.photoStage = e.detail?.stage || ''
}

pictureTakenStage 取值:

说明
before 虚拟序列 [Photo] → actions,拍完自动进入动作
during 随机 N∈[1, actions.length−1],完成前 N 个动作后插入拍照步
after 虚拟序列 actions → Photo,含拍照完成后才 onLivenessPass

Api

属性 类型 默认值 说明 平台
facing String "front" 摄像头:front(前置)、back(后置) android
previewCornerRadius Number 0 预览圆角半径(像素) android
previewCornerRadiusRate Number 0.5 预览圆角比例(0~1),0.5 为圆形 android
enabled Boolean true 是否启用检测 android
actions Array [] 动作列表,空则使用内置默认序列 android
requiredFrames Number 5 单动作判定所需连续帧数(见下方说明) android
actionThresholds Object {} 动作检测阈值,字段均为可选;传 {} 时使用 Native 默认值 android
autoStart Boolean true 相机打开后是否自动开始检测 android
debug Boolean false 调试模式 android
autoRecordVideo Boolean false 检测过程是否自动录像 android
recordAudio Boolean true 录像是否包含麦克风(需 autoRecordVideo android
saveVideoToGallery Boolean false 录像是否保存到系统相册 android
livenessMode String "action" 活体模式:action / color / hybrid android
colorPhaseDuration Number 450 炫彩单阶段时长(ms) android
colorRandomOrder Boolean false 炫彩颜色顺序是否随机(白基准固定最前) android
previewColorFlash Boolean false 是否在预览框内显示炫彩 overlay android
autoMaxScreenBrightness Boolean false 检测期间是否自动将屏幕亮度调至最大 android
returnPhoto Boolean false 是否返回正脸照片 android
pictureTakenStage String "after" 拍照阶段:before / during / after android
savePhotoToGallery Boolean false 照片是否保存到系统相册 android
photoQuality Number 90 JPEG 质量(60~100) android

requiredFrames 与各动作关系

动作 实际判定帧数
blink 固定 1(与 prop 无关)
smile max(requiredFrames + 3, 8)
head_shake_left / head_shake_right 转头阶段:requiredFrames;回正阶段:headYawCenterFramesRequired(默认 3,可通过 actionThresholds 配置)
head_shake 左、右各需 requiredFrames;回正同上
其他(mouth_openhead_nod 等) requiredFrames

actionThresholds 字段

调参提示:「灵敏度」列中 [最小, 最大] 为推荐调参范围(非 Native 强制限制); 数值越大越灵敏; 数值越小越灵敏。未列出的字段保持 Native 默认即可。

宿主传入普通 Object 即可(nvue / vue);组件内部会通过 buildActionThresholdsJson 规范化为 UTSJSONObject 再下发 Native。设置 debug=true 时,可在 logcat 过滤 ImaLivenessManager 查看 Applied actionThresholds 日志确认已生效。

字段 类型 默认 说明 灵敏度
eyeCloseThreshold Number 0.42 活体眨眼闭眼判定(睁眼概率低于此值视为闭眼) [0, 1] · ↑ 越大越易判闭眼,眨眼越灵敏
eyeOpenThreshold Number 0.52 睁眼边沿检测(概率高于此值视为睁眼,用于 open→closed 边沿) [0, 1] · ↓ 越小越易判睁眼,利于捕捉快速眨眼
eyeCloseStrictThreshold Number 0.30 拍照/正脸严格闭眼(低于此值视为闭眼,影响正脸抓拍) [0, 1] · ↑ 越大越易判闭眼,正脸拍照越严格
marThreshold Number 0.35 张嘴 MAR(嘴部纵横比高于此值视为张嘴) [0.1, 0.8] · ↓ 越小越易判张嘴
smileThreshold Number 0.62 微笑概率(ML Kit 微笑概率需达到此值) [0, 1] · ↓ 越小越易判微笑
smileCurveThreshold Number 0.10 嘴角上扬( landmark 嘴角曲线阈值) [0.05, 0.3] · ↓ 越小对嘴角上扬要求越低
smileMaxMarRatio Number 0.92 微笑时 MAR 上限比(相对 marThreshold,超过则不算微笑) [0.5, 1.2] · ↑ 越大允许嘴张得稍大仍算微笑
headYawRatioThreshold Number 0.06 鼻尖横向偏移比(相对眼距,辅助摇头判定) [0.02, 0.15] · ↓ 越小越容易判摇头
headPitchRatioThreshold Number 0.06 鼻尖纵向偏移比(相对眼距,辅助点头判定) [0.02, 0.15] · ↓ 越小越容易判点头
headYawDegreeThreshold Number 8 摇头 Yaw 角阈值(度,相对 baseline 转角) [3, 20] · ↓ 越小转头幅度要求越低
headPitchDegreeThreshold Number 8 点头 Pitch 角阈值(度) [3, 20] · ↓ 越小点头幅度要求越低
headCenterRatioThreshold Number 0.03 正脸比例阈值(鼻尖偏移相对 baseline 小于此值视为回正) [0.01, 0.1] · ↑ 越大越容易判回正/正脸
headYawCenterDegreeThreshold Number 5 回正 Yaw 上限(度,相对 baseline 小于此值视为回正) [2, 15] · ↑ 越大越容易判回正
headYawCenterFramesRequired Number 3 连续回正帧数(定向/双向摇头回正阶段) [1, 10] · ↓ 越小回正所需连续帧越少

修改 Native 阈值或新增 actionThresholds 支持后,需重编自定义基座后才能在真机生效。

宿主示例:pages/camera/livenessThresholdTune.nvuepagesx/camera/livenessThresholdTune.uvue(步进器调参 + 预设 + remount 重测)。

方法

方法名称 说明 方法参数 平台
open 打开摄像头预览 android
close 关闭摄像头预览 android
reset 重置检测状态 android
isOpened 查询预览是否已打开 无,返回 Boolean android
startDetection 开始活体检测 actionList:动作数组,可选 android
restartDetection 重新开始检测 actionList:动作数组,可选 android

事件

事件名称 说明 回调参数(detail) 平台
onCameraOpened 相机打开 {} android
onCameraClosed 相机关闭 {} android
onCameraError 相机错误 { action, message } android
onActionChange 切换动作提示 { action, index, total, tip, hasFace?, faceCount?, rePrompt? } android
onActionCompleted 单项动作完成 { action, index, total } android
onLivenessPass 活体检测通过 { actions, colorPassed?, mode? } android
onFaceStatus 人脸状态 { hasFace, faceCount } android
onFaceError 检测错误 { code, message } android
onVideoRecordStart 自动录像开始 { path } android
onVideoRecordEnd 自动录像结束 { path, uri, duration, size, suffix } android
onVideoRecordError 自动录像失败 { action, message } android
onColorPhaseChange 炫彩阶段变化 { phase, index, total, tip, color } android
onColorLivenessPass 炫彩阶段通过 { passed } android
onColorLivenessFail 炫彩阶段失败 { reason, retryable } android
onPictureTaken 正脸照片抓拍成功(returnPhoto=true { stage, path, uri, width, height } android
onPictureTakenError 正脸照片抓拍失败 { stage, code, message } android
onPictureTakenReady during 模式计划就绪 { duringInsertAfterActionCount } android

隐私、权限声明

1. 本插件需要申请的系统权限列表:

// 活体检测必须 <uses-permission android:name="android.permission.CAMERA" /> // 自动录像且含音频时需要 <uses-permission android:name="android.permission.RECORD_AUDIO" /> // 保存录像到相册时需要 <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率: