更新记录
1.0.93(2026-10-27)
- 修复普通授权及试用版升级后,Android 引擎发行版本未同步导致选择命令误报“加密发行合同缺失或版本不匹配”的问题。
- 明确每次重新导入或升级插件后,需要重新执行 Android 引擎选择命令;检查命令默认按项目 JSON 配置验证,避免检查时意外指定其他引擎。
- 更新后请完整导入插件,重新应用引擎配置,再制作并安装匹配的 Android 自定义基座或正式 App;本次不改变扫码 API、识别逻辑及 iOS / Harmony 能力。
1.0.92(2026-10-27)
- 修复 HarmonyOS 多张图片识别中可选配置与完成回调字段缺失导致的 ArkTS 编译失败。
- 修复批量识别错误消息缺省时的类型不匹配,保留显式错误消息、串行识别、取消和结果汇总行为。
1.0.91(2026-10-26)
- 修复普通授权及试用版执行 Android 引擎选择命令时,因 Kotlin 文件已加密而误报“尚未更新为中立引擎入口”或“未知本地修改”的问题。
- 保留源码版的旧版本检查和本地修改保护;加密包首次切换自动保存原始文件,后续切换继续检查实际文件身份,失败时恢复本次改动。
- 请完整更新插件后重新执行引擎选择命令;变更打入的 SDK 后,仍需重新制作并安装 Android 自定义基座或正式 App。扫码 API、Android 原生识别逻辑及 iOS / Harmony 能力不变。
平台兼容性
uni-app(4.84)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | - | - | √ | √ | 6.0 | √ | √ |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
uni-app x(4.84)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | 6.0 | √ | √ | - |
lizhao-scan-pro
介绍
lizhao-scan-pro 为 uni-app / uni-app x 提供全屏扫码、页面内扫码和本地图片多码识别,适用于录入、盘点、核销与图片标签提取。
功能特色
| 特色功能 | 能解决什么问题 | 相关配置 |
|---|---|---|
| 扫码自动抓图 | 扫到快递条码时自动保留相机画面,拿到图片即可上传后端识别 | captureOnSuccess |
| 原生全屏扫码 | 不依赖页面组件拼装,直接使用平台原生相机能力 | startScan |
| 多码制识别 | 支持二维码、Data Matrix、PDF417、Code39、Code128、EAN、UPC 等常见码制 | formats |
| 同帧多码返回 | 一张画面中多个码可一次性回传 | returnAllResults |
| 连续扫码 | 适合盘点、核销、批量入库等高频扫码场景 | continuous、continuousIntervalMs |
| 业务采集清单 | 本次去重、逐码确认、超时恢复,完成后取得已接收清单 | startScanSession、resolveScanItem |
| 多码人工选择 | Android / iOS 全屏支持跨帧补扫;稳定多码后冻结画面,由用户确认需要的结果 | enableMultiCodeSelection |
| 近距聚焦增强 | 改善细小码、设备铭牌、近距离扫码体验 | nearFocusLock、zoomRatio |
| 远码自动拉近 | 检测到远处小码时逐步放大辅助识别,显式模式默认关闭 | autoZoom(Android ML Kit / iOS) |
| 密集二维码补救 | Android 默认 ML Kit 普通全屏 QR/all 持续未识别时,自动尝试候选拉近与高清识别 | 无需新增参数 |
| 相册识别 | 支持从本地图片中识别码 | enableAlbum、pickImageAndScan |
| 图片文件识别 | 传入已有本地图片路径,直接取得图中多条已识别结果 | scanImage |
| 多张图片识别 | 逐张处理标签与截图,查看进度、失败项并取消任务 | scanImages、cancelScanImages |
| 扫码页自定义 | 支持扫码框、遮罩、扫描线、文案、图片图标和布局偏移配置 | scanFrameStyle、uiTextConfig、uiImageConfig、uiLayoutConfig |
| 完全自由布局 | 原生预览嵌入 .nvue/.uvue,页面自由编写扫码框、按钮和业务区 |
<lizhao-scan-pro /> |
适合哪些场景
| 场景 | 推荐能力 | 说明 |
|---|---|---|
| 快递面单识别 | captureOnSuccess、uni.uploadFile |
无需手动拍照,扫码成功后拿到图片并上传自己的后端 |
| 普通扫码 | startScan |
打开全屏扫码页,识别成功后回调结果 |
| 商品条码/库存盘点 | formats、minBarcodeLength、continuous |
限制条码类型、过滤短码、连续返回结果 |
| 唯一标签盘点、票券逐码校验 | startScanSession |
自动接收或等待业务确认,只汇总已接收内容 |
| 一屏多个码 | returnAllResults |
同一帧内返回多条识别结果,适合货架、票据、批量标签 |
| 一屏多个码由用户选择 | enableMultiCodeSelection |
Android / iOS 单次全屏扫码和嵌入式组件支持冻结画面后由用户确认要返回的码 |
| 相册识别 | enableAlbum、pickImageAndScan |
支持从图片中识别二维码或条形码 |
| 已有图片、下载后的标签图 | scanImage |
不打开选图界面,从可读本地文件中识别单条或多条码 |
| 近距离扫码 | nearFocusLock、zoomRatio |
适合约 5cm 近距标签、设备码、细小条码 |
| 品牌化扫码页 | scanFrameStyle、uiTextConfig、uiImageConfig、uiLayoutConfig、uiVisibilityConfig |
自定义扫码框、文案、图标、按钮位置和元素显隐 |
| 完全自由布局 | <lizhao-scan-pro /> |
原生预览嵌入客户页面,扫码框、按钮与业务 UI 全部由页面决定 |
| 页面状态联动 | pauseScan、resumeScan、stopScan、destroyScanner |
页面隐藏、返回、销毁时控制相机资源 |
下载与导入
- 在插件市场选择“使用 HBuilderX 导入插件”,导入到自己的 uni-app 或 uni-app x 项目。
- 保留完整的
uni_modules/lizhao-scan-pro目录和插件名称。示例页面可复制到自己的页面目录,组件及辅助模块统一通过@/uni_modules/lizhao-scan-pro/引入。 - 在页面脚本中从插件根目录导入:
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
Android 最低支持 Android 6.0(API 23)。云打包前,请在项目 manifest.json 的以下位置设置 minSdkVersion 为数字 23;如果已有值更高,请保留较高值。
| 项目类型 | manifest.json 配置位置 |
最低值 |
|---|---|---|
| uni-app | app-plus.distribute.android.minSdkVersion |
23 |
| uni-app x(HBuilderX 4.71 及以上) | app-android.distribute.minSdkVersion |
23 |
修改该配置后,请重新云打包自定义基座或正式 App。设置 targetSdkVersion 或升级 HBuilderX 不能代替这项配置,请勿使用 tools:overrideLibrary 跳过最低系统版本检查。
Android 云打包请使用 HBuilderX 5.09 及以上。插件当前使用 CameraX 1.6.1,该依赖要求 compileSdk 36;HBuilderX 5.07 / 5.08 的云打包环境使用 compileSdk 35,会在依赖检查阶段失败。这里要求的是打包环境版本,不表示手机必须是 Android 16,也不要求把项目的 minSdkVersion 或 targetSdkVersion 改为 36。
uni-app 使用普通页面脚本,uni-app x 使用 <script setup lang="uts">。两者调用同名 API,下面分别给出基础示例。
完整示例位于插件的 uni_modules/lizhao-scan-pro/example/ 目录下,按项目类型选择对应子目录:
- uni-app:
example/uniapp/,API 调用见 scan.vue,自由布局见 free-layout.nvue。 - uni-app x:
example/uniappx/,API 调用见 index.uvue,自由布局见 free-layout.uvue。
5 分钟跑通:用 API 打开扫码页
默认推荐使用 API 调用。 通过 startScan() 即可打开带相机预览、扫码框和操作按钮的全屏扫码页,不需要自己编写扫码组件。先跑通下面的基础示例,再按业务需要添加连续扫码、多码选择、相册或样式配置。
uni-app:按钮点击后打开扫码
把下面内容放到一个已注册的 .vue 页面。点击按钮、对准二维码,识别后会显示扫码内容。
<template>
<view>
<button @tap="openScanner">开始扫码</button>
<text>{{ scanText }}</text>
</view>
</template>
<script>
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
export default {
data() {
// 保存本次识别到的内容。
return { scanText: '' }
},
onUnload() {
// 页面销毁时释放该页面的扫码会话。
LizhaoScanPro.destroyScanner({ scannerId: 'main' })
},
methods: {
openScanner() {
LizhaoScanPro.startScan({
scannerId: 'main',
onResult: (res) => {
const first = res.results[0]
if (first != null) this.scanText = first.value
},
onError: (err) => {
// 取消扫码无需提示为故障。
if (err.errCode === 9010008) return
uni.showToast({ title: err.errMsg, icon: 'none' })
}
})
}
}
}
</script>
uni-app x:相同 API,使用 UTS 脚本
<template>
<view>
<button @tap="openScanner">开始扫码</button>
<text>{{ scanText }}</text>
</view>
</template>
<script setup lang="uts">
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
// 保存本次识别到的内容。
const scanText = ref<string>('')
function openScanner(): void {
LizhaoScanPro.startScan({
scannerId: 'main',
onResult: (res) => {
const first = res.results[0]
if (first != null) scanText.value = first.value
},
onError: (err) => {
if (err.errCode === 9010008) return
uni.showToast({ title: err.errMsg, icon: 'none' })
}
})
}
onUnload(() => {
LizhaoScanPro.destroyScanner({ scannerId: 'main' })
})
</script>
读取结果用 res.results[0].value。 results 是数组,每一项的 value 是识别内容,format 是码制。默认单次扫码;基础调用正常后,再增加下面需要的配置。
核心配置
首次使用只需关注这些参数。未填写的配置使用默认值,详细字段放在后面的查询表中。
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| formats | Array<ScanFormat> | 否 | 限制需要识别的码制 | ["all"] |
all / qrCode / code128 / dataMatrix / 其他支持码制 |
| continuous | boolean | 否 | 是否持续返回扫码结果 | false |
true / false |
| returnAllResults | boolean | 否 | 是否返回同一帧的全部有效结果 | false |
true / false |
| captureOnSuccess | boolean | 否 | Android / iOS / Harmony 全屏扫码成功自动保存完整 JPG,成功回调附带图片路径与尺寸;不可与多码点击选择组合,不用于相册识别 | false |
true / false |
| enableMultiCodeSelection | boolean | 否 | 单次扫码时是否允许用户从多个候选中选择;Harmony 当前不支持 | false |
true / false |
| enableAlbum | boolean | 否 | 全屏扫码页是否提供相册入口 | false |
true / false |
| nearFocusLock | boolean | 否 | 是否启用近距辅助锁焦 | false |
true / false |
接入方式选择
| 你的需求 | 推荐方式 | 阅读位置 |
|---|---|---|
| 普通扫码、核销、录入 | 默认推荐:startScan(options) |
快速开始、模块一 |
| 连续录入、同帧批量返回 | 继续使用 startScan(options),增加配置 |
模块二 |
| 本次去重、逐码确认、结束后拿清单 | startScanSession(options) |
下文“独立模块:批量盘点与逐码校验” |
| 从多个码中确认一个 | 继续使用 startScan(options),启用人工选择 |
模块三 |
| 打开相册选图后识别 | pickImageAndScan(options) |
模块四 |
| 已有图片文件路径,直接识别 | scanImage(options) |
下文“独立模块:从已有图片路径识别” |
| 改文案、按钮、颜色或扫码框 | 继续使用全屏 API 的样式配置 | 模块五 |
| 整个页面布局和业务区都自己编写 | 进阶使用嵌入式组件 | 后文“完全自由布局组件” |
从基础到进阶:按业务模块使用
以下 API 示例放在页面按钮事件或业务方法中调用;一次只打开一个扫码会话。可以把所需配置合并到上面的 openScanner,保留自己的结果和错误处理。
模块一:只识别业务需要的码
适合商品条码、设备标签或只允许二维码的入口。指定 formats 后,只接收对应码制的结果。
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
LizhaoScanPro.startScan({
scannerId: 'main',
// 只识别二维码和 Code128,减少无关码制干扰
formats: ['qrCode', 'code128'],
onResult(res) {
const first = res.results[0]
if (first != null) {
console.log('命中指定码制:', first.value)
}
}
})
formats 中使用 qrCode 表示二维码,code128 表示 Code128,ean13 表示 EAN-13;不确定码制时先保留默认的 ['all']。
模块二:连续扫码和批量返回
适合入库、盘点等需要持续扫描的场景。下面每次最多返回当前画面中全部有效结果,回调间隔至少 500 毫秒。
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
LizhaoScanPro.startScan({
scannerId: 'main',
// 开启连续扫码,适合仓储、盘点、核销等连续作业
continuous: true,
// 两次回调至少间隔 500ms,业务侧也建议继续做去重
continuousIntervalMs: 500,
// 同一帧出现多个码时返回全部识别结果
returnAllResults: true,
onResult(res) {
res.results.forEach((item) => {
console.log('批量结果:', item.value, item.format)
})
}
})
只需每次返回一个码时,去掉 returnAllResults 即可。continuousIntervalMs 控制回调频率,不能代替业务去重;同一商品是否允许重复入库,应由业务处理。Harmony 的连续扫描和批量返回差异见后文平台说明。
独立模块:批量盘点与逐码校验
适合“逐个扫描标签,完成后拿到一份清单”,或“先向自己的后端校验,通过后才接收”。普通连续扫码仍使用上面的 startScan;需要插件管理去重、待确认项和本次汇总时,单独调用 startScanSession。
两端完整示例首页均有独立的“批量盘点与核销”卡片:uni-app、uni-app x。卡片提供去重盘点、本地异步校验、一次超时恢复和汇总复制,接收满 20 条自动结束。校验演示只检查 TICKET- 前缀,不会请求后端或执行真实核销。
唯一标签盘点:同一码只记一次
例如每件资产都有不同的二维码,本次只需采集一遍。扫码页点“完成”返回;onSessionEnd 中取得完整的已接收清单,再由业务决定保存或提交。
import { startScanSession, finishScanSession } from '@/uni_modules/lizhao-scan-pro'
let inventorySessionId = ''
function startInventory() {
if (inventorySessionId.length > 0) return
inventorySessionId = startScanSession({
scannerId: 'inventory',
duplicateStrategy: 'session',
duplicateKey: 'format-value',
maxItems: 100,
onSessionEnd: (summary) => {
inventorySessionId = ''
// accepted 中每项的 candidate.result.value 是扫码内容。
console.log('本次清单', summary.accepted)
console.log('接收数量', summary.acceptedCount)
},
onError: (error) => {
uni.showToast({ title: error.errMsg, icon: 'none' })
}
})
}
function leaveInventory() {
if (inventorySessionId.length > 0) finishScanSession(inventorySessionId)
inventorySessionId = ''
}
把 startInventory 绑定到开始按钮;页面 onUnload 调用 leaveInventory,组件则在卸载时调用。不要因为原生扫码页覆盖业务页而在 onHide 中结束本次采集。同款商品按数量重复扫描时,可改用 duplicateStrategy: 'allow';它允许再次接收,但仍受原生识别器自身的重复抑制和处理速度限制,不会每帧回调。
逐码校验:后端明确通过后再接收
开启 validateEachScan 并提供 onCandidate。每次识别后暂停接收新候选,业务调用 resolveScanItem 确认当前项;通过后加入清单,拒绝或超时后可重新扫描。下面是 uni-app 的请求示例,先填写自己的 HTTPS 接口;示例约定后端返回 JSON { "accepted": true } 才表示业务通过。
import { startScanSession, resolveScanItem, finishScanSession } from '@/uni_modules/lizhao-scan-pro'
let verifyUrl = '' // 填写自己的 HTTPS 校验接口,并按业务添加登录态。
let ticketSessionId = ''
function startTicketScan() {
if (ticketSessionId.length > 0) return
if (!verifyUrl.startsWith('https://')) {
uni.showToast({ title: '请先填写自己的 HTTPS 校验接口', icon: 'none' })
return
}
ticketSessionId = startScanSession({
scannerId: 'tickets',
validateEachScan: true,
validationTimeoutMs: 10000,
duplicateStrategy: 'session',
maxItems: 100,
onCandidate: (candidate) => {
uni.request({
url: verifyUrl,
method: 'POST',
dataType: 'text',
timeout: 8000,
data: { code: candidate.result.value, requestId: candidate.itemId },
success: (response) => {
let accepted = false
try {
const body = JSON.parse(String(response.data))
accepted = response.statusCode >= 200 && response.statusCode < 300
&& body != null && body.accepted === true
} catch (error) { /* 非预期响应按未通过处理。 */ }
resolveScanItem({
sessionId: candidate.sessionId,
itemId: candidate.itemId,
accepted,
message: accepted ? '校验通过' : '未通过校验,请核对后重扫'
})
},
fail: () => {
resolveScanItem({
sessionId: candidate.sessionId,
itemId: candidate.itemId,
accepted: false,
message: '请求失败,请核对业务状态后重试'
})
}
})
},
onSessionEnd: (summary) => {
ticketSessionId = ''
console.log('校验通过的清单', summary.accepted)
},
onError: (error) => {
uni.showToast({ title: error.errMsg, icon: 'none' })
}
})
}
function leaveTicketScan() {
if (ticketSessionId.length > 0) finishScanSession(ticketSessionId)
ticketSessionId = ''
}
页面卸载时调用 leaveTicketScan。uni-app x 使用同名 API,在 <script setup lang="uts"> 中将上例的 JSON 解析和判断替换为下面的写法;仍保留外层 try/catch 和原有 resolveScanItem 调用:
const body = JSON.parseObject(response.data as string)
accepted = response.statusCode >= 200 && response.statusCode < 300
&& body != null && body!.getBoolean('accepted') == true
resolveScanItem 仅首次处理当前待确认项时返回 true;重复、迟到或已结束的回执返回 false。这只能阻止本地清单被旧回执修改,不能撤销已经发出的请求或后端操作;实际核销接口仍需自行实现幂等、超时后的状态查询和重复提交保护。
按业务选择规则
以下参数属于 ScanSessionOptions,不传入旧 ScanOptions。
| 配置 | 默认值 | 用途与范围 |
|---|---|---|
scannerId |
scan-business-session |
本页专用扫描器标识;同一时间只使用一个相机会话 |
androidEngine |
包内默认引擎 | 仅 Android,mlkit / huawei;整个会话使用启动时的选择,接入步骤见 Android 引擎模块 |
formats / minBarcodeLength |
['all'] / 0 |
限制码制、过滤短条码;新入口最小码长取 0~4096 的整数 |
autoZoom / nearFocusLock |
false / false |
复用原有平台的远码、近距能力 |
duplicateStrategy |
session |
session 本次已接受项去重;window 时间窗去重;allow 允许再次接收 |
duplicateKey |
format-value |
按码制与内容去重;改为 value 时仅按内容去重 |
duplicateWindowMs |
2000 |
仅 window 生效,从接受时计时;0~3600000 毫秒,整数;0 不做业务时间窗拦截 |
validateEachScan |
false |
false 自动接收;true 必须提供 onCandidate 并逐项回执 |
validationTimeoutMs |
10000 |
等待回执的上限;1000~60000 毫秒,整数;超时不加入清单 |
maxItems |
500 |
本次已接收条数上限;1~1000,整数;到达后自动结束 |
beepOnAccept / vibrateOnAccept |
false / false |
Android / iOS 业务接受后发出提示;Harmony 本轮仅提供文字反馈 |
拒绝和超时不进入去重记录;以后可重扫同一码。清单在当前会话内保存,结束时通过 onSessionEnd 一次交付,不是持久化存储。
| 回调或控制 | 使用结果 |
|---|---|
onCandidate(candidate) |
待确认项,包含 sessionId、itemId 与 result;仅逐码校验模式使用 |
onAccepted(item) |
已接收项,包含 candidate、acceptedAt、累计 acceptedCount |
onDuplicate(candidate) |
重复提示;最多每秒一次,duplicateCount 统计提示次数而非相机帧数 |
onRejected(event) |
reason 为 rejected 或 timeout,附带候选与提示文案 |
onStateChange(event) |
starting、scanning、waiting、paused、ended 状态变化 |
onSessionEnd(summary) |
完整 accepted 清单,以及接受、重复提示、拒绝、超时、结束未确认数量 |
finishScanSession(sessionId) |
请求完成本次采集;原生页“完成”按钮也可结束。返回 true 表示已接受结束请求,汇总由 onSessionEnd 异步通知 |
pauseScanSession / resumeScanSession |
业务暂停或恢复;暂停不会取消正在等待的校验,等待计时继续 |
结束原因 reason:主动调用完成为 finished,扫码页关闭为 closed,达到上限为 limit,启动或运行错误为 error。结束时的待确认项计入 cancelledPendingCount,不加入 accepted。同步参数/占用失败会返回空字符串并调用 onError,尚未创建会话时不会产生汇总。
请等 onSessionEnd 后再开始下一次采集,不要在调用 finishScanSession 后立即重新打开。Android / iOS 应用退到后台时暂停采集,已发出的校验仍可能完成并更新清单;后台回执或超时不会恢复相机,回到前台后才按待确认项和业务暂停状态决定是否继续。Harmony 扫码窗口隐藏或卸载时结束本次采集并返回已接收汇总,需要继续时重新开启一次会话。
本模块支持 Android / iOS / Harmony 全屏相机连续单码,不组合相册、多码点选、同帧全部返回、成功抓图或嵌入式组件;这些场景继续使用各自原有入口。Web / 小程序返回 9010001。首次使用前请安装包含 1.0.86 原生代码的自定义基座或 App 包;旧包不会因前端页面更新而具备新会话提示能力。
模块三:多个码中,由使用者选择一个
适合一张票据或货架上有多个码,但只需要确认其中一个的场景。开启后,Android / iOS 单次全屏扫码会显示可点击标记。
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
LizhaoScanPro.startScan({
scannerId: 'main',
continuous: false,
enableMultiCodeSelection: true,
// 从首个可靠结果起聚合最多约 300ms,减少识别后的等待
multiCodeDetectionWaitMs: 300,
onResult(res) {
console.log('用户选择的码:', res.results[0].value)
}
})
从 1.0.81 起,Android / iOS 全屏单次多码选择支持 multiCodeDetectionWaitMs,有效范围 200~3000ms。它从首个可靠扫码结果出现时开始计时;例如 300 表示最多聚合约 300ms,稳定多码可提前冻结供点选,到期仍只有单码则返回该结果。显式配置时,Android 不再追加高清补扫宽限或等待未解码的第二个码。较短的窗口响应更快,但较难识别的第二个码可能来不及进入选择。该参数不包含相机启动、首次识别、线程调度及用户点选耗时。
常见问题:开启多码选择后,为什么单码识别变慢?等待时间应该设置多少?
开启 enableMultiCodeSelection 后,插件在识别到第一个可靠码时不会立即返回,而是继续等待 multiCodeDetectionWaitMs,确认画面中是否还有第二个可选码。因此,单码场景主要是结果返回增加了聚合等待,并不代表第一个码本身识别变慢。以下建议适用于 Android / iOS 全屏 startScan:
| 建议值 | 适用场景 |
|---|---|
300ms |
单码响应优先;适合大多数画面只有一个码、偶尔需要多码选择的场景。 |
500ms |
速度与多码召回率更均衡;当 300ms 偶尔来不及收集第二个码时使用。 |
800~1000ms |
适合二维码较小、距离较远或多码召回优先的场景;单码会在首个可靠结果后明显多等约 0.8~1 秒。 |
如果客户已经反馈“单码慢了很多”,建议先设置 300ms,确认第二个码容易漏检时再提高到 500ms。1000ms 属于合理范围,但更偏向多码召回优先,不适合作为单码响应优先场景的首选值。业务绝大多数时候只扫一个码时,关闭 enableMultiCodeSelection 才能避免这段聚合等待。200ms 虽然是合法最小值,但留给第二个码的识别时间较短,通常先从 300ms 开始调试。
省略该参数、传 null 或非有限数值时保留旧策略:Android 在整个可见预览内聚合,基础窗口为 3000ms,高清补扫可延长至首码后的约 4.5/6 秒;默认 ML Kit 引擎若仍检测到独立的未解码第二码,会继续预览,确认只剩单码后才返回。华为引擎不等待未解码的第二码,按聚合及高清补扫窗口处理已解码结果。iOS 默认从首个结果起聚合最多约 3 秒,并用系统 Vision 补充带位置的候选。两端稳定多码均可提前冻结,未解码区域不会作为可选结果。有限数值向下取整并钳制到有效范围;显式 3000 也采用有界等待,不等同于省略参数。切换连续扫码或进入相册时恢复实时预览。
Android 默认使用 Google ML Kit,也可按“Android:打包前选择识别引擎”配置华为或双引擎;iOS 使用系统 Vision。变更打包配置后需重新制作并安装匹配的自定义基座或 App,双引擎包内通过参数选择本次识别无需再次打包。
与 returnAllResults=true 同时设置时,人工选择优先于 returnAllResults,最终只返回选中的一条结果。需要连续批量录入时使用模块二,不要开启人工选择。
模块四:从相册图片中识别
如果扫码页需要一个“相册”按钮,在 startScan 中加上 enableAlbum: true 即可,识别结果仍从同一个 onResult 返回。
如果业务入口就是“识别图片”,直接使用下面的 API,无需先调用 startScan:
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
LizhaoScanPro.pickImageAndScan({
scannerId: 'album',
onResult(res) {
const first = res.results[0]
if (first != null) console.log('图片识别结果:', first.value)
},
onError(err) {
if (err.errCode === 9010008) return
console.error('图片识别失败:', err.errMsg)
}
})
取消选图返回 9010008,图片中没有可识别码时返回 9010006。Android 相册识别支持 returnAllResults=true;iOS / Harmony 相册识别仍返回单条结果。Harmony 普通扫码页右上角可按 enableAlbum 显示相册入口;抓图模式不显示相册入口。
模块五:调整全屏扫码页外观
适合把扫码页改成自己的品牌风格。改扫码框、文案和按钮,仍然推荐使用 API,不需要改用组件。以下视觉配置用于 Android / iOS / Harmony 全屏扫码。
先改扫码框和文案
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
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) {
const first = res.results[0]
if (first != null) {
console.log('扫码结果:', first.value)
}
}
})
再按需要隐藏元素、修改多码标记
下面只显示必要操作与多码选择标记。启用相册需额外设置 enableAlbum=true;显示“单次/连续”切换按钮需设置 showContinuousToggle=true。
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
LizhaoScanPro.startScan({
scannerId: 'main',
enableMultiCodeSelection: true,
uiVisibilityConfig: {
showMaskOverlay: false,
showScanFrameBorder: false,
showScanFrameCorners: false,
showScanLine: false,
showTip: false,
showTorchButton: false,
showContinuousButton: false
},
multiCodeMarkerStyle: {
backgroundColor: '#16A34A',
foregroundColor: '#FFFFFF',
borderColor: '#FFFFFF',
size: 48,
cornerRadius: 24
},
onResult(res) {
console.log('扫码结果:', res.results)
},
onError(err) {
console.error('扫码失败:', err.errMsg)
}
})
使用自己的图片图标、调整位置
uni-app 与 uni-app x 示例的“图标+文案”使用相同的 ✖ 关闭 / 🖼 相册 / 🔦 打开手电筒 / 🎯 请对准二维码。这些字符由 uiTextConfig 配置,不依赖图片文件;只显示图标时保留相同字符并清空文案即可。
先在项目中放入 static/scan-close.png,再调用以下示例。无需替换插件源码。
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
LizhaoScanPro.startScan({
scannerId: 'main',
uiTextConfig: { closeText: '返回' },
uiImageConfig: {
close: { src: '/static/scan-close.png', width: 20, height: 20 }
},
uiLayoutConfig: {
close: { containerOffset: { x: 4, y: 4 } }
},
onResult(res) {
console.log('扫码结果:', res.results)
},
onError(err) {
console.error('扫码失败:', err.errMsg)
}
})
x 为正向右、y 为正向下;Android 按 dp、iOS 按 pt 处理。彩色图片通常不传 tintColor,单色图标需要统一颜色时再配置。
图片需要存在于当前运行项目;迁移到另一个项目时同时复制图片资源。iOS 支持直接传入 /static/、/uni_modules/ 下的图片路径;showActionCapsuleBackground 控制操作按钮背景,框下方提示气泡由 uiVisibilityConfig.showTip 控制。
远处小码自动拉近
Android 默认 ML Kit 引擎 / iOS 可通过 autoZoom: true 开启显式远码模式;Android 华为引擎当前不执行基于未解码候选的自动拉近。将目标放在画面中央,检测到小码候选后逐步拉近;iOS 在画面持续稳定、尚未检测到码框时,还会试探拉近一次,最高 1.5 倍。无需设置固定放大倍率,识别结果仍通过原有 onResult 返回。Android 默认 ML Kit 引擎普通全屏 QR/all 扫码还带有独立的密集二维码补救,即使未开启该参数,也可能在连续发现稳定未解码候选时受限拉近。
import { startScan } from '@/uni_modules/lizhao-scan-pro'
startScan({
scannerId: 'main',
formats: ['qrCode'],
autoZoom: true,
onResult(res) {
console.log('识别结果:', res.results)
},
onError(err) {
console.error('扫码失败:', err.errMsg)
}
})
内嵌组件使用 :auto-zoom="true",uni-app 的 .nvue 与 uni-app x 的 .uvue 均支持。完整示例的扫码配置区和自由布局页均提供默认关闭的“远码自动拉近”开关。
- 未传或设为
false时关闭显式远码模式;Android 普通全屏 QR/all 的密集二维码补救仍可能受限拉近。该补救不用于内嵌组件、近距锁焦、多码人工选择或混合指定码制。仅实时相机生效,相册识别不使用该配置;鸿蒙暂不支持此能力。 - 自动拉近遵循
formats:iOS 可使用系统返回的 QR、Aztec、Data Matrix、PDF417 及一维条形码候选。只识别 QR 时设置['qrCode'],只识别 Code128 时设置['code128'];需要多种码制时传入对应数组,或保留['all']。 zoomRatio作为起始倍率,自动拉近最高为 4 倍且不超过设备能力,不会主动缩小。手动设置倍率或点击聚焦后,本次扫码停止自动调整,重新开始扫码才恢复。- Android / iOS 在小码候选稳定出现后分步平滑拉近,每一步约半秒,并重新检查目标位置和相机实际倍率。尽量将码保持在画面中央,边缘目标会限制拉近幅度以避免移出画面。
- iOS 尚无有效候选时,独立观察实时画面的稳定性,持续稳定约 0.65 秒、至少三次有效观察后,可先试探拉近一次,绝对倍率不超过 1.5 倍;稳定观察不再等待完整的后备检测。画面移动、对焦中或画面缺乏纹理时重新等待,实际启动时间仍受设备和画面影响。试探后仍无码框则保持倍率,找到码框后继续跟踪;暂停恢复不会重复试探,已识别或已按候选拉近的会话也不再试探。
- iOS 单次扫码时,同一标签上相邻的小码可按一组逐步拉近,并保留整组的显示范围;分散且无法确定目标时等待重新对准。
- iOS 在系统已发现有效码框、尚未读出文字时也可开始拉近;扫码结果仍只在成功识别内容后返回。
- 开启
nearFocusLock或enableMultiCodeSelection时优先保留这两种模式,自动拉近不生效。暂停、退后台或选择相册时停止自动调整。 - 距离过远、反光、画面不稳定或摄像头能力不足仍可能无法拉近或识别,实际效果以设备为准。升级后需重新制作并安装对应平台自定义基座或重新打包。
模块六:识别近距离小码和 Data Matrix
适合设备铭牌、小标签等场景。可启用近距辅助聚焦并设置初始缩放;识别效果仍取决于相机焦距、画面清晰度和反光情况。
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
LizhaoScanPro.startScan({
scannerId: 'main',
// 开启近距辅助聚焦,实际距离按设备对焦能力调整。
nearFocusLock: true,
// 预设缩放倍率,帮助小码在画面中更清晰
zoomRatio: 1.8,
// 固定码长业务可过滤明显错误的短结果
minBarcodeLength: 8,
onResult(res) {
const first = res.results[0]
if (first != null) {
console.log('近距识别结果:', first.value)
}
}
})
minBarcodeLength 只用于一维条码最小长度过滤,按实际业务长度填写。二维码、Data Matrix 等二维格式不受该字段影响。
识别 Data Matrix(DM)时,改用下列配置:
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
LizhaoScanPro.startScan({
scannerId: 'dm',
formats: ['dataMatrix'],
nearFocusLock: true,
onResult(res) {
console.log('DM 识别结果:', res.results)
},
onError(err) {
console.error('DM 识别失败:', err.errMsg)
}
})
Android 支持反色 DM 识别增强,但不能保证所有材质、打标质量或光照下都能识别。让码清晰地位于画面中心,再根据实际标签调整距离和补光。
模块七:控制扫描、手电和缩放
适合业务需要暂停、继续或结束扫描的场景。控制已有会话时,scannerId 必须和打开时一致;下面函数在扫码会话已经创建后按需调用。
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
// 暂停与继续:例如业务弹层显示和关闭时调用。
function pauseScanner() {
LizhaoScanPro.pauseScan({ scannerId: 'main' })
}
function resumeScanner() {
LizhaoScanPro.resumeScan({ scannerId: 'main' })
}
// 结束扫码:业务完成或主动退出时调用。
function closeScanner() {
LizhaoScanPro.stopScan({ scannerId: 'main' })
}
Android / iOS 可通过 setTorchEnabled({ scannerId: 'main', enabled: true }) 打开手电,通过 setZoomRatio({ scannerId: 'main', zoomRatio: 1.8 }) 调整缩放;全屏扫码页本身也提供相应操作。页面销毁时使用 destroyScanner({ scannerId: 'main' }) 释放资源。
模块八:监听扫码页状态
适合需要知道扫码页何时显示、关闭或发生模式切换的进阶业务。仅取得扫码内容时,使用 onResult 即可。
import * as LizhaoScanPro from '@/uni_modules/lizhao-scan-pro'
LizhaoScanPro.startScan({
scannerId: 'main',
overlayConfig: { enabled: true },
onResult(res) {
console.log('扫码结果:', res.results)
},
onError(err) {
console.error('扫码失败:', err.errMsg)
},
onOverlayEvent(event) {
console.log('扫码页状态:', event.type, event.payload)
}
})
onOverlayEvent 必须配合 overlayConfig.enabled=true 才会触发。overlayConfig 用于事件信息传递,不会加载网页,也不能用它创建 H5 扫码界面。
模块九:扫码成功后自动抓图并上传识别
适用于快递面单、收货核验等流程:扫描条码的同时保留完整相机画面,再把图片上传后端识别文字。只需显式设置 captureOnSuccess: true,全程无需点击拍照。
Android / iOS / Harmony 全屏 API 使用同一套参数和返回字段。Harmony 从 1.0.74 起支持,需 HarmonyOS 5.0(API 12)及以上;嵌入式抓图仍仅支持 Android / iOS。
该开关默认 false,不传时保持原有扫码行为。开启后,插件先保存与本次识别对应的视频帧 JPG,再通过 onResult 返回条码和图片路径。图片包含完整相机画面,不含按钮、遮罩等页面 UI;不自动上传、不自动写入相册。视频帧分辨率受设备及相机配置影响,请用实际面单确认文字清晰度。
先在原有示例中体验
打开 uni-app 原示例 scan.vue 或 uni-app x 原示例 index.uvue,使用新增的“扫码自动抓图”区域:
- 打开“识别成功时保存图片”,关闭“连续扫码”和“多码点击选择”,点击原有“打开原生扫码”。
- 对准面单条码,成功后自动回到本页,显示图片、路径与像素尺寸。
- 在原页填写自己的 HTTPS 上传接口。开启“抓图后自动上传”,下次扫码成功后会自动上传;也可点击“上传 / 重试当前图片”。这是上传操作,无需手动拍照。
- 后端识别通过后显示“可以进入下一步”;HTTP、网络或业务失败时显示原因并保留图片供重试。示例不内置可用后端,也不会将图片发往作者服务器。
uni-app:图片路径直接用于文件上传
将以下方法放入现有页面脚本,并从按钮调用 scanAndUpload。把接口地址换成自己的服务地址;需要鉴权时使用业务系统当前登录态。
import { startScan } from '@/uni_modules/lizhao-scan-pro'
// 改成自己的后端;后端接收 multipart/form-data 的 file 文件字段。
const uploadUrl = 'https://your-api.example.com/parcel/recognize'
function scanAndUpload() {
startScan({
scannerId: 'parcel',
captureOnSuccess: true,
continuous: false,
enableAlbum: false,
onResult: (res) => {
if (!res.imagePath || res.results.length === 0) return
// 传文件路径即可,不要把本地路径作为普通 JSON 发给服务器。
uni.uploadFile({
url: uploadUrl,
filePath: res.imagePath,
name: 'file',
formData: {
barcode: res.results[0].value,
requestId: res.scannerId + '-' + res.timestamp + '-' + res.frameIndex
},
timeout: 30000,
// 如需鉴权:header: { Authorization: 'Bearer ' + 业务登录令牌 }
success: (response) => {
if (response.statusCode < 200 || response.statusCode >= 300) {
uni.showToast({ title: '上传失败 HTTP ' + response.statusCode, icon: 'none' })
return
}
try {
const body = JSON.parse(response.data)
// 这里按下文示例响应判断,请改成你自己的后端协议。
if (body != null && body.code === 0 && body.data != null && body.data.accepted === true) {
console.log('后端识别通过,执行下一步', body.data)
// 在这里更新业务数据或跳转页面。
} else {
uni.showToast({ title: '后端未确认通过,请核对面单', icon: 'none' })
}
} catch (error) {
uni.showToast({ title: '后端返回格式异常', icon: 'none' })
}
},
fail: (error) => {
console.error('上传失败,保留图片后可重试', error.errMsg)
}
})
},
onError: (error) => {
console.error('扫码或抓图失败', error.errCode, error.errMsg)
}
})
}
// 页面卸载时调用 destroyScanner({ scannerId: 'parcel' });上传任务的中止和重试见完整原页示例。
uni-app x:用 UTS 读取图片和后端 JSON
在原有 <script setup lang="uts"> 中使用相同参数,图片仍直接交给 uni.uploadFile:
import { startScan, ScanFrameResult, ScanFail } from '@/uni_modules/lizhao-scan-pro'
function scanAndUpload() : void {
startScan({
scannerId: 'parcel',
captureOnSuccess: true,
continuous: false,
enableAlbum: false,
onResult: (res : ScanFrameResult) => {
const path = res.imagePath ?? ''
if (path.length == 0 || res.results.length == 0) return
uni.uploadFile({
url: 'https://your-api.example.com/parcel/recognize', // 替换为自己的接口。
filePath: path,
name: 'file',
formData: {
barcode: res.results[0].value,
requestId: res.scannerId + '-' + res.timestamp.toString() + '-' + res.frameIndex.toString()
},
timeout: 30000,
success: (response : UploadFileSuccess) => {
if (response.statusCode < 200 || response.statusCode >= 300) {
console.error('上传失败 HTTP', response.statusCode)
return
}
try {
const body = JSON.parseObject(response.data)
const data = body?.getJSON('data')
if (body?.getNumber('code') == 0 && data?.getBoolean('accepted') == true) {
console.log('后端识别通过,执行下一步', data)
// 在这里更新业务数据或跳转页面。
} else {
console.warn('后端未确认通过,请核对面单')
}
} catch (error) {
console.error('后端返回格式异常', error)
}
},
fail: (error : UploadFileFail) => { console.error('上传失败,可重试', error.errMsg) }
})
},
onError: (error : ScanFail) => { console.error('扫码或抓图失败', error.errCode, error.errMsg) }
})
}
后端怎样接收
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| file | 文件 | 是 | JPG 二进制,对应 uni.uploadFile.name;若后端字段叫 image,请同步修改 name |
无 | 无 |
| barcode | string | 是 | 扫码结果内容,通过 formData 传递 | 无 | 无 |
| requestId | string | 否 | 同一张图片重试保持相同值,后端可用来避免重复处理 | 无 | 无 |
以下仅是示例约定的响应格式,插件不限定后端技术栈或业务协议:
{ "code": 0, "data": { "accepted": true, "trackingNo": "EXAMPLE123" } }
uni.uploadFile 会以文件表单上传;不要手动设置 Content-Type: application/json 或遗漏文件边界,也不必转换成 base64。success 表示收到了上传响应,还要检查 HTTP 状态码并解析字符串 response.data,再判断业务是否通过。complete 只用于解除忙碌状态、释放任务,不表示后端识别成功。完整示例还包含上传进度、页面卸载中止、失败重试。API 细节见 uni-app 上传文件 与 uni-app x 上传文件。
嵌入式与连续扫码
在现有 <lizhao-scan-pro /> 上设置 :capture-on-success="true",其 scan 事件也返回同样的三个图片字段,沿用上述上传方法即可。
原页上传演示采用单次扫码,便于一单一图地等待后端结果。插件开启 continuous: true 时仍可抓图;业务应使用 pauseScan/resumeScan(组件使用实例 pause/resume)控制上传期间的扫码,并自行处理并发、失败重试与后端幂等,不能只靠回调间隔防止重复业务处理。captureOnSuccess 不支持与 enableMultiCodeSelection 同时开启,也不用于 pickImageAndScan;相册识别请沿用原接口且不传该属性。
独立模块:从已有图片路径识别
当业务已经通过选图、下载或文件选择取得图片路径时,使用 scanImage 直接提取其中的二维码和条形码。接口不打开相机或相册,不上传、删除或修改原图,也不会主动结束已有扫码或业务会话。
下面代码可放在 uni-app 页面脚本或 uni-app x 的 <script setup lang="uts"> 中。假设图片已保存在 _doc/codes.png;使用时替换为业务取得的可读本地图片路径,例如 uni.chooseImage 返回的 tempFilePaths[0]。
import { scanImage } from '@/uni_modules/lizhao-scan-pro'
scanImage({
filePath: '_doc/codes.png',
returnAllResults: true,
success: (res) => {
for (const item of res.results) {
console.log('识别内容:', item.value, '码制:', item.format)
}
},
fail: (err) => {
console.error('图片识别失败:', err.errCode, err.errMsg)
}
})
成功结果包含原始输入 filePath、识别结束时的毫秒时间戳 timestamp 和 results 数组。每项提供 value / format / rawType,本接口不返回相机帧编号或位置坐标。回调使用 success / fail / complete,无需传入 scannerId;成功后执行 success → complete,失败后执行 fail → complete,可在 complete 中结束自己的忙碌状态。
| 参数 | 类型 | 默认值 | 使用说明 |
|---|---|---|---|
filePath |
string | 必填 | 非空的可读本地图片路径或已授权 URI,原样传入 |
androidEngine |
ScanAndroidEngine | 包内默认引擎 | 仅 Android,mlkit / huawei;固定使用本次选择,需已包含在原生包中 |
returnAllResults |
boolean | false |
true 返回本次过滤、去重后的所有已解码结果;false 只返回其中一条 |
formats |
Array<ScanFormat> | 全部支持格式 | 不填或传空数组表示全部;也可指定 ['qrCode', 'code128'] 等有效码制 |
minBarcodeLength |
number | 0 |
非负整数,只过滤过短的一维码正文;0 表示不过滤 |
例如只识别二维码和 Code128,并过滤长度不足 8 的一维码:
import { scanImage } from '@/uni_modules/lizhao-scan-pro'
scanImage({
filePath: '_doc/labels.jpg',
formats: ['qrCode', 'code128'],
minBarcodeLength: 8,
returnAllResults: true,
success: (res) => { console.log('符合条件的结果:', res.results) },
fail: (err) => { console.error(err.errCode, err.errMsg) }
})
同一张图片中,相同码制和正文只保留一条;正文前后空格不会被裁剪。接口先过滤再选择一条或多条,结果顺序不保证跨平台一致,也不能保证识别出图片中的每个物理条码。没有符合条件的码时进入 fail,错误码为 9010006。
支持框架临时/沙盒路径、本地绝对路径和 file URI;Android 还接受已授权的 content URI,Harmony 接受已授权的本地图片 file URI。路径须处于当前应用可读范围,不要裁剪 URI 或去掉文件名空格。HTTP(S)、Base64、/static/、/uni_modules/ 等代码包路径不能直接传入,需先下载或复制为可读本地文件。
完整的路径输入、选图取路径、结果列表和错误处理见 uni-app 图片示例 和 uni-app x 图片示例。pickImageAndScan 继续使用模块四的原有选图及返回规则。
独立模块:批量识别多张图片
商品标签、面单或截图需要批量录入时,将已有本地图片路径交给 scanImages。图片依次处理,坏图、无码等单图失败仍继续下一张;重复图片和跨图重复标签都会保留。
import { scanImages } from '@/uni_modules/lizhao-scan-pro'
const taskId = scanImages({
filePaths: ['_doc/label-a.jpg', '_doc/label-b.jpg'],
returnAllResults: true,
onItem: (item) => {
console.log('输入序号、原路径', item.index, item.filePath)
console.log('单图结果', item.result, '单图错误', item.error)
},
onProgress: (progress) => {
console.log('已完成/总数', progress.completed, progress.total)
},
onComplete: (summary) => {
console.log(summary.reason, summary.succeeded, summary.failed, summary.skipped)
},
onError: (error) => { console.error('任务未启动', error.errCode, error.errMsg) }
})
| 参数或结果 | 使用说明 |
|---|---|
filePaths |
1~100 个字符串路径;序号 index 从 0 开始,路径原样保留;单项空路径作为该图失败 |
formats / minBarcodeLength / returnAllResults |
沿用单图参数;默认每图返回一条,设 returnAllResults: true 取得每图多条结果 |
androidEngine |
仅 Android,mlkit / huawei;省略时使用包内默认引擎,整批固定使用同一选择 |
onItem |
每张结算一次,status 为 success / failed;result 与 error 分别为单图结果或错误 |
onProgress |
初次完成数为 0,随后每张结算更新;单图失败也计入完成数 |
onComplete |
汇总仅一次;reason 为 completed / cancelled,items 仅含实际结算项 |
onError |
任务参数无效、已有活动任务或平台不支持时异步回调;启动返回空字符串,不再产生汇总 |
需要用户取消或页面卸载清理时,保存启动返回的任务 ID,再调用取消接口:
import { cancelScanImages } from '@/uni_modules/lizhao-scan-pro'
function cancelCurrentTask(taskId: string): void {
const accepted = cancelScanImages(taskId)
console.log('本次取消是否受理', accepted)
}
首次取消当前活动任务返回 true,再次取消或 ID 不匹配返回 false。当前图片已经开始时会等待该图结算,再以 cancelled 汇总;剩余数量放在 skipped,页面应等汇总后再结束忙碌状态。页面卸载时还应隔离旧回调,完整示例已包含此处理。
同时只运行一个多图任务;任务未结束时再次启动会异步返回 9010011 / batch-busy。所有任务回调异步派发,每张先 onItem 后 onProgress。失败重试可从汇总 items 筛选 status == 'failed' 的原始 filePath,再启动新任务;取消跳过的图片不属于失败项。
支持 Android / iOS / Harmony App,其他平台异步返回 9010001。调用多图接口前,请重新制作并安装包含 1.0.89 插件代码的自定义基座或 App,仅热更新页面无法加入新接口。路径授权、图片解码及码制能力沿用 scanImage 的平台边界,不额外扩大可读路径、码制或文件权限。完整操作见 uni-app 多图示例 与 uni-app x 多图示例。
Android:选择单引擎或双引擎
需要减小依赖范围时选择单引擎,需要在同一个 App 中比较识别效果时选择双引擎。uni-app 与 uni-app x 使用相同步骤,默认仍为原来的 Google ML Kit;本模块只影响 Android。
1. 配置需要打入的引擎
在项目根目录新建 lizhao-scan-pro.config.json。例如,同时打入两套引擎:
{
"android": {
"engine": "both"
}
}
android.engine |
打入的识别 SDK | 省略运行参数时使用 | 设备范围 |
|---|---|---|---|
mlkit(默认) |
Google ML Kit Barcode Scanning 17.3.0 |
ML Kit | 延续原有 Android 支持 |
huawei |
华为 Scan Kit scanplus:2.15.0.301 |
华为 | ARMv7 / ARM64 |
both |
上述两套 SDK | ML Kit | ARMv7 / ARM64;包体会增加 |
Huawei 与双引擎配置不支持 x86 / x86_64 模拟器。单引擎配置只声明选中的识别 SDK;应用中的其他插件仍可能独立引入另一套 SDK。
2. 应用配置并重新打包
安装 Node.js 后,在项目根目录执行:
node uni_modules/lizhao-scan-pro/select-android-engine.cjs
普通授权或试用版同样执行上述命令,无需修改 Kotlin 文件。每次重新导入或升级插件后,都需要重新执行上述命令;项目根目录保留的 JSON 不会自动应用到新导入的源码和 SDK 依赖。首次切换会自动保存原始文件,请保留命令输出的恢复文件;更新插件时请完整导入,避免混用不同版本的文件。
命令成功后,在 HBuilderX 中重新制作并安装当前配置的 Android 自定义基座或正式 App,再运行示例。修改 JSON 或热更新页面不能给已安装的包增加或移除 SDK。导入新版插件、修改配置或切回单引擎后,都请重新执行命令并重新打包;没有配置文件时执行命令会选回 mlkit。
选择 huawei 或 both 时,Android 打包的 CPU 类型只选择 ARMv7 / ARM64,不选择 x86 / x86_64。
也可通过 --engine mlkit、--engine huawei 或 --engine both 明确选择,命令参数优先于配置文件。追加 --check 只检查当前源码和依赖是否匹配,不写入文件:
node uni_modules/lizhao-scan-pro/select-android-engine.cjs --check
3. 在双引擎包中选择本次识别
既有调用无需修改。需要使用华为时,在本次调用中添加 androidEngine: 'huawei';选择 ML Kit 则传 'mlkit'。例如,双引擎包中打开一次华为扫码:
import { startScan } from '@/uni_modules/lizhao-scan-pro'
startScan({
androidEngine: 'huawei',
onResult: (result) => { console.log(result.results) },
onError: (error) => { console.error(error.errCode, error.errMsg) }
})
startScan、pickImageAndScan、scanImage、scanImages 和 startScanSession 均支持这个可选参数。每次操作固定使用启动时选择的引擎;多图任务的整批图片使用同一引擎。both 仅用于打包配置,不能作为 androidEngine 的值,也不会自动同时识别或失败后切换引擎。指定未打入的引擎会返回 9010009,请根据包内可用列表提供选项。
嵌入式组件通过 android-engine 选择。例如,使用华为显示页面内预览:
<lizhao-scan-pro scanner-id="engine-demo" android-engine="huawei" />
组件运行期间修改该属性只影响下次 start();先停止当前扫码,再启动即可使用新的选择。iOS、Harmony、Web 与小程序忽略 Android 专属引擎参数,沿用各平台既有能力。
4. 确认安装包实际包含哪些引擎
调用原生查询接口,读取当前安装包的配置:
import { getAndroidScanEngineInfo } from '@/uni_modules/lizhao-scan-pro'
const info = getAndroidScanEngineInfo()
console.log(info.mode, info.defaultEngine, info.availableEngines)
// 双引擎包:both、mlkit、['mlkit', 'huawei']
mode 为 mlkit / huawei / both,defaultEngine 是省略调用参数时使用的引擎,availableEngines 是允许选择的列表。这个接口查询安装包中的原生实现,不读取工程 JSON;非 Android 返回 unsupported、空字符串和空数组。完整示例中的 Android 引擎选项也以此查询结果为准,可分别选择两套引擎测试;旧基座无法提供新接口时,请重新制作包含本版本的基座。
主页面的选择用于全屏扫码、旧相册及从该页面进入的自由布局;单图、多图和业务会话示例各自选择引擎,互不改变已启动的任务。
两种引擎的能力边界
华为引擎复用现有扫码界面和相机流程,保留已解码结果的位置、多码选择、高清取帧与相册补救。当前不提供完整未解码候选检测,因此 autoZoom、普通扫码的候选自动拉近及未解码第二码等待不生效;手动缩放仍可使用。双引擎包按本次选择应用这些差异。华为的 itf 映射为 ITF14,普通非 14 位 ITF 标签请先以实际样本确认。请用自己的困难样本比较识别效果。
三种配置均保留 Google Tasks 异步任务库,它本身不是 ML Kit 识别 SDK。SDK 的许可与隐私边界见 第三方依赖与许可说明。
Android 正式包问题诊断与复制日志
从 1.0.82 起,Android 全屏 startScan 可开启 enableDiagnostics: true,用于反馈画面模糊、对焦困难或识别缓慢。默认关闭;不改变对焦、倍率、分辨率或识别策略,也不表示已经修复某个机型的问题。iOS、Harmony、内嵌组件和独立相册识别不使用此开关。
先重新制作并安装包含 1.0.82 的 Android 正式包或自定义基座。 该能力包含 Android 原生代码,仅更新页面、WGT 或 appResource 不会生效。
保留现有调用,只增加诊断开关
在客户现有 startScan 参数对象中增加一行,保留原有其他参数、onResult、onError 和业务校验:
enableDiagnostics: true, // 仅 Android 全屏扫码,默认 false
例如现有调用使用 formats: ['all']、enableAlbum: true,这两项继续原样使用。无需为了收集日志调整 autoZoom、近距模式、结果判断或回调代码,也不需要额外开启 overlayConfig。
发给测试客户的操作步骤
- 使用新安装的测试包进入扫码页。当前完整示例已默认开启“客户问题诊断 → 记录相机诊断日志”,确认开关保持开启后点“打开原生扫码”;自己的页面则由开发者设置上述参数。
- 对准原先难以识别的同一个码,保持通常的距离约 10 秒;轻点画面中的码尝试对焦,等待几秒,记录画面是否变清楚。若仍失败,再改变距离复现一次。
- 点击扫码页中的“复制日志”,将复制出的全部文本粘贴给开发者,同时说明“始终模糊 / 点按后清楚 / 改变距离后清楚”等实际表现。
- 如果扫码成功自动返回,或已关闭扫码页,在完整示例中点击“复制诊断日志”。先复制,再关闭 App 或开始下一次测试;新诊断会话会覆盖上一轮记录,App 进程退出后记录丢失。
日志只描述插件采集到的相机状态与处理过程,客户页面如何判断扫码结果仍需结合原业务代码分析。复制失败时可在 App 内再次点击复制;提示没有日志时,先开启诊断并重新进入扫码页复现。
在自己的页面复制日志
扫码页的“复制日志”由插件直接提供。若还需要返回业务页后复制,可使用现有公共 API;Android 示例按钮仅复制插件诊断快照,不拼接页面结果或 onResult 的码值:
import { getDebugTrace } from '@/uni_modules/lizhao-scan-pro'
function copyScanDiagnostics() {
try {
const lines = getDebugTrace()
if (lines.length === 0) {
uni.showToast({ title: '请先开启诊断并扫码', icon: 'none' })
return
}
uni.setClipboardData({
data: lines.join('\n'),
success: () => { uni.showToast({ title: '日志已复制', icon: 'none' }) },
fail: () => { uni.showToast({ title: '复制失败,请重试', icon: 'none' }) }
})
} catch (error) {
uni.showToast({ title: '读取日志失败,请检查原生包版本', icon: 'none' })
}
}
上例用于 Android 的 uni-app 页面;uni-app x 的条件编译、强类型开关和复制处理见 完整示例。
| 内容 | 说明 |
|---|---|
| 诊断范围 | 插件源码标记、机型和系统、相机 ID 与能力、实际预览/分析尺寸、对焦请求结果、倍率变化、识别统计与生命周期 |
| 内容保护 | 不记录条码正文、图片、账号或设备唯一标识;相机 ID 仅用于区分摄像头 |
| 保留范围 | 仅本进程的最近诊断会话,有界保留,最多 320 条且总量不超过 64 KiB;达到上限会淘汰旧记录 |
| 读取 | getDebugTrace(): Array<string>,关闭扫码后仍可读取,未产生记录时返回空数组 |
| 清理 | clearDebugTrace() 清空记录并停止当前诊断会话,直到下次以 enableDiagnostics: true 开始扫码;应在测试开始前或反馈完成后清理,复现后复制前不要调用 |
| 其他平台 | iOS 原有调试轨迹保持;getCrashReports / clearCrashReports 仍仅用于 iOS,Android 不提供进程崩溃持久化记录 |
API 用途速查
| 模块 | 适用业务 | 常用方法 | 使用结果 |
|---|---|---|---|
| 全屏扫码 | 普通扫码、核销、连续录入 | startScan |
从 onResult 取得识别结果 |
| 业务采集清单 | 去重盘点、逐码校验 | startScanSession / resolveScanItem |
仅已接收内容进入最终清单 |
| 业务采集控制 | 暂停、恢复、主动完成 | pauseScanSession / resumeScanSession / finishScanSession |
控制 sessionId 对应的业务会话 |
| 相册识别 | 图片、截图中的码 | pickImageAndScan |
选图后返回识别结果 |
| 图片文件识别 | 业务已有本地路径、图片内多码提取 | scanImage |
从 success 取得本次 results 列表 |
| 多张图片任务 | 多张标签与截图批量录入、失败重试 | scanImages、cancelScanImages |
逐图回调、进度与完成汇总 |
| 会话控制 | 暂停、继续、主动结束 | pauseScan / resumeScan / stopScan |
控制指定扫描器 |
| 相机与规则 | 手电、缩放、动态码制 | setTorchEnabled / setZoomRatio / setScanFormats |
调整正在使用的扫描器 |
| 资源释放 | 页面销毁、业务结束 | destroyScanner |
释放指定扫描器 |
| 业务事件 | 监听页面状态、传递业务消息 | postOverlayMessage / onOverlayEvent |
收到状态或 nativeMessage 事件 |
| 本地诊断 | Android 全屏相机问题、iOS 调试轨迹 | getDebugTrace / clearDebugTrace |
Android 需开启 enableDiagnostics,仅保留进程内最近诊断会话;iOS 保持原有行为 |
| Android 引擎 | 确认安装包配置、提供引擎选择 | getAndroidScanEngineInfo |
返回实际原生包的 mode / defaultEngine / availableEngines |
| 崩溃报告 | 排查 iOS 问题 | getCrashReports / clearCrashReports |
仅 iOS;其他平台返回空数组或不执行操作 |
参数说明(ScanOptions)
以下是全屏扫码和相册 API 的配置查询表,不需要一次填完。回调单独见后文;嵌入式组件属性见进阶部分。
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| scannerId | string | 否 | 扫描器 ID | default |
任意非空字符串 |
| androidEngine | ScanAndroidEngine | 否 | 仅 Android,本次扫码或相册识别使用的引擎;必须已包含在原生包中 | 包内默认引擎 | mlkit / huawei |
| formats | Array<ScanFormat> | 否 | 识别格式列表 | ["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 |
| captureOnSuccess | boolean | 否 | Android / iOS / Harmony 全屏扫码成功自动保存完整 JPG,成功回调附带图片路径与尺寸;不可与多码点击选择组合,不用于相册识别 | false |
true / false |
| enableMultiCodeSelection | boolean | 否 | Android / iOS 单次全屏扫码识别到多个码时显示点击选择标记并冻结当前画面;仅 continuous=false 生效;Harmony 当前不支持,传 true 返回 9010009 |
false |
true / false |
| multiCodeDetectionWaitMs | number | 否 | 1.0.81 起,Android / iOS 全屏单次多码从首个可靠结果开始的最大聚合等待时间;显式配置不追加高清/未解码候选等待。有限值取整并钳制;空值或非有限值保留旧策略;普通单码、连续、相册忽略 | 未配置(基础窗口 3000ms,保留平台原有补扫策略) |
200~3000,单位毫秒 |
| continuous | boolean | 否 | 是否连续扫码 | false |
true / false |
| continuousIntervalMs | number | 否 | 连续扫码最小回调间隔(ms);仅 continuous=true 生效 |
0 |
大于等于 0 的数值 |
| showContinuousToggle | boolean | 否 | 是否在 Android / iOS / Harmony 原生扫码全屏界面显示“单次/连续”切换按钮 | false |
true / false |
| enableAlbum | boolean | 否 | 是否在原生扫码全屏界面右上角显示相册入口(仅 startScan 生效) |
false |
true / false |
| enableDiagnostics | boolean | 否 | 1.0.82 起,仅 Android 全屏 startScan 记录进程内相机诊断并显示“复制日志”;不改变识别策略,其他平台及内嵌组件忽略 |
false |
true / false |
| enableTorch | boolean | 否 | 是否启用闪光灯 | false |
true / false |
| zoomRatio | number | 否 | 缩放倍率 | 1 |
大于 0 的数值 |
| autoZoom | boolean | 否 | 显式远码自动拉近,仅 Android ML Kit / iOS 实时扫码;设为 false 不关闭 ML Kit 默认全屏 QR/all 的密集二维码补救;华为引擎当前不执行此自动拉近 |
false |
true / false |
| nearFocusLock | boolean | 否 | 是否启用近距锁焦模式(Android / iOS);开启后点击聚焦会优先应用近距辅助缩放,适合约 5cm 场景 |
false |
true / false |
| showScanFrame | boolean | 否 | 是否显示红色扫码角框与中间透明框遮罩;传 false 时隐藏角框和遮罩仅保留扫描线 |
true |
true / false |
| showMaskOverlay | boolean | 否 | 是否显示扫码页黑色遮罩层;仅控制黑色遮罩显隐,不影响扫码框、扫描线、提示文案与操作按钮 | true |
true / false |
| scanFrameStyle | ScanFrameStyle | 否 | Android / iOS / Harmony 扫码框样式配置;支持区域大小、圆角、顶角显隐与颜色定制 | 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 |
| uiVisibilityConfig | ScanUiVisibilityConfig | 否 | Android / iOS / Harmony 全屏扫码页元素显隐配置;既有功能开关先允许,本配置再进一步隐藏;showFocusIndicator 当前仅 Android / iOS 生效 |
null |
showCloseButton / showAlbumButton / showTorchButton / showContinuousButton / showTip / showFocusIndicator / showMaskOverlay / showScanFrameBorder / showScanFrameCorners / showScanLine |
| multiCodeMarkerStyle | ScanMultiCodeMarkerStyle | 否 | Android / iOS 多码点击标记颜色、尺寸和圆角 | null |
backgroundColor / foregroundColor / borderColor / size / cornerRadius |
| 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 |
iOS 旧扫码入口(startScan、pickImageAndScan 及嵌入式组件)仅指定 formats: ["upcA"] 时,将系统返回的对应 EAN-13 前导零正文规范为 12 位 UPC-A,并返回 format: "upcA";使用 all 或显式 ean13 时保留 EAN-13 原格式和正文。此规则不扩展 scanImage 的码制支持范围。
样式配置查询
只调整某一项时,仅传该字段,其余保持默认值。
扫码框(scanFrameStyle)
scanFrameStyle 作用于 Android / iOS / Harmony 全屏原生扫码页:
- 不传时保持默认扫码框样式。
- 比例参数使用 0~1 坐标系:
widthRatio / heightRatio / topRatio。 cornerRadius单位:Android / Harmony 按vp视觉尺寸、iOS 按pt。showScanFrame=false时,scanFrameStyle整体忽略。showCorners=false时隐藏四个顶角,仅保留边框与扫描线。- 字段缺失或非法值自动回退默认值,不抛错、不影响扫码链路。
参数结构:
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| 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,Harmony=vp,iOS=pt) | 14 |
大于等于 0 |
| scanFrameStyle.showCorners | boolean | 否 | 是否显示四个顶角;false 时仅显示边框与扫描线 |
true |
true / false |
| scanFrameStyle.borderColor | string | 否 | 框体描边色 | 平台默认色 | #RRGGBB / #AARRGGBB |
| scanFrameStyle.cornerColor | string | 否 | 四角线条色(仅影响四角,不影响边框) | 平台默认色 | #RRGGBB / #AARRGGBB |
扫码页元素显隐配置
uiVisibilityConfig 影响 Android / iOS / Harmony 的全屏 startScan。既有功能开关先决定能力是否允许,新配置只能在此基础上进一步隐藏,不能反向强制开启:例如相册按钮仍需 enableAlbum=true,连续模式按钮仍需 showContinuousToggle=true。showFocusIndicator 当前仅 Android / iOS 生效。
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| showCloseButton | boolean | 否 | 是否显示关闭按钮 | true |
true / false |
| showAlbumButton | boolean | 否 | 是否显示相册按钮,仍需 enableAlbum=true |
true |
true / false |
| showTorchButton | boolean | 否 | 是否显示手电按钮,仍受设备闪光灯能力限制 | true |
true / false |
| showContinuousButton | boolean | 否 | 是否显示单次/连续按钮,仍需 showContinuousToggle=true |
true |
true / false |
| showTip | boolean | 否 | 是否显示提示图标、文字和背景 | true |
true / false |
| showFocusIndicator | boolean | 否 | 是否显示点击聚焦提示框;实际聚焦仍会执行 | true |
true / false |
| showMaskOverlay | boolean | 否 | 是否显示扫码框外遮罩,仍受 showScanFrame/showMaskOverlay 限制 |
true |
true / false |
| showScanFrameBorder | boolean | 否 | 是否显示扫码框细边框,仍受 showScanFrame 限制 |
true |
true / false |
| showScanFrameCorners | boolean | 否 | 是否显示四角,仍受 showScanFrame/scanFrameStyle.showCorners 限制 |
true |
true / false |
| showScanLine | boolean | 否 | 是否显示并运行扫描线动画,可独立于边框和四角使用 | true |
true / false |
若设置 showCloseButton=false,请保留系统返回或业务可用的退出路径,或由业务调用 stopScan(),避免用户无法退出扫码页。鸿蒙普通扫码与抓图扫码共用这套原生界面;抓图模式按能力约束隐藏相册入口。嵌入式组件的扫码框、按钮和提示由业务页面自行绘制,不应用本配置。
多码点击标记样式
multiCodeMarkerStyle 在 Android / iOS 全屏扫码启用人工选择时可配置原生标记;嵌入式组件仅在 native 绘制模式下使用 multiCodeMarkerStyle,custom 模式由业务页面决定标记样式。样式错误不会触发扫码失败,非法字段会回退安全默认值。
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| backgroundColor | string | 否 | 标记背景颜色 | #5046EE |
#RRGGBB / #AARRGGBB |
| foregroundColor | string | 否 | 箭头前景颜色 | #FFFFFF |
#RRGGBB / #AARRGGBB |
| borderColor | string | 否 | 标记边框颜色,边框宽度固定为 Android 2dp / iOS 2pt |
#FFFFFF |
#RRGGBB / #AARRGGBB |
| size | number | 否 | 标记宽高,超出时自动限制 | 44 |
44~72dp/pt |
| cornerRadius | number | 否 | 标记圆角,超出时自动限制 | size / 2 |
0~size / 2 |
文案和图片图标
| 配置 | 常用字段 | 使用说明 |
|---|---|---|
uiTextConfig |
tipIcon / tipText |
提示图标和提示文字;这里的 tipText 优先于顶层同名字段 |
uiTextConfig |
closeIcon / closeText / albumIcon / albumText |
关闭、相册按钮的字符图标和文案 |
uiTextConfig |
torchIcon / torchOnText / torchOffText / torchUnsupportedText |
手电图标及开、关、不支持时的文字 |
uiImageConfig |
tip / close / album / torchOn / torchOff / torchUnsupported |
对应位置的图片,每个位置填写下表中的图标对象 |
图片来源可使用应用静态资源路径、本地文件路径、file:// / content:// URI 或 data:image/*;base64,...。一般优先填写 /static/xxx.png,并确认对应资源存在。
ScanUiImageItem 字段说明:
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| src | string | 是 | 图标来源(建议 png/jpg/webp 或 data URI) | 无 | 无 |
| width | number | 否 | 图标宽度(Android / Harmony 按 vp 视觉尺寸,iOS 按 pt) | 16~18(按位置默认) |
大于 0 的数值 |
| height | number | 否 | 图标高度(Android / Harmony 按 vp 视觉尺寸,iOS 按 pt) | 16~18(按位置默认) |
大于 0 的数值 |
| tintColor | string | 否 | 图标染色 | null |
#RRGGBB / #AARRGGBB |
按钮和提示的位置(uiLayoutConfig)
uiLayoutConfig 作用于 Android / iOS / Harmony 全屏原生扫码页,用于解决“隐藏胶囊后图标离边太远”场景:
- 坐标语义统一:
x > 0向右,y > 0向下;支持负值。 - 单位:Android / Harmony 按
vp视觉尺寸、iOS 按pt。 - 未传字段按
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 |
回调说明(startScan)
| 回调 | 何时使用 | 读取内容 |
|---|---|---|
onResult(res) |
获取单次、连续或相册识别结果 | res.results 数组 |
onError(err) |
处理取消、权限、参数或识别错误 | err.errCode / err.errMsg |
success / fail / complete |
监听 API 调用的成功、失败、完成 | 不同 API 的动作结果;扫码内容统一在 onResult 中处理 |
onOverlayEvent(event) |
进阶监听全屏页状态,需开启事件配置 | event.type / scannerId / payload |
不要把 startScan 的 success 当作识别成功;识别结果使用 onResult。相册识别成功会触发 onResult 及 success/complete,业务保存操作只放在其中一个入口,避免重复处理。
扫码页事件类型
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 | 运行标识,反馈扫码问题时可用于定位 |
| error | string | 原生扫码过程异常,payload 为错误文本 |
| closed | null | 原生扫码界面已关闭并释放 |
| nativeMessage | any | 调用 postOverlayMessage 后回传的消息内容 |
说明:上述事件仅在 overlayConfig.enabled=true 时派发。
完全自由布局组件(进阶选用)
只有需要自行编写整个扫码页面布局时才使用本节。 普通全屏扫码、连续扫码、相册识别和样式调整,优先使用前面的 API。
组件只负责相机预览、识别和事件,扫码框、按钮、提示及业务区域由页面绘制。以下内容可在 API 接入完成后按需阅读。
uni-app x 端使用标准 native-view 组件,同一个 <lizhao-scan-pro /> 标签同时支持 VDOM 与 Vapor(蒸汽模式),不需要切换组件标签、属性、事件或实例方法。Vapor 项目仍需安装包含当前插件原生代码的匹配自定义基座或正式包;只更新 appResource / wgt 不能替换基座内已经编译的原生实现。
Android 选择 ML Kit 时,uni-app x 嵌入式组件会将困难码兜底帧转换为 NV21 输入,避免 Vapor 运行时持续输出 Bitmap 性能告警。选择华为引擎时由对应适配处理输入,组件调用方式相同。
最小正确接入
uni-app x 使用 .uvue 页面。下面只展示基础预览和结果处理,给组件设置明确宽高,页面返回时恢复、卸载时释放。
<template>
<view>
<lizhao-scan-pro
ref="scanner"
scanner-id="embeddedDemo"
class="scanner-preview"
@ready="onScannerReady"
@scan="onScan"
@error="onError"
/>
</view>
</template>
<script setup lang="uts">
import { ScanEmbeddedState, ScanFrameResult, ScanFail } from '@/uni_modules/lizhao-scan-pro'
// 保存组件引用与就绪状态,首次 onShow 不重复启动。
const scanner = ref<LizhaoScanProComponentPublicInstance | null>(null)
const scannerReady = ref<boolean>(false)
function onScannerReady(_state: ScanEmbeddedState): void {
scannerReady.value = true
}
function onScan(res: ScanFrameResult): void {
console.log('扫码结果:' + JSON.stringify(res.results))
}
function onError(err: ScanFail): void {
console.error('扫码失败:' + err.errMsg)
}
onShow(() => {
if (scannerReady.value) scanner.value?.resume?.()
})
onHide(() => { scanner.value?.pause?.() })
onUnload(() => { scanner.value?.dispose?.() })
</script>
<style>
.scanner-preview { width: 100%; height: 400px; }
</style>
uni-app 使用 .nvue,事件数据可能位于 event.detail 中;请使用随插件提供的对应示例,完整页面入口见下表。
完整示例入口
| 需求 | uni-app | uni-app x |
|---|---|---|
| API 全屏扫码、相册、样式配置 | scan.vue | index.uvue |
| 嵌入式预览、自定义布局、多码标记 | free-layout.nvue | free-layout.uvue |
组件职责与扫码范围
| 能力 | 由谁负责 | 说明 |
|---|---|---|
| 相机预览、码识别、格式过滤、连续扫码、多码冻结选择 | <lizhao-scan-pro /> |
通过 props 配置,通过事件返回结果 |
| 扫码框、扫描线、遮罩、按钮、提示、动画、结果区 | 业务页面 | 使用 .nvue/.uvue 页面元素覆盖在组件上方 |
| 相册识别 | 业务页面调用 pickImageAndScan |
嵌入式组件不内置相册按钮 |
| 页面隐藏、恢复和销毁 | 业务页面生命周期 | 分别调用 pause()、resume()、dispose() |
自定义扫码框只是视觉引导,不是识别裁剪区域。组件会识别整个相机预览范围内的有效码;如业务只允许扫码框内的码,需要在业务层结合结果规则做校验,不能仅依赖页面上画出的方框。
showScanFrame、showMaskOverlay、scanFrameStyle、uiVisibilityConfig、uiTextConfig、uiImageConfig、uiLayoutConfig、tipText 和 enableAlbum 属于全屏 startScan 的界面配置,不是嵌入式组件属性。自由布局模式下请直接在页面中实现这些 UI。
页面覆盖层如果拦截了点击事件,组件不会自动收到点击位置。需要点按聚焦时,在覆盖层的点击事件中取得组件局部坐标,再调用 focusAt(x, y)。
嵌入式多码点击选择
Android / iOS 嵌入式组件可通过 enableMultiCodeSelection=true 开启人工选码。该能力只在 continuous=false 的单次扫码中生效:第一条可定位结果会进入有界聚合,组件属性 multiCodeDetectionWaitMs 默认最多等待 500ms,有效范围仍为 200~1500ms;候选集合连续稳定为多码时冻结当前画面。若候选集合未稳定为多码,包括始终只有单码或候选发生波动,到期后会按确定顺序降级返回一条结果并进入 stopped。全屏 startScan 的同名参数自 1.0.81 起另行支持 200~3000ms,详见前面的多码人工选择说明,不改变嵌入式默认值和范围。两端都不会把仅有轮廓、没有解码内容的潜在框直接作为可选结果。
先按界面需求选择绘制模式:
| 模式 | 谁绘制候选标记 | 是否由插件冻结画面 | 适用场景 |
|---|---|---|---|
native |
插件原生层 | 是 | 希望最少接入代码,直接使用内置可点击标记 |
custom |
业务页面 | 是 | 希望完全控制标记形态、布局和点击交互 |
两种模式都会由插件冻结预览,并通过 multicodechange 返回同一套候选坐标;custom 只把标记绘制和点击入口交给业务页面,不要求业务页面自行截取或冻结相机画面。
以下示例适用于 uni-app .nvue 的 Options API;uni-app x 请直接参考随插件提供的强类型示例 example/uniappx/free-layout.uvue。
使用插件内置标记:
<template>
<view class="scanner-wrap">
<lizhao-scan-pro
ref="scanner"
class="scanner-preview"
scanner-id="nativeSelectionScanner"
:continuous="false"
:enable-multi-code-selection="true"
multi-code-selection-render-mode="native"
@scan="onScan"
@error="onError"
@multicodechange="onMultiCodeChange"
/>
</view>
</template>
<script>
export default {
methods: {
onScan(event) {
const detail = event != null && event.detail != null ? event.detail : event
console.log('选中结果:', detail)
},
onError(event) {
const detail = event != null && event.detail != null ? event.detail : event
console.error('扫码失败:', detail)
},
onMultiCodeChange(event) {
const detail = event != null && event.detail != null ? event.detail : event
const candidates = detail != null && Array.isArray(detail.candidates) ? detail.candidates : []
console.log('候选坐标:', candidates)
}
}
}
</script>
<style>
.scanner-wrap {
width: 100%;
height: 500px;
}
.scanner-preview {
width: 100%;
height: 500px;
}
</style>
由业务页面绘制标记并确认或重扫:
<template>
<view class="scanner-wrap">
<lizhao-scan-pro
ref="scanner"
class="scanner-preview"
scanner-id="customSelectionScanner"
:continuous="false"
:enable-multi-code-selection="true"
multi-code-selection-render-mode="custom"
@scan="onScan"
@error="onError"
@multicodechange="onMultiCodeChange"
/>
<view
v-for="candidate in candidates"
:key="candidate.id"
class="candidate-marker"
:style="markerStyle(candidate.normalizedCenter)"
@tap="selectCandidate(candidate.id)"
>选择</view>
<button
v-if="candidates.length > 0"
class="resume-button"
@tap="resumeSelection"
>重新扫描</button>
</view>
</template>
<script>
export default {
data() {
return { candidates: [] }
},
methods: {
onScan(event) {
const detail = event != null && event.detail != null ? event.detail : event
console.log('选中结果:', detail)
},
onError(event) {
const detail = event != null && event.detail != null ? event.detail : event
console.error('扫码失败:', detail)
},
onMultiCodeChange(event) {
const detail = event != null && event.detail != null ? event.detail : event
const nextCandidates = detail != null && Array.isArray(detail.candidates) ? detail.candidates : []
this.candidates = detail != null && detail.frozen === true ? nextCandidates : []
},
markerStyle(center) {
return {
left: (center.x * 100) + '%',
top: (center.y * 100) + '%'
}
},
selectCandidate(candidateId) {
const scanner = this.$refs.scanner
if (scanner != null) {
scanner.selectMultiCodeCandidate(candidateId)
}
},
resumeSelection() {
const scanner = this.$refs.scanner
if (scanner != null) {
scanner.resumeMultiCodeSelection()
}
}
}
}
</script>
<style>
.scanner-wrap {
position: relative;
width: 100%;
height: 500px;
}
.scanner-preview {
width: 100%;
height: 500px;
}
.candidate-marker {
position: absolute;
z-index: 40;
width: 52px;
height: 52px;
margin-left: -26px;
margin-top: -26px;
border-radius: 26px;
background-color: #5b43d6;
color: #ffffff;
text-align: center;
}
.resume-button {
position: absolute;
right: 16px;
bottom: 16px;
z-index: 41;
}
</style>
returnAllResults=true与人工选择同时开启时,人工选择优先,scan事件的results只包含用户选中的一条。continuous=true时不会进入冻结选择,继续按原有连续扫码协议返回结果。multiCodeMarkerStyle可配置标记背景色、箭头前景色、边框色、尺寸和圆角,仅在native模式由插件绘制时生效;两种模式都会返回multicodechange事件和坐标。- iOS Vision 与 Android Bitmap 等兜底识别结果没有可靠预览坐标时保持无位置状态,不伪造候选坐标或点击标记;只有可定位候选才进入嵌入式多码选择。
- 冻结快照失败时不会留下不可点击的假界面,组件会继续实时扫描。
- 只有
enableMultiCodeSelection=true且continuous=false、人工选择实际生效时才校验选择配置:multiCodeSelectionRenderMode不是native/custom时通过error返回9010009并安全回退为native;multiCodeDetectionWaitMs默认500ms,有效范围为200~1500ms,越界时返回9010009并钳制到安全范围,无效数值回退为默认值。 - 选择完成、重新扫描、停止或销毁时会发出一次
frozen=false、candidates=[]的清理事件;过期候选id会被安全忽略,不会误选新批次。
uni-app x .uvue 的装饰扫码框、四角、扫描线和提示应设置 pointer-events="none"。uni-app .nvue 不应依赖该 CSS 做点击穿透:不要创建整屏透明装饰容器,并像完整示例一样在 enableEmbeddedMultiCodeSelection=true 时通过 v-if 移除扫码框和提示。关闭、手电和模式切换等业务按钮应放在独立的小范围可点击容器中,不要用整屏透明点击层覆盖相机预览。uiVisibilityConfig 仍只控制全屏扫码页,不参与嵌入式自由布局。
组件属性
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| scannerId | string | 否 | 扫描器唯一标识,用于组件注册与公共 API 控制;挂载后不要修改 | embedded |
任意非空且当前页面唯一的字符串 |
androidEngine(模板 android-engine) |
string | 否 | 仅 Android;运行时修改只影响下次 start(),指定未打入引擎返回错误 |
包内默认引擎 | mlkit / huawei |
| formats | Array<ScanFormat> | 否 | 允许识别的码制 | ["all"] |
all / qrCode / aztec / codabar / code39 / code93 / code128 / dataMatrix / ean8 / ean13 / itf / pdf417 / upcA / upcE |
| minBarcodeLength | number | 否 | 一维码最小长度过滤 | 0 |
大于等于 0 |
| returnAllResults | boolean | 否 | 是否返回同一帧的全部有效结果 | false |
true / false |
| captureOnSuccess | boolean | 否 | Android / iOS 扫码成功自动保存完整 JPG,成功回调附带图片路径与尺寸;不可与多码点击选择组合,不用于相册识别 | false |
true / false |
| enableMultiCodeSelection | boolean | 否 | Android / iOS 单次嵌入式扫码开启有界聚合;稳定多码时冻结预览供用户选择,单码到期仅返回一次 | false |
true / false |
| multiCodeSelectionRenderMode | ScanMultiCodeSelectionRenderMode | 否 | 嵌入式多码标记绘制模式;两种模式均由插件冻结并返回事件坐标 | native |
native / custom |
| multiCodeDetectionWaitMs | number | 否 | 第一条可定位结果出现后的最大聚合等待时间,单位毫秒;越界返回 9010009 并钳制 |
500 |
200~1500 |
| multiCodeMarkerStyle | ScanMultiCodeMarkerStyle | 否 | 插件原生标记的背景色、箭头色、边框色、尺寸和圆角;仅 native 模式绘制生效,与全屏扫码共用样式结构 |
{} |
backgroundColor / foregroundColor / borderColor / size / cornerRadius |
| continuous | boolean | 否 | 是否持续识别 | false |
true / false |
| continuousIntervalMs | number | 否 | 连续结果最小间隔,单位毫秒;仅 continuous=true 生效 |
0 |
大于等于 0 |
| autoStart | boolean | 否 | 原生 View 挂载后是否自动启动;设为 false 后需在 ref 可用时调用 start() |
true |
true / false |
| zoomRatio | number | 否 | 初始缩放倍率 | 1 |
大于 0 |
| autoZoom | boolean | 否 | 远码自动拉近,仅 Android ML Kit / iOS 生效;切换属性后重启扫码会话,手动倍率优先 | false |
true / false |
| torchEnabled | boolean | 否 | 初始手电状态 | false |
true / false |
| nearFocusLock | boolean | 否 | 是否启用近距辅助锁焦 | false |
true / false |
| beepOnScan | boolean | 否 | 识别成功后是否播放提示音 | false |
true / false |
| vibrateOnScan | boolean | 否 | 识别成功后是否短震动 | false |
true / false |
组件事件
1.0.81 修复 iOS uni-app Vue3 + nvue 的事件 detail 传值。原有 event.detail ?? event 读取方式保持可用,扫码结果位于 results 数组(如 detail.results[0].value);uni-app x 原有顶层字段也保留。单次扫码成功后停止预览属于原有行为,可按业务需要调用 resume() 或启用连续扫码。
| 事件 | 数据类型 | 说明 |
|---|---|---|
ready |
ScanEmbeddedState | 原生预览与识别链路准备完成;收到后才可安全执行前后台恢复控制 |
scan |
ScanFrameResult | 返回单码或同帧多码结果,业务数据读取 results 数组,结构与 startScan 一致 |
multicodechange |
ScanMultiCodeSelectionEvent | 嵌入式多码冻结与清理事件;native/custom 两种模式都会返回候选及组件局部坐标 |
error |
ScanFail | 权限、初始化、参数或会话冲突错误;必须监听并记录 errCode/errMsg |
statechange |
ScanEmbeddedEvent | 返回 starting/running/paused/stopped/destroyed 状态变化 |
focus |
ScanEmbeddedEvent | 返回点按聚焦坐标与执行状态 |
uni-app .nvue 的原生组件事件数据可能包装在 event.detail 中,建议像完整示例一样先取 event.detail,不存在时再使用事件对象本身;uni-app x .uvue 按表格中的强类型直接接收。
ScanMultiCodeSelectionEvent 返回值:
| 字段 | 类型 | 说明 |
|---|---|---|
| scannerId | string | 产生事件的组件扫描器标识 |
| timestamp | number | 事件时间戳,单位毫秒 |
| selectionId | string | 当前冻结选择批次标识;用于区分前后两批候选 |
| frozen | boolean | true 表示画面已冻结且可选择;false 表示该批次已清理 |
| coordinateSpace | component |
坐标空间固定为扫码组件本地坐标 |
| unit | ScanCoordinateUnit | Android 为 px,iOS 为 pt |
| viewWidth | number | 事件产生时的组件宽度 |
| viewHeight | number | 事件产生时的组件高度 |
| candidates | Array<ScanMultiCodeCandidate> | 当前可选候选;清理事件固定为空数组 |
ScanMultiCodeCandidate 候选字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 当前冻结批次内唯一的候选标识,选择时原样传回 |
| value | string | 识别内容 |
| format | ScanFormat | 归一化后的码制 |
| rawType | string | 原生识别器返回的码制名称 |
| bounds | ScanRect | 候选在组件内的外接矩形,单位由事件 unit 指定 |
| center | ScanPoint | 候选在组件内的中心点 |
| cornerPoints | Array<number> | 四个角点,共 8 个数值,顺序固定为左上、右上、右下、左下(LT/RT/RB/LB) |
| normalizedBounds | ScanRect | 按组件宽高归一化后的外接矩形,范围为 0..1 |
| normalizedCenter | ScanPoint | 按组件宽高归一化后的中心点,范围为 0..1 |
页面自绘时优先使用 normalizedBounds/normalizedCenter,避免 Android px 与 iOS pt 的单位差异。iOS Vision、Android Bitmap 等无法取得可靠组件坐标的兜底结果不会伪造这些字段,也不会作为可点击候选返回。
组件方法
| 方法 | 说明 |
|---|---|
start() |
请求权限并启动或重新绑定相机;适用于 autoStart=false 或 stop() 后重启 |
stop() |
停止识别并解绑相机,保留组件实例和 scannerId 注册;打开不同 ID 的全屏扫码前必须先调用 |
pause() |
暂停分析,不派发识别结果 |
resume() |
恢复分析;尚未启动时会启动会话 |
applyTorchEnabled(enabled) |
设置手电状态 |
applyZoomRatio(zoomRatio) |
设置缩放倍率 |
setScanFormats(formats) |
动态更新码制 |
focusAt(x, y) |
按组件局部坐标执行聚焦 |
getState() |
返回当前组件状态快照 |
selectMultiCodeCandidate(candidateId) |
选择当前冻结批次中的候选;传入已清理或过期的 candidateId 时安全忽略 |
resumeMultiCodeSelection() |
放弃当前冻结批次并恢复实时识别,不触发 scan 事件 |
dispose() |
永久释放相机、识别器、线程、回调和注册表引用;调用后必须重新挂载组件才能再次使用 |
组件与现有 pauseScan/resumeScan/setTorchEnabled/setZoomRatio/setScanFormats/stopScan/destroyScanner 共用 scannerId。公共 API 会优先控制同 ID 的组件;若同 ID 已被组件占用,再调用全屏 startScan 会返回 9010011 scanner id occupied,不会隐式关闭业务页面中的相机。
支持平台
| 平台 | 全屏扫码 API | 相册 API | 图片路径 scanImage |
嵌入式组件 |
|---|---|---|---|---|
| Android 6.0 及以上 | 支持,全屏样式可配置 | 支持,可返回多条结果 | 支持,可返回多条已解码结果 | 支持,uni-app 用 .nvue,uni-app x 用 .uvue(VDOM / Vapor) |
| iOS | 支持,全屏样式可配置 | 支持,当前返回单条结果 | 支持,可返回多条已解码结果 | 支持,uni-app 用 .nvue,uni-app x 用 .uvue(VDOM / Vapor) |
| Harmony | 支持,普通扫码与抓图共用可配置的原生全屏界面 | 支持,普通扫码页可打开系统相册选择器 | 支持,可返回多条已解码结果 | 不支持 |
| Web / 微信小程序 / 支付宝小程序 | 不支持,返回 9010001 |
不支持,返回 9010001 |
不支持,异步返回 9010001 |
不支持 |
uni-app 的普通 .vue 页面可调用全屏及图片路径 API;嵌入式组件需要 .nvue。uni-app x 的 App 页面使用 .uvue,标准 native-view 组件同时支持 VDOM 与 Vapor。
调用 scanImage 前,请制作并安装包含 1.0.87 原生代码的自定义基座或 App;仅热更新页面不能带入该能力。图片格式和可用码制以当前系统能力为准,显式指定不支持的码制返回 9010005。
插件底层按平台走原生能力:Android 使用 CameraX,默认 Google ML Kit,可配置仅华为 Scan Kit 或双引擎包;iOS 使用 AVFoundation + Vision,Harmony 使用 CameraKit + Scan Kit。三端普通扫码和抓图扫码都使用插件原生全屏界面;Web 和小程序会返回明确的不支持错误。
Harmony 使用差异
Harmony 使用同名 API,并与 Android / iOS 共用全屏扫码配置。使用时请按以下差异处理:
startScan:普通扫码与captureOnSuccess=true的抓图扫码都使用 CameraKit 原生全屏界面;预览按相机画面比例等比铺满,扫码框、遮罩、扫描线、文案、图片图标、布局偏移和元素显隐使用同一套参数。enableAlbum=true:普通扫码页显示相册入口,选图后按当前formats识别;取消、无码或失败后回到相机预览。抓图模式不显示相册入口。showContinuousToggle=true:页面内可实时切换单次/连续模式;continuousIntervalMs继续控制连续回调最小间隔,业务仍应自行去重。setTorchEnabled/setZoomRatio:直接控制当前 CameraKit 会话,设备不支持或未生效时返回明确失败。formats:CameraKit 识别阶段按二维码、Data Matrix、PDF417、Code39、Code128、EAN、UPC 等细分格式过滤;minBarcodeLength继续用于过滤过短的一维码结果。returnAllResults=true:相机帧可返回同帧多条结果;Harmony 相册识别当前仍返回单条结果。enableMultiCodeSelection=true:Harmony 当前不支持人工点选多个候选,返回9010009。beepOnScan / vibrateOnScan:Harmony 当前暂不承诺生效。
开启 captureOnSuccess 后,识码器读取的完整 JPG 会通过 file:/// 本地路径连同图片宽高返回;预览的等比裁剪不会裁切保存的原图。低于 API 12 返回 9010001,图片保存失败返回 9010013。请重新构建并安装包含 1.0.74 的鸿蒙 App 后使用。
iOS 多码选择与条码识别
iOS 全屏扫码开启多码选择后,从首个可定位结果起按 multiCodeDetectionWaitMs 聚合,未配置时默认最多约 3 秒,1.0.81 起可设置为 300 等 200~3000ms 范围内的值。窗口内使用带可靠坐标的 metadata 与 Vision 候选,两个候选稳定后可提前冻结供用户点选;到期只有一个候选时按单码返回。没有可靠位置的结果不会显示为可点击标记;未开启多码选择、连续扫码、相册、成功抓图仍沿用原流程;嵌入式组件使用自己的同名属性和范围。
已知条码格式时请明确填写 formats;固定长度的一维条码可配合 minBarcodeLength 过滤过短结果。普通 ITF 设备码使用 formats: ['itf'];最小长度按实际标签填写。Android 华为引擎将 itf 映射为 ITF14,非 14 位标签需先验证识别兼容性。
返回值说明(ScanFrameResult)
| 字段 | 类型 | 说明 |
|---|---|---|
| scannerId | string | 扫描器 ID |
| timestamp | number | 时间戳 |
| frameIndex | number | 帧序号 |
| imagePath | string(可选) | 开启抓图时返回的临时 JPG 本地文件 URI(file://...),可直接用于 image.src 或 uni.uploadFile.filePath;保留完整 URI,不自行拼接或截取路径 |
| imageWidth | number(可选) | 已校正方向的图片宽度,单位像素 |
| imageHeight | number(可选) | 已校正方向的图片高度,单位像素 |
| results | Array<ScanResultItem> | 当前帧结果列表(默认 1 条;returnAllResults=true 时可返回多条) |
results 数组元素结构:
| 字段 | 类型 | 说明 |
|---|---|---|
| value | string | 识别出的二维码或条形码内容 |
| format | ScanFormat | 实际识别码制 |
| rawType | string | 原生识别器返回的码制名称 |
| cornerPoints | Array<number>(可选) | 可定位时返回左上、右上、右下、左下四个角点 |
| bounds | ScanRect(可选) | 可定位时返回结果在嵌入式组件内的外接矩形 |
| center | ScanPoint(可选) | 可定位时返回结果在嵌入式组件内的中心点 |
| normalizedBounds | ScanRect(可选) | 可定位时返回 0..1 归一化外接矩形 |
| normalizedCenter | ScanPoint(可选) | 可定位时返回 0..1 归一化中心点 |
嵌入式多码人工选择完成后,最终选中的 ScanResultItem 会在坐标可靠时保留上述位置字段;这些字段均为嵌入式组件局部坐标,Android 使用 px、iOS 使用 pt,归一化字段范围为 0..1。普通结果或 Vision/Bitmap 等无可靠组件映射的兜底结果不会伪造坐标。
错误码说明
| 错误码 | 含义 | 建议处理 |
|---|---|---|
| 9010001 | 当前平台不支持 | 按支持平台表隐藏对应入口 |
| 9010002 | 相机权限不足 | 引导使用者允许相机访问后重试 |
| 9010003 | 相册权限不足 | 检查相册访问权限及用途说明 |
| 9010004 | 相机启动失败 | 确认相机未被其他活动会话占用后重试 |
| 9010005 | 码制不支持或格式配置有误 | 检查 formats 的拼写与平台支持范围 |
| 9010006 | 图片不可读、解析失败或没有符合条件的码 | 检查路径与读取权限,或换用清晰完整的图片 |
| 9010007 | 预留错误码 | 当前不触发 |
| 9010008 | 取消或中止扫码 | 一般按正常取消处理,无需报错弹窗 |
| 9010009 | 参数不合法或指定引擎未打入 | 检查路径、参数及包内 availableEngines;增加引擎后需重新打包安装 |
| 9010010 | 系统异常 | 记录错误信息后重试 |
| 9010011 | 扫描器 ID 被占用 | 为活动会话使用唯一 ID,或先释放原会话 |
| 9010012 | 组件未就绪或已销毁 | 等待组件挂载;销毁后需重新挂载 |
| 9010013 | 扫码图片保存失败 | 检查存储空间并重试;该次不返回成功结果 |
scanImage 失败时还可结合 details.reason 定位原因:invalid-path / unsupported-source 表示路径或来源不合法,invalid-formats 表示码制无效,invalid-return-all-results / invalid-min-barcode-length 表示对应参数无效。9010006 的原因分别为 file-unreadable(文件不可读)、image-decode-failed(图片解析失败)、no-barcode(没有匹配的码);system-error 对应 9010010。不支持的平台优先异步返回 9010001 / platform-unsupported。
注意事项
Android 默认 ML Kit 引擎普通全屏扫码持续未识别时会分两层补救:码制为空、仅 qrCode 或仅 all 时,对稳定的未解码候选受限拉近;码制包含 qrCode 或 all 时,按节奏尝试高清二维码识别。多码人工选择采用前述“第二码未解全时继续识别”规则,高清补识别仍最多两次,不会持续拍照;未解码区域不会直接作为可选结果,最终能否读出仍取决于画质。近距锁焦和内嵌模式沿用原识别流程;混合指定码制不会触发默认候选拉近,但其中包含 qrCode 时仍可使用高清补救。手动设置倍率或点击聚焦后停止本次自动调整。设备不支持高清取帧时仍可继续普通扫码。该说明对应默认 ML Kit 引擎;选用华为引擎时,候选检测与补救效果以所选 SDK 能力和实际样本为准。
高清补救的图像用于本机识别,不额外写入相册;开启 captureOnSuccess 时仍按原配置返回与结果对应的图片。
基础接入与结果处理
-
captureOnSuccess默认关闭;全屏支持 Android / iOS / Harmony,嵌入式仅支持 Android / iOS。Android / iOS 需包含 1.0.73 抓图能力的自定义基座;Harmony 需 API 12+ 并重新构建安装包含 1.0.74 的鸿蒙 App。Web / 小程序返回9010001。 -
抓图文件是临时资源,请及时上传或按业务需要另存;不要只把本地路径存到后端当作图片。上传成功后可用文件 API 删除本次文件,失败时保留用于重试,勿在上传完成前删除。
-
开启抓图时不提供相册入口;与多码点击选择组合或用于相册识别返回
9010009。 -
Android 云打包必须使用 HBuilderX 5.09 及以上;首次接入或原生能力变更后,需要安装包含对应插件的自定义基座或正式包,纯文档更新不需要重打。
-
全屏扫码和嵌入式预览需要相机权限;相册识别由系统选择器处理,iOS 应配置相册用途说明。
-
API 只从插件根目录导入。全屏扫码使用
startScan,相册选图使用pickImageAndScan,已有图片路径使用scanImage,无需额外挂载组件。 -
scannerId应固定,后续暂停、恢复、停止、销毁都使用相同 ID。同一时间保持一个活动相机会话。 -
全屏扫码打开系统或原生页面时,宿主页面可能暂时不可见;不要把宿主
onHide一律当作业务结束并立即停止扫码。根据实际导航决定停止时机,页面卸载时释放会话。 -
连续扫码需要业务去重;批量结果只表示当前识别到的有效码,不能保证图中所有码一次都能识别。
-
条码模糊、反光、缺损或距离过近时,先调整距离与光照;近距聚焦与缩放不能突破设备相机的对焦能力。
-
beepOnScan / vibrateOnScan默认关闭,Android / iOS 可按需开启;Harmony 当前暂不承诺生效。
接入前先确认(仅嵌入式组件)
先按页面形态选择正确入口:
| 你的需求 | 正确接入方式 | 不要这样用 |
|---|---|---|
| 快速打开完整扫码页 | 调用 startScan(options) |
不需要为了改几段文案就改用组件 |
| 页面结构、按钮和业务区完全自定义 | 在 .nvue/.uvue 使用 <lizhao-scan-pro /> |
不要同时再调用同 ID 的全屏 startScan |
uni-app 普通 .vue 页面 |
继续使用全屏 startScan |
不要在普通 .vue 中放嵌入式组件 |
开始接入前必须满足以下条件:
- 只在 Android/iOS App 使用;Harmony、Web 和小程序当前不支持嵌入式预览。
- uni-app 页面文件必须是
.nvue,uni-app x 页面文件必须是.uvue,不能只把普通.vue改个组件标签;uni-app x 的 VDOM 与 Vapor(蒸汽模式)使用同一个标准组件入口。 - 安装包含当前插件原生能力的应用包后再测试组件。
- 给预览容器和组件设置明确的宽度、高度;高度为
0时不会显示相机画面。 scannerId必须是非空且当前页面唯一的固定字符串,组件挂载后不要动态修改。- 必须监听
error,权限被拒绝、参数错误或会话冲突都会通过该事件返回,不能只监听scan。 - 一个页面只保留一个活动相机会话;打开全屏扫码前先停止嵌入式组件。
生命周期必须这样处理
| 页面时机/动作 | 应调用 | 说明 |
|---|---|---|
| 首次进入页面 | 通常无需手动调用 | 默认 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()。脚本层使用 destroyScanner({ scannerId }) 按 ID 释放扫码会话;两种调用方式不要混用。
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 使用规则
- 每个已挂载组件使用一个非空、唯一且固定的
scannerId,推荐按页面或业务命名,例如warehouseInboundScanner。 - 通过公共 API 控制组件时,API 参数中的
scannerId必须与组件完全一致。 - 为保证 Android/iOS 行为一致,组件挂载后不要动态修改
scannerId;需要换 ID 时先卸载旧组件,再挂载新组件。 - 同一个
scannerId不能同时属于全屏扫码和嵌入式组件,否则返回9010011 scanner id occupied。stop()不会释放组件注册;必须复用同 ID 时需要先dispose()或卸载组件。 - 即使使用不同 ID,设备通常也只能稳定占用一个相机会话,因此打开全屏扫码前仍应先调用组件
stop()。
常见错误与处理
| 现象/错误 | 常见原因 | 正确处理 |
|---|---|---|
| 组件不显示或 easycom 无法识别 | uni-app 使用了普通 .vue |
改用 .nvue;uni-app x 使用 .uvue |
| 页面有位置但相机黑屏 | 组件宽高为 0、相机权限未授权或安装包未包含当前插件原生能力 |
明确设置宽高、处理 error,并确认安装包已包含当前插件 |
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() |
| 扫码框外的码也被识别 | 误以为自定义扫码框会裁剪识别区域 | 扫码框只是视觉提示;在业务层校验结果或调整相机预览范围 |
隐私与数据处理
- 二维码/条形码图像和识别结果默认在设备端处理;插件不会主动把扫码内容上传到作者服务器,也不内置广告或账号追踪。
- Android 默认使用 Google ML Kit Barcode Scanning,可在打包前选用华为 Scan Kit。ML Kit 可能联系 Google 服务以获取模型、错误修复、硬件兼容信息或相关运行指标;华为 Scan Kit 也包含网络通信及运维统计能力。设备端识别不等于 SDK 完全不联网,请按实际选择的 SDK 核对官方隐私条款并完成应用披露。
getDebugTrace()和getCrashReports()用于本地诊断。业务仍不应把账号、口令、Token、完整证件号或其他敏感内容写入扫码参数、页面日志或反馈材料。- 应用开发者仍需根据自身业务、上架地区和目标应用商店要求,在应用隐私政策中说明相机、相册、扫码数据和所用 SDK。
依赖版本、用途、许可与官方条款见 THIRD_PARTY_NOTICES.md。
联系方式
信-微:l-z-1-8-7-1512-5421(-去掉,不这样写会被和谐)
作者系列 UTS 插件
以下为已在 DCloud 插件市场上架的作者系列 UTS 插件,可按业务场景组合使用。未列出的插件表示当前未确认公开市场页,后续上架后再补充。
| 插件 | 能力方向 | 插件市场 |
|---|---|---|
lizhao-app-keepalive |
应用保活、唤醒、自愈与报告 | 查看插件 |
lizhao-bg-audio |
背景音频播放、队列、倍速与事件 | 查看插件 |
lizhao-ble |
BLE 扫描、连接、读写、通知与自动重连 | 查看插件 |
lizhao-call-kit |
电话、短信、通讯录原生能力 | 查看插件 |
lizhao-camera-pro |
原生相机、拍照录像、水印与媒体保存 | 查看插件 |
lizhao-cast-screen |
DLNA 投屏、AirPlay 路由入口 | 查看插件 |
lizhao-choose-file |
原生文件选择、上传、进度与取消 | 查看插件 |
lizhao-device-id |
设备标识、隐私策略与诊断 | 查看插件 |
lizhao-doc-corrector |
文档扫描、矫正、增强与识别 | 查看插件 |
lizhao-emu-detect |
模拟器环境检测、风险评分与证据 | 查看插件 |
lizhao-float-window |
悬浮窗、画中画、权限与诊断 | 查看插件 |
lizhao-gallery-pro |
相册媒体分页、筛选、缩略图与导出 | 查看插件 |
lizhao-hce-card |
NFC 虚拟卡、APDU 交互与 NDEF 标签模拟 | 查看插件 |
lizhao-health |
健康数据授权、查询、统计与写入 | 查看插件 |
lizhao-http-server |
本地 HTTP 服务、文件传输与实时通信 | 查看插件 |
lizhao-icon-pro |
SVG 图标组件、多主题与缓存 | 查看插件 |
lizhao-id-photo |
证件照制作、尺寸换算、换底色与模板换装 | 查看插件 |
lizhao-img-eraser |
图片去水印、局部修复与原生编辑器 | 查看插件 |
lizhao-live-activity |
实时活动、系统胶囊与普通通知降级 | 查看插件 |
lizhao-nfc-pro |
NFC 标签读写、NDEF、IsoDep 与诊断 | 查看插件 |
lizhao-notify-pro |
本地通知、点击动作、进度与定时提醒 | 查看插件 |
lizhao-novel-reader |
原生小说阅读、仿真翻页与段落评论 | 查看插件 |
lizhao-office-view |
Office 与 PDF 文件预览、进度与缓存管理 | 查看插件 |
lizhao-pdf-pro |
PDF 阅读、签批、真实写回与页面处理 | 查看插件 |
lizhao-scan-pro |
原生扫码、连续扫码、相册识别 | 查看插件 |
lizhao-serial-port |
路径串口、USB 串口、多会话收发与诊断 | 查看插件 |
lizhao-share-plus |
系统分享、远程文件下载后分享 | 查看插件 |
lizhao-smart-tts |
系统 TTS、云端合成、听书方案 | 查看插件 |
lizhao-sqlite-pro |
原生 SQLite、迁移、备份与诊断 | 查看插件 |
lizhao-sse-pro |
SSE、Line、JSONL 与 Raw 流式请求 | 查看插件 |
lizhao-tcp-pro |
TCP 客户端、服务端、多连接与诊断 | 查看插件 |
lizhao-usb-storage |
U 盘、移动硬盘文件浏览、读写与批量复制 | 查看插件 |
lizhao-video-editor |
视频裁剪、压缩、取帧与 FFmpeg/FFprobe | 查看插件 |
lizhao-video-feed |
短视频上下滑、短剧选集与分页加载 | 查看插件 |
lizhao-video-player |
原生视频播放器、清晰度与播放交互 | 查看插件 |
lizhao-video-thumb |
视频封面、批量取帧与 Base64 返回 | 查看插件 |
lizhao-vpn-pro |
企业 VPN、IKEv2、安全接入与脱敏诊断 | 查看插件 |
lizhao-wechat-kit |
微信登录、分享、支付、小程序与客服 | 查看插件 |

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 6486
赞赏 5
下载 12750945
赞赏 1959
赞赏
京公网安备:11010802035340号