更新记录

1.0.66(2026-07-30)

  • 修复 iOS 首次允许相机权限后,动态扫码页图片配置在生成 Swift 中发生强制类型转换并导致 App 闪退的问题;插件层改为安全读取动态字段并直接构造平台配置类型,原示例 uiImageConfig + startScan(options) 调用保持不变。
  • 修复 iPhone X / iOS 16 全屏扫码默认码制下同步 Vision 兜底占用主线程、导致相册/手电/连续模式/关闭按钮响应迟滞的问题;视频帧现在由专用串行队列识别,主线程只接收结果。
  • 修复打开系统相册触发页面 onHide 时,stopScan/destroyScanner 可能从 Weex bridge 线程直接关闭 UIKit 页面并触发 EXC_BREAKPOINT / SIGTRAP 的问题;全屏关闭、状态清理和完成回调统一回到主线程。
  • Android / iOS 全屏与嵌入式运行诊断标识统一升级到 1.0.66。本版包含 iOS 原生 UTS/Swift 生成变化,发布和真机验收必须重新制作并安装匹配的 iOS 自定义基座或正式包;仅更新页面资源不能替换旧 framework。

1.0.65(2026-07-28)

  • 修复 Android 原生扫码六处将 Throwable 直接传给仅接受 ExceptionTasks.forException,导致 Kotlin compileReleaseKotlin 类型不匹配、安卓云打包失败的问题。
  • 失败任务现在统一通过安全转换收敛异常类型:普通 Exception 保持原对象,其他 Throwable 使用保留 cause 的 RuntimeException 包装,不改变扫码回调、错误码或业务行为。
  • 用户已确认当前源码安卓云打包成功;Android / iOS 全屏与嵌入式运行诊断标识统一升级到 1.0.65。Android 原生 Kotlin 已变化,旧自定义基座需重新原生联编或重新制作。

1.0.64(2026-07-27)

  • 修复 Android 工业平板或低清晰度相机中,长而细的 Code128 在实时画面占比较小时持续扫描却不返回结果的问题;整帧无结果后会对可见扫码区域执行节流的裁剪放大重试。
  • 修复 Android 相册整图中一维码占比较小时返回 album decode failed: no code recognized 的问题;首轮无结果后会对中心区域执行受尺寸上限保护的裁剪放大重试。
  • 新兜底仅覆盖 Code128、Code39、Code93、Codabar、EAN、UPC、ITF 等一维码,二维码与既有 Data Matrix 中心裁剪、反色重试链路保持不变。
  • Android / iOS 全屏与嵌入式运行诊断标识统一升级到 1.0.64;Android 原生 Kotlin 已变化,发布与客户复测必须重新原生联编或安装匹配的正式包/自定义基座。
查看更多

平台兼容性

uni-app(4.84)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(4.84)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - -

lizhao-scan-pro

lizhao-scan-pro 是一个面向 uni-app / uni-app x 的原生扫码 UTS 插件。既可以通过 API 拉起原生全屏扫码页,也可以在 .nvue/.uvue 页面使用 <lizhao-scan-pro /> 原生预览组件,完全自由布局扫码框、按钮、提示和业务结果 UI。

插件底层按平台走原生能力:Android 使用 CameraX + ML Kit,iOS 使用 AVFoundation + Vision,Harmony 使用系统扫码能力。Web 和小程序当前不伪造成功结果,会返回明确的不支持错误。

适合哪些场景

场景 推荐能力 说明
普通扫码 startScan 打开全屏扫码页,识别成功后回调结果
商品条码/库存盘点 formatsminBarcodeLengthcontinuous 限制条码类型、过滤短码、连续返回结果
一屏多个码 returnAllResults 同一帧内返回多条识别结果,适合货架、票据、批量标签
相册识别 enableAlbumpickImageAndScan 支持从图片中识别二维码或条形码
近距离扫码 nearFocusLockzoomRatio 适合约 5cm 近距标签、设备码、细小条码
品牌化扫码页 scanFrameStyleuiTextConfiguiImageConfiguiLayoutConfig 自定义扫码框、文案、图标、按钮位置和遮罩显示
完全自由布局 <lizhao-scan-pro /> 原生预览嵌入客户页面,扫码框、按钮与业务 UI 全部由页面决定
页面状态联动 pauseScanresumeScanstopScandestroyScanner 页面隐藏、返回、销毁时控制相机资源

接入方式选择

接入方式 适合客户 推荐入口
只要快速扫码 想先跑通功能,界面使用默认样式 复制“5 分钟跑通”示例
需要业务规则 指定二维码/条码类型、连续扫码、过滤短码 查看“从基础到进阶”
需要品牌化全屏扫码 调整扫码框、操作按钮、提示文案和图标 查看“扫码页样式配置”
需要完全自由布局 自己编写页面结构、动画、按钮与结果区域 查看“完全自由布局组件”
需要完整查询资料 已接入,正在查某个字段含义 直接跳到“参数说明(ScanOptions)”

5 分钟跑通

1. 使用推荐版本

建议使用 HBuilderX 5.07 及以上版本进行测试、运行和打包。低版本 HBuilderX 的 UTS 编译器可能不支持当前插件使用的部分 UTS 语法或生成规则,容易出现 UTS 语法校验、编译或原生联编问题。

2. 引入插件

import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'

全屏扫码通过 script 中的 API 调用;完全自由布局通过 <lizhao-scan-pro /> 组件使用。页面 import 只写插件根目录,不要直接 import utssdk 内部文件。

3. 打开扫码页

import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'

LizhaoScanPro.startScan({
  // 建议页面内固定一个扫描器 ID,后续停止、暂停、恢复都使用同一个 ID
  scannerId: 'main',
  // 显示相册入口,方便用户从图片中识别二维码或条形码
  enableAlbum: true,
  // 识别成功回调,单次扫码默认识别成功后返回结果
  onResult(res) {
    console.log('扫码结果:', res.value, res.format)
  },
  // 识别失败、权限异常或平台不支持时会进入这里
  onError(err) {
    console.error('扫码失败:', err)
  }
})

4. 页面离开时释放资源

onHide() {
  // 页面不可见时停止扫码,避免后台占用相机
  LizhaoScanPro.stopScan({ scannerId: 'main' })
}

onUnload() {
  // 页面销毁时彻底释放扫描器
  LizhaoScanPro.destroyScanner({ scannerId: 'main' })
}

从基础到进阶

只识别指定码制

LizhaoScanPro.startScan({
  scannerId: 'main',
  // 只识别二维码和 Code128,减少无关码制干扰
  formats: ['qrCode', 'code128'],
  onResult(res) {
    console.log('命中指定码制:', res.value)
  }
})

连续扫码和批量识别

LizhaoScanPro.startScan({
  scannerId: 'main',
  // 开启连续扫码,适合仓储、盘点、核销等连续作业
  continuous: true,
  // 两次回调至少间隔 500ms,业务侧也建议继续做去重
  continuousIntervalMs: 500,
  // 同一帧出现多个码时返回全部识别结果
  returnAllResults: true,
  onResult(res) {
    res.results.forEach((item) => {
      console.log('批量结果:', item.value, item.format)
    })
  }
})

近距小码识别

LizhaoScanPro.startScan({
  scannerId: 'main',
  // 开启近距锁焦模式,适合设备铭牌、细小标签、约 5cm 近距扫码
  nearFocusLock: true,
  // 预设缩放倍率,帮助小码在画面中更清晰
  zoomRatio: 1.8,
  // 固定码长业务可过滤明显错误的短结果
  minBarcodeLength: 8,
  onResult(res) {
    console.log('近距识别结果:', res.value)
  }
})

品牌化扫码页

LizhaoScanPro.startScan({
  scannerId: 'main',
  scanFrameStyle: {
    // 调整扫码框宽高和位置,适配业务视觉
    widthRatio: 0.72,
    heightRatio: 0.5,
    topRatio: 0.2,
    cornerRadius: 22,
    borderColor: '#88FFFFFF',
    cornerColor: '#FFFF6B6B'
  },
  uiTextConfig: {
    // 自定义提示文案和按钮文案
    tipText: '请对准二维码或条形码',
    closeText: '关闭',
    albumText: '相册',
    torchOffText: '打开手电筒',
    torchOnText: '关闭手电筒'
  },
  onResult(res) {
    console.log('扫码结果:', res.value)
  }
})

完全自由布局组件

当扫码页的结构、动画、按钮或业务信息需要由业务自己编写时,使用 <lizhao-scan-pro /> 把原生相机预览嵌入页面。组件只负责相机、识别和状态回调,扫码框、扫描线、按钮、提示、结果区等界面全部由页面实现。

接入前先确认

先按页面形态选择正确入口:

你的需求 正确接入方式 不要这样用
快速打开完整扫码页 调用 startScan(options) 不需要为了改几段文案就改用组件
页面结构、按钮和业务区完全自定义 .nvue/.uvue 使用 <lizhao-scan-pro /> 不要同时再调用同 ID 的全屏 startScan
uni-app 普通 .vue 页面 继续使用全屏 startScan 不要在普通 .vue 中放嵌入式组件

开始接入前必须满足以下条件:

  1. 只在 Android/iOS App 使用;Harmony、Web 和小程序当前不支持嵌入式预览。
  2. uni-app 页面文件必须是 .nvue,uni-app x 页面文件必须是 .uvue,不能只把普通 .vue 改个组件标签。
  3. 必须重新制作并安装包含当前插件原生代码的 Android/iOS 自定义基座或正式包。只更新 wgt/appResource 不会更新旧基座中的相机组件。
  4. 给预览容器和组件设置明确的宽度、高度;高度为 0 时不会显示相机画面。
  5. scannerId 必须是非空且当前页面唯一的固定字符串,组件挂载后不要动态修改。
  6. 必须监听 error,权限被拒绝、参数错误或会话冲突都会通过该事件返回,不能只监听 scan
  7. 一个页面只保留一个活动相机会话;打开全屏扫码前先停止嵌入式组件。

最小正确接入

下面的 template 和 style 可用于 .nvue/.uvue;script 部分需要按 uni-app 或 uni-app x 选择对应版本。

<view class="scanner-shell">
  <!-- 原生组件只负责相机预览与识别,不绘制固定扫码 UI -->
  <lizhao-scan-pro
    ref="scanner"
    scanner-id="freeLayout"
    class="camera-preview"
    :formats="['all']"
    :continuous="false"
    @ready="onReady"
    @scan="onScan"
    @error="onError"
    @statechange="onStateChange"
  />

  <!-- 扫码框、扫描线、按钮和业务提示全部由客户页面自由布局 -->
  <view class="custom-overlay">
    <view class="custom-scan-frame"></view>
    <text class="custom-tip">请将二维码或条形码放入扫码框</text>
  </view>
</view>
.scanner-shell {
  position: relative;
  width: 750rpx;
  height: 900rpx;
}
.camera-preview,
.custom-overlay {
  position: absolute;
  left: 0;
  top: 0;
  width: 750rpx;
  height: 900rpx;
}
.camera-preview { z-index: 1; }
.custom-overlay { z-index: 10; }

uni-app .nvue 的最小生命周期代码:

<script>
export default {
  data() {
    return {
      // ready 前不要在 onShow 中调用 resume,避免首次进入时重复启动。
      scannerReady: false
    }
  },
  onShow() {
    const scanner = this.$refs.scanner
    if (this.scannerReady && scanner != null && scanner.resume != null) {
      scanner.resume()
    }
  },
  onHide() {
    const scanner = this.$refs.scanner
    if (scanner != null && scanner.pause != null) scanner.pause()
  },
  onUnload() {
    const scanner = this.$refs.scanner
    if (scanner != null && scanner.dispose != null) scanner.dispose()
  },
  methods: {
    eventData(event) {
      // uni-app 原生组件事件数据可能位于 event.detail。
      return event != null && event.detail != null ? event.detail : event
    },
    onReady(event) {
      this.scannerReady = true
      console.log('原生扫码预览已就绪:', this.eventData(event))
    },
    onScan(event) {
      const frame = this.eventData(event)
      console.log('本帧扫码结果:', frame.results)
    },
    onError(event) {
      console.error('嵌入式扫码失败:', this.eventData(event))
    },
    onStateChange(event) {
      console.log('扫码状态变化:', this.eventData(event))
    }
  }
}
</script>

uni-app x .uvue 的最小生命周期代码:

<script setup lang="uts">
import {
  ScanEmbeddedEvent,
  ScanEmbeddedState,
  ScanFail,
  ScanFrameResult
} from '@/uni_modules/lizhao-scan-pro'

// component-uts easycom 会生成该公开实例类型,无需手写组件声明。
const scanner = ref<LizhaoScanProComponentPublicInstance | null>(null)
const scannerReady = ref<boolean>(false)

const onReady = (state: ScanEmbeddedState): void => {
  scannerReady.value = true
  console.log('原生扫码预览已就绪:' + JSON.stringify(state))
}
const onScan = (frame: ScanFrameResult): void => {
  console.log('本帧扫码结果:' + JSON.stringify(frame.results))
}
const onError = (error: ScanFail): void => {
  console.error('嵌入式扫码失败:' + JSON.stringify(error))
}
const onStateChange = (event: ScanEmbeddedEvent): void => {
  console.log('扫码状态变化:' + JSON.stringify(event))
}

onShow(() => {
  if (scannerReady.value) scanner.value?.resume?.()
})
onHide(() => {
  scanner.value?.pause?.()
})
onUnload(() => {
  scanner.value?.dispose?.()
})
</script>

完整可运行页面:

  • uni-app:uni_modules/lizhao-scan-pro/example/uniapp/free-layout.nvue
  • uni-app x:uni_modules/lizhao-scan-pro/example/uniappx/free-layout.uvue

建议先复制对应完整示例确认预览和回调正常,再逐步替换成业务 UI,不要从零拼装生命周期代码。

组件职责与扫码范围

能力 由谁负责 说明
相机预览、码识别、格式过滤、连续扫码 <lizhao-scan-pro /> 通过 props 配置,通过事件返回结果
扫码框、扫描线、遮罩、按钮、提示、动画、结果区 业务页面 使用 .nvue/.uvue 页面元素覆盖在组件上方
相册识别 业务页面调用 pickImageAndScan 嵌入式组件不内置相册按钮
页面隐藏、恢复和销毁 业务页面生命周期 分别调用 pause()resume()dispose()

自定义扫码框只是视觉引导,不是识别裁剪区域。组件会识别整个相机预览范围内的有效码;如业务只允许扫码框内的码,需要在业务层结合结果规则做校验,不能仅依赖页面上画出的方框。

showScanFrameshowMaskOverlayscanFrameStyleuiTextConfiguiImageConfiguiLayoutConfigtipTextenableAlbum 属于全屏 startScan 的界面配置,不是嵌入式组件属性。自由布局模式下请直接在页面中实现这些 UI。

页面覆盖层如果拦截了点击事件,组件不会自动收到点击位置。需要点按聚焦时,在覆盖层的点击事件中取得组件局部坐标,再调用 focusAt(x, y)

生命周期必须这样处理

页面时机/动作 应调用 说明
首次进入页面 通常无需手动调用 默认 autoStart=true,组件挂载后自动请求权限并启动;不要再在 onReady 中重复调用 start()
页面进入前台 resume() 仅在已经收到 ready 且没有活动中的全屏会话时调用;首次 onShow 应跳过
页面进入后台 pause() 暂停识别但保留相机和组件实例,返回页面后可快速恢复
临时关闭相机 stop() 解绑相机但保留组件实例和 scannerId 注册,之后可调用 start() 再次启动
Android 示例切换全屏扫码 stop(),再用不同 ID 调用 startScan() 仅 Android 示例提供“嵌入 → 全屏 → 返回恢复”比较链;必须监听 onOverlayEvent,收到 closed/stopped 后再调用组件 start()
页面卸载或永久关闭 dispose() 释放相机、线程、回调和注册关系;dispose() 后不能再次调用 start(),重新使用必须重新挂载组件

页面 ref 的最终释放方法是 dispose(),不要调用 scanner.destroy()destroy 与 component-uts 框架内部方法同名,会导致生成代码冲突。脚本层公共 API destroyScanner({ scannerId }) 仍然保留,它会按 scannerId 销毁对应扫码会话,不等同于页面 ref 方法名。

Android 从嵌入式组件切换到全屏扫码时,onResult 只表示已经返回识别结果,不表示全屏原生页面和相机已经释放。不要在 onResult/onError 中直接调用组件 start();示例会设置 overlayConfig.enabled=true,并在 onOverlayEvent 收到 closed/stopped 后恢复嵌入预览。iOS 支持嵌入式自由布局,但本示例不提供嵌入与全屏混合切换;iOS 客户应在同一页面只选择一种相机会话形态。

Android 全屏 Activity 返回时,页面 onShow 可能早于原生 closed/stopped 事件触发。fullScreenActive=true 时必须跳过页面 onShow 中的 resume();只能由 closed/stopped(或全屏启动前同步失败)调用统一恢复方法,避免两个相机会话同时抢占摄像头。

如果设置 autoStart=false,请在组件 ref 可用后主动调用 start();不要等待 ready 再启动,因为 ready 只有原生相机真正启动后才会触发。

scannerId 使用规则

  1. 每个已挂载组件使用一个非空、唯一且固定的 scannerId,推荐按页面或业务命名,例如 warehouseInboundScanner
  2. 通过公共 API 控制组件时,API 参数中的 scannerId 必须与组件完全一致。
  3. 为保证 Android/iOS 行为一致,组件挂载后不要动态修改 scannerId;需要换 ID 时先卸载旧组件,再挂载新组件。
  4. 同一个 scannerId 不能同时属于全屏扫码和嵌入式组件,否则返回 9010011 scanner id occupiedstop() 不会释放组件注册;必须复用同 ID 时需要先 dispose() 或卸载组件。
  5. 即使使用不同 ID,设备通常也只能稳定占用一个相机会话,因此打开全屏扫码前仍应先调用组件 stop()

常见错误与处理

现象/错误 常见原因 正确处理
组件不显示或 easycom 无法识别 uni-app 使用了普通 .vue 改用 .nvue;uni-app x 使用 .uvue
页面有位置但相机黑屏 组件宽高为 0、相机权限未授权或仍在使用旧基座 明确设置宽高,处理 error,重新制作并安装当前插件自定义基座/正式包
只更新 wgt 后仍没有组件能力 原生代码已经编译进旧基座 重新原生联编或重新云打包,wgt/appResource 不能替换原生组件
9010011 scanner id occupied 同 ID 已被另一个组件或全屏扫码占用 改用新的唯一 ID;如必须复用原 ID,先 dispose() 或卸载旧组件,单独调用 stop() 不会释放 ID
9010012 scanner component unavailable ref 尚未就绪、组件已卸载或已执行 dispose() 等待组件挂载;dispose() 后重新挂载组件,不要复用旧 ref
调用 scanner.destroy() 编译失败或方法不存在 使用了旧示例或把页面 ref 方法与公共 API 混用 页面 ref 改用 scanner.dispose();脚本 API 使用 destroyScanner({ scannerId })
首次进入页面重复启动 autoStart=true,同时又在首次 onShow/onReady 调用了 start/resume 使用 scannerReady 标记,首次 onShow 跳过,收到 ready 后再允许恢复
连续收到相同结果 开启了 continuous,但没有设置间隔或业务去重 设置 continuousIntervalMs,并按业务主键做二次去重
Android 全屏扫码无法打开或返回后黑屏 嵌入式组件仍占用相机,或在 onResult/onError 中过早恢复 stop() 再调用不同 ID 的 startScan();设置 overlayConfig.enabled=true,只在 closed/stopped 后调用组件 start()
扫码框外的码也被识别 误以为自定义扫码框会裁剪识别区域 扫码框只是视觉提示;在业务层校验结果或调整相机预览范围

组件属性

参数 类型 必填 说明 默认值 可选参数
scannerId string 扫描器唯一标识,用于组件注册与公共 API 控制;挂载后不要修改 embedded 任意非空且当前页面唯一的字符串
formats Array 允许识别的码制 ["all"] all / qrCode / aztec / codabar / code39 / code93 / code128 / dataMatrix / ean8 / ean13 / itf / pdf417 / upcA / upcE
minBarcodeLength number 一维码最小长度过滤 0 大于等于 0
returnAllResults boolean 是否返回同一帧的全部有效结果 false true / false
continuous boolean 是否持续识别 false true / false
continuousIntervalMs number 连续结果最小间隔,单位毫秒;仅 continuous=true 生效 0 大于等于 0
autoStart boolean 原生 View 挂载后是否自动启动;设为 false 后需在 ref 可用时调用 start() true true / false
zoomRatio number 初始缩放倍率 1 大于 0
torchEnabled boolean 初始手电状态 false true / false
nearFocusLock boolean 是否启用近距辅助锁焦 false true / false
beepOnScan boolean 识别成功后是否播放提示音 false true / false
vibrateOnScan boolean 识别成功后是否短震动 false true / false

组件事件

事件 数据类型 说明
ready ScanEmbeddedState 原生预览与识别链路准备完成;收到后才可安全执行前后台恢复控制
scan ScanFrameResult 返回单码或同帧多码结果,业务数据读取 results 数组,结构与 startScan 一致
error ScanFail 权限、初始化、参数或会话冲突错误;必须监听并记录 errCode/errMsg
statechange ScanEmbeddedEvent 返回 starting/running/paused/stopped/destroyed 状态变化
focus ScanEmbeddedEvent 返回点按聚焦坐标与执行状态

uni-app .nvue 的原生组件事件数据可能包装在 event.detail 中,建议像完整示例一样先取 event.detail,不存在时再使用事件对象本身;uni-app x .uvue 按表格中的强类型直接接收。

组件方法

方法 说明
start() 请求权限并启动或重新绑定相机;适用于 autoStart=falsestop() 后重启
stop() 停止识别并解绑相机,保留组件实例和 scannerId 注册;打开不同 ID 的全屏扫码前必须先调用
pause() 暂停分析,不派发识别结果
resume() 恢复分析;尚未启动时会启动会话
applyTorchEnabled(enabled) 设置手电状态
applyZoomRatio(zoomRatio) 设置缩放倍率
setScanFormats(formats) 动态更新码制
focusAt(x, y) 按组件局部坐标执行聚焦
getState() 返回当前组件状态快照
dispose() 永久释放相机、识别器、线程、回调和注册表引用;调用后必须重新挂载组件才能再次使用

组件与现有 pauseScan/resumeScan/setTorchEnabled/setZoomRatio/setScanFormats/stopScan/destroyScanner 共用 scannerId。公共 API 会优先控制同 ID 的组件;若同 ID 已被组件占用,再调用全屏 startScan 会返回 9010011 scanner id occupied,不会隐式关闭客户页面中的相机。

自由布局平台边界

页面/平台 是否支持 说明
uni-app App .nvue Android / iOS 可嵌入原生预览
uni-app x App .uvue Android / iOS 可嵌入原生预览
Android 嵌入/全屏比较链 示例提供切换按钮,并在全屏 closed/stopped 后恢复嵌入预览
iOS 嵌入/全屏比较链 iOS 仍支持嵌入式自由布局;本示例不提供两种相机会话混合切换
uni-app 普通 .vue 普通 Vue 页面不承诺原生 View 层级与覆盖层稳定性,请使用 .nvue
Harmony 保留系统全屏 startScan,不伪造嵌入式组件成功
Web / 小程序 不具备本插件的原生嵌入式预览能力

页面隐藏时必须调用 pause(),再次显示时在已收到 ready 的前提下调用 resume(),页面卸载时调用 dispose()。Android/iOS 原生组件代码会编译进基座或安装包,仅更新 wgt/appResource 不能替换旧基座里的原生实现。

特色功能一览

特色功能 能解决什么问题 相关配置
原生全屏扫码 不依赖页面组件拼装,直接使用平台原生相机能力 startScan
多码制识别 支持二维码、Data Matrix、PDF417、Code39、Code128、EAN、UPC 等常见码制 formats
同帧多码返回 一张画面中多个码可一次性回传 returnAllResults
连续扫码 适合盘点、核销、批量入库等高频扫码场景 continuouscontinuousIntervalMs
近距聚焦增强 改善细小码、设备铭牌、近距离扫码体验 nearFocusLockzoomRatio
相册识别 支持从本地图片中识别码 enableAlbumpickImageAndScan
扫码页自定义 支持扫码框、遮罩、扫描线、文案、图片图标和布局偏移配置 scanFrameStyleuiTextConfiguiImageConfiguiLayoutConfig
完全自由布局 原生预览嵌入 .nvue/.uvue,页面自由编写扫码框、按钮和业务区 <lizhao-scan-pro />
手电与缩放控制 扫码过程中动态调整设备能力 setTorchEnabledsetZoomRatio
明确平台边界 不支持平台返回错误,不伪造成功 9010001

支持平台

平台 是否支持 说明
uni-app Vue2/Vue3 可用
uni-app x App 侧可用
Android 原生依赖入口已配置,扫码链路基于 CameraX + ML Kit
iOS 原生扫码链路已实现(AVFoundation + Vision,实时扫码含 Vision 视频帧兜底)
Harmony 基础扫码能力可用(基于系统 scanCode,手电/缩放为状态兼容)
Web 返回 9010001
微信小程序 返回 9010001
支付宝小程序 返回 9010001

API 列表

API 用途
startScan(options) 打开原生全屏扫码页
stopScan(options) 停止当前扫码
pauseScan(options) 暂停当前扫码
resumeScan(options) 恢复当前扫码
setTorchEnabled(options) 动态打开或关闭手电筒
setZoomRatio(options) 动态设置缩放倍率
pickImageAndScan(options) 从图片中识别二维码或条形码
setScanFormats(options) 动态设置识别码制
postOverlayMessage(options) 向扫码遮罩事件链路发送业务消息
destroyScanner(options) 销毁扫描器并释放资源

Harmony 能力边界

Harmony 端已补齐与 Android / iOS 同名 API 与回调结构,但受系统扫码页能力限制,存在以下边界:

  1. setTorchEnabled / setZoomRatio:保持状态兼容并返回成功回调,当前不直接驱动系统扫码页的手电筒和缩放。
  2. startScan / pickImageAndScan:基于系统 uni.scanCode 能力,UI 形态以系统页面为准,不保证与 Android/iOS 自定义扫码页完全一致。
  3. continuous=true:通过循环拉起系统扫码能力实现连续扫描,支持 continuousIntervalMs 回调间隔控制;建议业务侧继续做去重与节流。
  4. showContinuousToggle:参数可接收但受系统扫码页能力限制,Harmony 当前不展示页内“单次/连续”切换按钮。
  5. returnAllResults:参数可接收但受系统扫码能力限制,Harmony 当前仍按单条结果回调。
  6. formats:Harmony 仅能按系统扫码大类限制(如 barCode / qrCode / datamatrix / pdf417),code39/code128/ean13 等一维细分格式会映射到 barCode
  7. minBarcodeLength:Harmony 端按识别结果长度做回调前过滤,可过滤短于阈值的一维码结果,但不能提升系统扫码页本身的识别精度。
  8. beepOnScan / vibrateOnScan:Android / iOS 按插件原生链路处理;Harmony 当前暂不承诺震动/提示音生效,以系统扫码页行为为准。

参数说明(ScanOptions)

参数 类型 必填 说明 默认值 可选参数
scannerId string 扫描器 ID default 任意非空字符串
formats Array 识别格式列表 ["all"] all / qrCode / aztec / codabar / code39 / code93 / code128 / dataMatrix / ean8 / ean13 / itf / pdf417 / upcA / upcE
minBarcodeLength number 一维条码最小长度过滤(Android 相机扫码 / 相册识别、iOS 相机扫码;Harmony 回调前过滤);固定码长业务建议传实际位数 0 大于 0 的数值
returnAllResults boolean 是否返回同一帧内全部识别结果(默认保持历史行为:每帧仅返回一个优先结果) false true / false
continuous boolean 是否连续扫码 false true / false
continuousIntervalMs number 连续扫码最小回调间隔(ms);仅 continuous=true 生效 0 大于等于 0 的数值
showContinuousToggle boolean 是否在原生扫码全屏界面显示“单次/连续”切换按钮(Harmony 当前仅接收参数,不展示) false true / false
enableAlbum boolean 是否在原生扫码全屏界面右上角显示相册入口(仅 startScan 生效) false true / false
enableTorch boolean 是否启用闪光灯 false true / false
zoomRatio number 缩放倍率 1 大于 0 的数值
nearFocusLock boolean 是否启用近距锁焦模式(Android / iOS);开启后点击聚焦会优先应用近距辅助缩放,适合约 5cm 场景 false true / false
showScanFrame boolean 是否显示红色扫码角框与中间透明框遮罩;传 false 时隐藏角框和遮罩仅保留扫描线 true true / false
showMaskOverlay boolean 是否显示扫码页黑色遮罩层;仅控制黑色遮罩显隐,不影响扫码框、扫描线、提示文案与操作按钮 true true / false
scanFrameStyle ScanFrameStyle 扫码框样式配置(仅 Android / iOS);支持区域大小、圆角、顶角显隐与颜色定制 null widthRatio / heightRatio / topRatio / cornerRadius / showCorners / borderColor / cornerColor
scanLineColor string 扫描线颜色 #FF3B30 #RRGGBB / #AARRGGBB
tipText string 提示文案 请将二维码/条形码放入框内 任意字符串
uiTextConfig ScanUiTextConfig 扫码页文案/图标配置,支持提示文案与“关闭/相册/手电”按钮图标文案自定义 null tipIcon / tipText / closeIcon / closeText / albumIcon / albumText / torchIcon / torchOnText / torchOffText / torchUnsupportedText
uiImageConfig ScanUiImageConfig 扫码页图片图标配置(提示区/关闭/相册/手电),可与 uiTextConfig 组合使用 null tip / close / album / torchOn / torchOff / torchUnsupported
uiLayoutConfig ScanUiLayoutConfig 扫码页布局偏移配置,支持 close/album/continuous/torch/tip 的容器+图标+文字三层独立偏移 null close / album / continuous / torch / tip
showActionCapsuleBackground boolean 是否显示顶部/底部操作按钮胶囊背景(关闭/相册/单次连续/手电) true true / false
beepOnScan boolean 成功识别时播放提示音;对相机扫码与相册识别都生效 false true / false
vibrateOnScan boolean 成功识别时触发短震动;对相机扫码与相册识别都生效 false true / false
overlayConfig OverlayConfig 遮罩事件透传配置(不加载 webview) null enabled / htmlUrl / bridgeName / userAgentSuffix
permissionRationale PermissionRationale 权限说明文案 null cameraTitle / cameraMessage / albumTitle / albumMessage

扫码框样式配置(scanFrameStyle)

scanFrameStyle 仅作用于 Android / iOS 全屏原生扫码页:

  1. 不传时保持历史默认扫码框样式(零破坏兼容)。
  2. 比例参数使用 0~1 坐标系:widthRatio / heightRatio / topRatio
  3. cornerRadius 单位:Android 按 dp、iOS 按 pt
  4. showScanFrame=false 时,scanFrameStyle 整体忽略。
  5. showCorners=false 时隐藏四个顶角,仅保留边框与扫描线。
  6. 字段缺失或非法值自动回退默认值,不抛错、不影响扫码链路。

参数结构:

参数 类型 必填 说明 默认值 可选参数
scanFrameStyle.widthRatio number 扫码框宽度占屏宽比例 0.68 推荐 0.3~0.9
scanFrameStyle.heightRatio number 扫码框高度占屏高比例 0.44 推荐 0.25~0.85
scanFrameStyle.topRatio number 扫码框顶部占屏高比例 0.24 推荐 0.05~0.7
scanFrameStyle.cornerRadius number 扫码框圆角(Android=dp,iOS=pt) 14(Android)/18(iOS) 大于等于 0
scanFrameStyle.showCorners boolean 是否显示四个顶角;false 时仅显示边框与扫描线 true true / false
scanFrameStyle.borderColor string 框体描边色 平台默认色 #RRGGBB / #AARRGGBB
scanFrameStyle.cornerColor string 四角线条色(仅影响四角,不影响边框) 平台默认色 #RRGGBB / #AARRGGBB

默认行为示例(不传 scanFrameStyle):

import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'

LizhaoScanPro.startScan({
  // 扫描会话 ID;后续 stop/pause/resume/destroy 需传同一个值
  scannerId: 'main',
  // 是否显示默认扫码框与遮罩层
  showScanFrame: true,
  // 识别成功回调(单次/连续结果都从这里返回)
  onResult(res) {
    console.log(res)
  }
})

自定义样式示例:

import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'

LizhaoScanPro.startScan({
  // 扫描会话 ID
  scannerId: 'main',
  // 启用扫码框渲染(scanFrameStyle 仅在此为 true 时生效)
  showScanFrame: true,
  scanFrameStyle: {
    // 扫码框宽度占屏宽比例(0~1)
    widthRatio: 0.72,
    // 扫码框高度占屏高比例(0~1)
    heightRatio: 0.5,
    // 扫码框顶部距屏幕顶部比例(0~1)
    topRatio: 0.2,
    // 圆角:Android=dp,iOS=pt
    cornerRadius: 22,
    // 是否显示四个顶角
    showCorners: true,
    // 边框颜色(支持 #RRGGBB / #AARRGGBB)
    borderColor: '#88FFFFFF',
    // 顶角颜色(仅影响顶角,不影响边框)
    cornerColor: '#FFFF6B6B'
  },
  // 识别成功回调
  onResult(res) {
    console.log(res)
  }
})

黑色遮罩独立开关示例(仅隐藏黑色遮罩,保留扫码框/扫描线):

import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'

LizhaoScanPro.startScan({
  scannerId: 'main',
  // 继续显示扫码框与扫描线
  showScanFrame: true,
  // 仅隐藏黑色遮罩层
  showMaskOverlay: false,
  onResult(res) {
    console.log(res)
  }
})

扫码页文案/图标配置(uiTextConfig)

uiTextConfig 仅作用于 Android / iOS 全屏原生扫码页,支持以下三种配置方式:

  1. 仅图标:{ closeIcon: "✕" }
  2. 仅文案:{ closeText: "返回" }
  3. 图标 + 文案:{ closeIcon: "✕", closeText: "关闭" }

提示:

  1. tipText(旧字段)继续可用,若同时传 uiTextConfig.tipText,优先使用 uiTextConfig.tipText
  2. torchIcon 会同时作用于手电按钮的开/关/不支持文案。
  3. 未配置的字段自动回退到默认文案,不影响历史行为。

扫码页图片图标配置(uiImageConfig)

uiImageConfig 仅作用于 Android / iOS 全屏原生扫码页,推荐配合 uiTextConfig 使用:

  1. 仅图标:只传图片图标,文本字段留空(例如 close 只传 src)。
  2. 仅文案:不传 uiImageConfig,只传 uiTextConfig 文案字段。
  3. 图标 + 文案:同时传 uiImageConfiguiTextConfig 对应字段。

图标来源支持:

  1. 本地文件路径(如 /storage/...、应用沙盒路径)
  2. file:// / content:// URI
  3. data:image/*;base64,...
  4. 应用静态资源路径(如 static/xxx.png_www/static/xxx.png

静态资源路径建议:

  1. 优先传 static/xxx.png/static/xxx.png(推荐)。
  2. _www/static/xxx.png 也兼容,但通常不需要业务层手动加 _www 前缀。
  3. 若业务需要固定为绝对路径,可在页面侧用 plus.io.convertLocalFileSystemURL('_www/static/xxx.png') 转换后再传入。

本地 static 图片示例(Android / iOS):

import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'

function resolveUiImagePath(path: string): string {
  // 统一路径分隔符并去除首尾空白
  const normalized = String(path || '').replace(/\\/g, '/').trim()
  if (!normalized) {
    return normalized
  }
  // #ifdef APP-PLUS
  try {
    // 兼容传入 static/xxx.png 或 /static/xxx.png 的写法
    const plusLocalPath = normalized.startsWith('_www/')
      ? normalized
      : `_www/${normalized.replace(/^\/+/, '')}`
    return plus.io.convertLocalFileSystemURL(plusLocalPath) || normalized
  } catch (_) {
    // plus 不可用时回退原始路径(例如非 App 环境文档预览)
    return normalized
  }
  // #endif
  return normalized
}

LizhaoScanPro.startScan({
  // 扫描会话 ID
  scannerId: 'main',
  // 关闭按钮/相册/手电等按钮胶囊背景(适合 icon-only 风格)
  showActionCapsuleBackground: false,
  uiTextConfig: {
    // icon-only 场景:文本置空
    closeText: '',
    albumText: '',
    torchOnText: '',
    torchOffText: '',
    // 底部提示文案
    tipText: '请对准二维码'
  },
  uiImageConfig: {
    // 左上角关闭图标(src 支持 static/file/content/data URI)
    close: { src: resolveUiImagePath('/static/logo.png'), width: 18, height: 18 },
    // 右上角相册图标(需同时 enableAlbum=true 才会显示按钮)
    album: { src: resolveUiImagePath('/static/logo.png'), width: 18, height: 18 },
    // 手电开启态图标
    torchOn: { src: resolveUiImagePath('/static/logo.png'), width: 16, height: 16 },
    // 手电关闭态图标
    torchOff: { src: resolveUiImagePath('/static/logo.png'), width: 16, height: 16 },
    // 底部提示区图标
    tip: { src: resolveUiImagePath('/static/logo.png'), width: 18, height: 18 }
  }
})

tintColor 使用建议:

  1. 彩色图标建议不传 tintColor,保持原图颜色(iOS 默认 alwaysOriginal 渲染)。
  2. 单色图标需要统一着色时再传 tintColor(如 #FFFFFF)。

参数结构:

参数 类型 必填 说明 默认值 可选参数
uiImageConfig.tip ScanUiImageItem 提示区图标(底部提示) null src / width / height / tintColor
uiImageConfig.close ScanUiImageItem 左上角关闭按钮图标 null src / width / height / tintColor
uiImageConfig.album ScanUiImageItem 右上角相册按钮图标 null src / width / height / tintColor
uiImageConfig.torchOn ScanUiImageItem 手电开启态图标 null src / width / height / tintColor
uiImageConfig.torchOff ScanUiImageItem 手电关闭态图标 null src / width / height / tintColor
uiImageConfig.torchUnsupported ScanUiImageItem 设备无手电筒能力时图标 null src / width / height / tintColor

ScanUiImageItem 字段说明:

参数 类型 必填 说明 默认值 可选参数
src string 图标来源(建议 png/jpg/webp 或 data URI)
width number 图标宽度(Android 按 dp,iOS 按 pt) 16~18(按位置默认) 大于 0 的数值
height number 图标高度(Android 按 dp,iOS 按 pt) 16~18(按位置默认) 大于 0 的数值
tintColor string 图标染色 null #RRGGBB / #AARRGGBB

扫码页偏移配置(uiLayoutConfig)

uiLayoutConfig 仅作用于 Android / iOS 全屏原生扫码页,用于解决“隐藏胶囊后图标离边太远”场景:

  1. 坐标语义统一:x > 0 向右,y > 0 向下;支持负值。
  2. 单位:Android 按 dp、iOS 按 pt
  3. 未传字段按 0 处理,不影响旧布局。

参数结构:

参数 类型 必填 说明 默认值 可选参数
uiLayoutConfig.close ScanUiElementLayout 左上角关闭按钮偏移配置 null containerOffset / iconOffset / textOffset
uiLayoutConfig.album ScanUiElementLayout 右上角相册按钮偏移配置 null containerOffset / iconOffset / textOffset
uiLayoutConfig.continuous ScanUiElementLayout 底部“单次/连续”按钮偏移配置 null containerOffset / iconOffset / textOffset
uiLayoutConfig.torch ScanUiElementLayout 底部手电按钮偏移配置 null containerOffset / iconOffset / textOffset
uiLayoutConfig.tip ScanUiElementLayout 底部提示区偏移配置 null containerOffset / iconOffset / textOffset

ScanUiElementLayout 字段说明:

参数 类型 必填 说明 默认值 可选参数
containerOffset ScanUiOffset 元素整体偏移(容器位置) { x: 0, y: 0 } x / y
iconOffset ScanUiOffset 图标相对容器偏移(无图标时忽略) { x: 0, y: 0 } x / y
textOffset ScanUiOffset 文案相对容器偏移(无文案时忽略) { x: 0, y: 0 } x / y

顶栏 icon-only 贴边示例:

LizhaoScanPro.startScan({
  // 建议固定 scannerId,便于在生命周期中释放资源
  scannerId: 'main',
  // 关闭按钮胶囊背景,配合 icon-only 更简洁
  showActionCapsuleBackground: false,
  // 文本置空,仅展示图标
  uiTextConfig: {
    closeText: '',
    albumText: ''
  },
  // 细调顶部按钮位置(Android=dp,iOS=pt)
  uiLayoutConfig: {
    close: {
      // 整个关闭按钮容器向左偏移
      containerOffset: { x: -12, y: 0 },
      // 图标相对容器再微调
      iconOffset: { x: -2, y: 0 }
    },
    album: {
      // 整个相册按钮容器向右偏移
      containerOffset: { x: 12, y: 0 },
      // 图标相对容器再微调
      iconOffset: { x: 2, y: 0 }
    }
  }
})

胶囊背景控制:

  1. 默认 showActionCapsuleBackground=true,保持历史胶囊样式。
  2. showActionCapsuleBackground=false 时,顶部/底部操作按钮不渲染胶囊底和描边。
  3. 该开关对“关闭/相册/单次连续/手电”统一生效,适合纯图标视觉风格。

底层实现说明:

  1. Android:原生页按钮使用“容器 + 独立 icon/text 子视图”渲染,支持 containerOffset / iconOffset / textOffset 三层偏移。
  2. iOS:原生页按钮使用 UIButton + UIImage 渲染图标(支持尺寸缩放与 tintColor,默认保持原图色彩,不受系统蓝色模板渲染影响)。
  3. 传参方式:统一通过 startScan({ uiImageConfig: {...} }) 传入,不需要额外调用其他 API。

回调说明(startScan)

参数 类型 必填 说明 默认值 可选参数
options.onResult function 单次或连续扫码结果回调 null
options.onError function 扫码失败回调 null
options.onOverlayEvent function 原生遮罩事件回调(仅当 overlayConfig.enabled=true 时触发) null

说明:startScan 结果流默认通过 options.onResult/options.onError 回调返回。options.onOverlayEvent 属于高级通道,需同时配置 overlayConfig.enabled=true 才会触发。 说明:不使用遮罩事件时,建议不要传 options.onOverlayEvent,可减少页面销毁后回调释放日志。 说明:returnAllResults=true 时,onResult(res)res.results 会携带同帧多码结果;默认 false 保持单码回调行为。 说明:Android 相机扫码 / 相册识别、iOS 相机扫码支持 minBarcodeLength 一维条码最小长度过滤;Harmony 端按识别结果长度做回调前过滤。固定长度业务可直接过滤近距失焦、倾斜或轻微拖影时出现的短码片段;过滤后会优先返回码值更长的一维码,长度一致时再按识别框面积选择;Android 相机扫码还会在前 8 帧或约 1.2s 内合并一维码候选择长,避免 minBarcodeLength 小于实际码长时首帧短码立即回调;二维码等二维格式不受该字段影响。 说明:iOS 实时扫码默认先走 AVCaptureMetadataOutput 快速识别;当竖向、反光或轻微虚焦的一维条码没有 metadata 回调时,会低频抽取视频帧交给 Vision 兜底识别,成功后仍沿用原有 onResult、去重与 minBarcodeLength 过滤逻辑。 说明:连续扫码中同一数字 Code39/Code128 已返回较长结果后,后续短码子序列会被过滤,减少同一标签结果从 2000000031 回退到 20000031。 建议:业务已知码制时,优先通过 formats 只保留需要的格式;若码值固定长度,务必同时传 minBarcodeLength,例如本场景应传 formats: ['code39'], minBarcodeLength: 10,可过滤 20000031 这类短码片段且不会额外等待冷启动窗口。 建议:15 位纯数字 ITF / Interleaved 2 of 5 设备码场景应传 formats: ['itf'], minBarcodeLength: 15;iOS 会同时启用 itf14interleaved2of5,避免只支持 ITF-14 导致普通 ITF 无法识别。

Android 对长而细的一维码提供小占比识别兜底:当 Code128、Code39、EAN、UPC、ITF 等条码占画面比例较小、整帧首轮没有结果时,插件会在后台对可见扫码区域做节流的裁剪放大重试;相册整图首轮无结果时也会对中心区域有限重试。该兜底不会替代清晰成像,工业平板仍建议让条码横向占扫码框宽度约 60%~80%、避免反光,并在已知码制时只传目标 formats

Data Matrix / 反色 DM 码说明

识别 DM 码时建议显式传 formats: ['dataMatrix'],减少 Android ML Kit 与 iOS Vision 的无关码制候选。

Android Data Matrix 识别链包含中心裁剪与反色兜底,并已升级 Android 原生依赖以兼容 16 KB page size;ML Kit 帧回调在 cameraExecutor 执行并对 DM Bitmap 兜底节流,避免进入预览后出现预览卡顿,同时修复扫码成功后退出全屏界面时晚到回调触发 RejectedExecutionException 的闪退问题:

  1. 常规整帧识别无结果时,会按可视扫码框做中心裁剪后再次识别,让 DM 码更接近 ML Kit 输入图中心。
  2. 中心裁剪仍无结果时,会对裁剪图做反色重试,用于黑底白点这类反色 DM 码。
  3. 该增强仅在请求包含 dataMatrix 或未限制码制时启用;未限制码制时已做低频兜底节流,不影响普通二维码/条形码主链路的实时预览。
  4. 反色 DM 码仍受清晰度、反光、焦距、打标质量影响;建议客户提供实物样张做 Android 真机确认。

示例:

import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'

LizhaoScanPro.startScan({
  scannerId: 'dm-main',
  // DM / Data Matrix 码制固定这样传,大小写需保持 dataMatrix
  formats: ['dataMatrix'],
  // 近距离小码建议开启近距锁焦
  nearFocusLock: true,
  // 现场较暗时可打开手电
  enableTorch: true,
  onResult(res) {
    console.log('DM扫码结果', res.results[0].value)
  },
  onError(err) {
    console.error('DM扫码失败', err)
  },
  onOverlayEvent(event) {
    console.log('扫码诊断事件', event)
  },
  overlayConfig: {
    enabled: true
  }
})

连续扫描说明

continuous=true 时,扫码界面保持打开并持续返回 onResult,适用于批量入库、流水线录入等场景。
可选传 continuousIntervalMs 控制连续回调最小间隔(默认 0,即不额外延迟)。 当 continuousIntervalMs 传入负数或无效值时,按 0 处理。

建议:

  1. 业务侧对 onResult 做去重或节流(插件内部会对相同码值做约 900ms 短窗口去重,但建议业务侧保底)。
  2. 在页面 onHide/onUnload 中调用 stopScan/destroyScanner 主动释放会话。
  3. 若业务需要同帧多码,请传 returnAllResults=true 并按 res.results 批量处理。

相册识别说明(Android / iOS / Harmony)

startScan(options) 中设置 enableAlbum=true 后,原生扫码界面右上角会显示相册按钮。 点击该按钮后会拉起系统图片选择器,识别成功后复用 startScanonResult 回调返回结果。

Android / iOS 扫码页面按钮文案(Harmony 以系统页面为准):

  1. 左上角:关闭
  2. 右上角(启用相册时):相册
  3. 底部操作区(showContinuousToggle=true 时):单次扫码 / 连续扫码打开手电筒 / 关闭手电 同一行左右并排、整体居中
  4. 底部中间(showContinuousToggle=false 且设备支持闪光灯时):打开手电筒 / 关闭手电
  5. Android / iOS 支持点击扫码画面触发重新聚焦(启动时也会自动执行一次近景优先聚焦)
  6. Android / iOS 点击对焦时会显示短暂聚焦提示框,便于确认“已触发对焦”
  7. Android / iOS 传 nearFocusLock=true 时,会保持近距辅助缩放策略,提升近距离(约 5cm)对焦稳定性
  8. Android / iOS 传 showActionCapsuleBackground=false 时,可关闭“关闭/相册/单次连续/手电”按钮胶囊背景

pickImageAndScan(options) 会拉起系统图片选择器,用户选图后由插件原生链路解析条码/二维码。

说明:

  1. Android 一般无需额外存储权限(使用系统 Picker 返回授权 URI);iOS 走系统相册选择器并受 NSPhotoLibraryUsageDescription 约束;Harmony 走系统扫码页相册入口,权限与系统实现保持一致。
  2. 识别成功时会触发 options.onResult,并回调 options.success/complete
  3. 用户取消选择时返回 9010008
  4. 图片中无可识别码时返回 9010006
  5. 如需识别成功提示音/短震动,请在 startScanpickImageAndScan 中传 beepOnScan/vibrateOnScan=true(默认 false);Harmony 当前暂不承诺震动/提示音生效,以系统扫码页行为为准。
  6. returnAllResults=true 在 Android 相册识别生效;iOS/Harmony 相册识别当前仍返回单条结果。

示例:

import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'

LizhaoScanPro.pickImageAndScan({
  // 扫描会话 ID(用于区分不同业务会话)
  scannerId: 'main',
  // 指定相册识别格式,减少无关格式扫描开销
  formats: ['qrCode', 'code128', 'ean13'],
  // 识别成功时播放提示音
  beepOnScan: true,
  // 识别成功时触发短震动
  vibrateOnScan: true,
  // 识别成功回调
  onResult(res) {
    console.log('album scan result', res)
  },
  // 识别失败回调(如 9010006 / 9010008)
  onError(err) {
    console.error('album scan error', err)
  }
})

Overlay 事件类型

onOverlayEvent 回调事件结构:

{
  type: string,
  scannerId: string,
  payload: any
}
事件 type payload 类型 说明
overlayReady string | null 遮罩事件通道初始化完成,payload 为 overlayConfig.htmlUrl(如未配置则为 null
shown null 原生扫码全屏界面已显示
cameraReady null 相机预览与分析链路已绑定完成
albumClick null 点击右上角相册按钮后触发(需 enableAlbum=true
albumRecognized string 通过右上角相册入口识别成功,payload 为识别字符串
focusTapped string | object 点击预览触发聚焦后回传;Android 为 "x,y",iOS 为坐标对象
recognized string 识别到码内容,payload 为识别字符串
continuousChanged object 原生页模式切换事件,payload 固定为 { continuous: boolean, source: "nativeToggle" }
paused null 调用 pauseScan 后触发
resumed null 调用 resumeScan 后触发
buildInfo string Android / iOS 原生扫码页当前构建标识(用于确认真机运行到的插件版本)
error string 原生扫码过程异常,payload 为错误文本
closed null 原生扫码界面已关闭并释放
nativeMessage any 调用 postOverlayMessage 后回传的消息内容

说明:上述事件仅在 overlayConfig.enabled=true 时派发。

Overlay 事件处理示例

import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'

LizhaoScanPro.startScan({
  // 扫描会话 ID
  scannerId: 'main',
  // 限定识别格式,提升识别稳定性和效率
  formats: ['qrCode', 'code128'],
  // 连续扫码模式(扫码页不会自动关闭)
  continuous: true,
  // 启用右上角相册入口
  enableAlbum: true,
  // 近距锁焦(Android/iOS)
  nearFocusLock: true,
  // 隐藏默认扫码框,仅保留扫描线
  showScanFrame: false,
  // 开启 overlay 事件通道(onOverlayEvent 才会触发)
  overlayConfig: {
    enabled: true
  },
  // 识别成功回调
  onResult(res) {
    console.log('scan result', res)
  },
  // 识别失败回调
  onError(err) {
    console.error('scan error', err)
  },
  // 原生层事件回调(shown/cameraReady/recognized/...)
  onOverlayEvent(event) {
    switch (event.type) {
      case 'shown':
        console.log('scanner shown')
        break
      case 'cameraReady':
        console.log('camera ready')
        break
      case 'recognized':
        console.log('recognized payload:', event.payload)
        break
      case 'continuousChanged':
        console.log('mode changed:', event.payload)
        break
      case 'error':
        console.warn('overlay error:', event.payload)
        break
      case 'closed':
        console.log('scanner closed')
        break
      case 'nativeMessage':
        console.log('native message:', event.payload)
        break
      default:
        console.log('overlay event:', event)
        break
    }
  }
})

返回值说明(ScanFrameResult)

字段 类型 说明
scannerId string 扫描器 ID
timestamp number 时间戳
frameIndex number 帧序号
results Array 当前帧结果列表(默认 1 条;returnAllResults=true 时可返回多条)

错误码说明

错误码 含义 说明
9010001 platform unsupported 当前平台不支持
9010002 camera permission denied 相机权限不足
9010003 album permission denied 相册权限不足
9010004 camera init failed 相机流程失败
9010005 format not supported 格式配置不合法
9010006 album decode failed 相册图片识别失败(无码或解码异常)
9010007 overlay reserved 预留错误码,当前版本不触发
9010008 scan aborted 扫码被中止
9010009 invalid options 参数不合法
9010010 system error 系统异常
9010011 scanner id occupied scannerId 已被其他全屏或嵌入式组件会话占用
9010012 scanner component unavailable 组件未就绪、已销毁或目标组件不存在

权限说明

  • Android:CAMERAFLASHLIGHTVIBRATE(相册识别走系统 Picker,通常不需要额外存储权限)
  • iOS:NSCameraUsageDescriptionNSPhotoLibraryUsageDescription(扫码与相册识别)
  • Harmony:依赖系统扫码能力与系统权限弹窗策略

自定义基座说明

新增以下配置时需要自定义基座:

  • Android CameraX / ML Kit 依赖
  • AndroidManifest 权限
  • Android utssdk/app-android/ScanCaptureNative.kt 原生链路变更
  • iOS Info.plist / PrivacyInfo.xcprivacy
  • iOS utssdk/app-ios/index.utsScanIosBridge.swiftScanEmbeddedNative.swift 原生链路变更
  • Android/iOS utssdk/*/index.vue component-uts 原生组件入口变更

本插件 Android 端严格使用自研链路(UTS + CameraX + ML Kit),不依赖 Barcode/uni-barcode-scanning 模块兜底。

如果直接使用普通调试基座运行,Android 侧可能出现 androidx.camera.*com.google.android.gms.tasks.* 类缺失,表现为无法打开扫码界面。此时必须重新编译并安装自定义基座或原生安装包。 当前发布包会通过 buildInfo 返回运行诊断标识。完全自由布局原生扫码组件保留 Android 全屏关闭与迟到回调隔离、JS 回调桥接、组件事件主线程派发,以及“嵌入式自由布局 → 原生全屏 → 返回恢复”示例;当前发布同时包含 iOS 聚焦、Vision 视频帧和 Swift 类型桥接兼容修复。Android 16 KB page size、预览卡顿、扫码成功后退出闪退、HarmonyOS 4.2 Android 兼容层桥接修复、参数强转修复与本次组件会话均涉及自定义基座内的原生/平台代码;Android/iOS 发布或真机验证前需要重新原生联编、重新云打包或制作并安装对应平台当前插件自定义基座/正式包。全屏链路可通过 onOverlayEventbuildInfo 确认真机运行构建,组件可通过 ready/getState()buildInfo 确认嵌入式实现构建。

Android 16 KB page size 说明:

  1. 旧版 androidx.camera:camera-core:1.3.3 会带入 libimage_processing_util_jni.so,旧版 com.google.mlkit:barcode-scanning:17.2.0 会带入 libbarhopper_v3.so;这两个库在旧调试包中均可能表现为 4 KB ELF 对齐,从而触发 Google Play 的 16 KB page size 检查。
  2. 当前版本已将 CameraX 升级到 1.4.2,将 ML Kit Barcode Scanning 升级到 17.3.0;重新打包后应以最终 AAB/APK 中的 .so 为准再次验证。
  3. 只替换 uni_modules 文件但不重新制作 Android 自定义基座,设备和上架包仍可能使用旧 .so,无法解决 Google Play 拦截。

建议步骤:

  1. 在 HBuilderX 执行「运行 -> 运行到手机或模拟器 -> 制作自定义基座」。
  2. 卸载设备上旧基座后安装新基座(避免继续复用旧依赖)。
  3. 清理项目编译缓存后重新运行。

完整组合示例(uni-app)

如果已经跑通前面的最小示例,可以参考下面的组合写法一次性启用多码识别、连续扫码、相册入口、自定义文案和图片图标。完整页面示例可查看 uni_modules/lizhao-scan-pro/example/index.vue 或项目页面 uni_modules/lizhao-scan-pro/example/uniapp/scan.vue

import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'

const info = uni.getSystemInfoSync()
const platform = String(info.platform || '').toLowerCase()
if (platform !== 'android' && platform !== 'ios' && platform !== 'harmony') {
  console.warn('lizhao-scan-pro 当前仅支持 Android/iOS/Harmony')
  return
}

LizhaoScanPro.startScan({
  // 扫描会话 ID;建议页面内固定值
  scannerId: 'main',
  // 仅识别二维码和 code128
  formats: ['qrCode', 'code128'],
  // 同帧多码回传(默认 false)
  returnAllResults: true,
  // 连续扫码模式
  continuous: true,
  // 连续回调最小间隔(ms)
  continuousIntervalMs: 500,
  // 显示“单次/连续”切换按钮
  showContinuousToggle: true,
  // 隐藏操作胶囊背景(保留按钮能力)
  showActionCapsuleBackground: false,
  // 显示相册入口
  enableAlbum: true,
  uiTextConfig: {
    // 底部提示图标(emoji 或文本图标)
    tipIcon: '📷',
    // 底部提示文案
    tipText: '请对准二维码',
    // 左上角关闭按钮图标/文案
    closeIcon: '✕',
    closeText: '关闭',
    // 右上角相册按钮图标/文案
    albumIcon: '🖼',
    albumText: '相册',
    // 底部手电按钮图标/开关文案
    torchIcon: '🔦',
    torchOnText: '关闭手电',
    torchOffText: '打开手电筒'
  },
  uiImageConfig: {
    // 可传本地路径、file://、content://、data URI、static 资源路径
    // 彩色图标建议不传 tintColor;需要统一单色时再传 tintColor(如 #FFFFFF)。
    close: { src: 'static/scan-icons/close.png', width: 18, height: 18 },
    album: { src: 'static/scan-icons/album.png', width: 18, height: 18 },
    torchOn: { src: 'static/scan-icons/torch-on.png', width: 16, height: 16 },
    torchOff: { src: 'static/scan-icons/torch-off.png', width: 16, height: 16 },
    tip: { src: 'static/scan-icons/tip.png', width: 18, height: 18 }
  },
  // 识别成功回调(returnAllResults=true 时 res.results 可能有多条)
  onResult(res) {
    res.results.forEach((item) => {
      console.log(item.value, item.format)
    })
  },
  // 识别失败回调
  onError(err) {
    console.error(err)
  }
})

页面生命周期建议

onHide() {
  // 页面不可见时先停扫码(避免后台占用相机)
  LizhaoScanPro.stopScan({ scannerId: 'main' })
}

onUnload() {
  // 页面销毁时彻底释放扫描器资源
  LizhaoScanPro.destroyScanner({ scannerId: 'main' })
}

完整组合示例(uni-app x)

uni-app x 同样通过插件根目录导入 API。下面示例展示扫码启动后再动态控制手电和缩放,适合需要在页面按钮中调整扫码状态的场景。

import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'

const info = uni.getSystemInfoSync()
const platform = String(info.platform || '').toLowerCase()
if (platform !== 'android' && platform !== 'ios' && platform !== 'harmony') {
  console.warn('lizhao-scan-pro 当前仅支持 Android/iOS/Harmony')
  return
}

LizhaoScanPro.startScan({
  // 扫描会话 ID(需与后续 setTorch/setZoom 一致)
  scannerId: 'main',
  // 开启连续扫码,便于演示动态调参
  continuous: true,
  // 显示手电按钮(部分业务可选)
  enableTorch: true,
  onResult(res) {
    console.log('uni-app x scan result', res)
  },
  onError(err) {
    console.error('uni-app x scan error', err)
  }
})

// 动态打开手电(仅设备支持时生效)
LizhaoScanPro.setTorchEnabled({
  scannerId: 'main',
  enabled: true
})

// 动态设置缩放倍率(>0)
LizhaoScanPro.setZoomRatio({
  scannerId: 'main',
  zoomRatio: 1.8
})

// 页面离开时释放资源(示例)
// onHide() {
//   LizhaoScanPro.stopScan({ scannerId: 'main' })
// }
// onUnload() {
//   LizhaoScanPro.destroyScanner({ scannerId: 'main' })
// }

联系方式

信-微:l-z-1-8-7-1512-5421(-去掉,不这样写会被和谐)

发布前自检清单

  1. 确认插件仅通过 @/uni_modules/lizhao-scan-pro API 入口调用。
  2. 确认未使用 <lizhao-scan-pro /> 模板标签或 common/*.js 旧入口。
  3. 确认 Android 自定义基座已重建并重装(含 CameraX + ML Kit 依赖)。
  4. 确认扫码页在 Android 真机可拉起全屏原生界面并返回结果。
  5. 确认 iOS 与 Harmony 真机均可拉起扫码并返回结果;Web/小程序路径返回 9010001 且文档说明一致。

作者系列UTS插件

以下为已在 DCloud 插件市场上架的作者系列 UTS 插件,可按业务场景组合使用。未列出的插件表示当前未确认公开市场页,后续上架后再补充。

插件 能力方向 插件市场
lizhao-nfc-pro NFC 标签读写、NDEF、IsoDep 与诊断 查看插件
lizhao-float-window 悬浮窗、画中画、权限与诊断 查看插件
lizhao-device-id 设备标识、隐私策略与诊断 查看插件
lizhao-scan-pro 原生扫码、连续扫码、相册识别 查看插件
lizhao-choose-file 原生文件选择、上传、进度与取消 查看插件
lizhao-bg-audio 背景音频播放、队列、倍速与事件 查看插件
lizhao-smart-tts 系统 TTS、云端合成、听书方案 查看插件
lizhao-share-plus 系统分享、远程文件下载后分享 查看插件
lizhao-sqlite-pro 原生 SQLite、迁移、备份与诊断 查看插件
lizhao-icon-pro SVG 图标组件、多主题与缓存 查看插件
lizhao-cast-screen DLNA 投屏、AirPlay 路由入口 查看插件
lizhao-call-kit 电话、短信、通讯录原生能力 查看插件
lizhao-app-keepalive 应用保活、唤醒、自愈与报告 查看插件
lizhao-doc-corrector 文档扫描、矫正、增强与识别 查看插件
lizhao-emu-detect 模拟器环境检测、风险评分与证据 查看插件
lizhao-gallery-pro 相册媒体分页、筛选、缩略图与导出 查看插件
lizhao-video-thumb 视频封面、批量取帧与 Base64 返回 查看插件
lizhao-ble BLE 扫描、连接、读写、通知与自动重连 查看插件
lizhao-sse-pro SSE、Line、JSONL 与 Raw 流式请求 查看插件

隐私、权限声明

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

相机、震动

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

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