更新记录

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 页面隐藏、返回、销毁时控制相机资源

下载与导入

  1. 在插件市场选择“使用 HBuilderX 导入插件”,导入到自己的 uni-app 或 uni-app x 项目。
  2. 保留完整的 uni_modules/lizhao-scan-pro 目录和插件名称。示例页面可复制到自己的页面目录,组件及辅助模块统一通过 @/uni_modules/lizhao-scan-pro/ 引入。
  3. 在页面脚本中从插件根目录导入:
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/ 目录下,按项目类型选择对应子目录:

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,使用新增的“扫码自动抓图”区域:

  1. 打开“识别成功时保存图片”,关闭“连续扫码”和“多码点击选择”,点击原有“打开原生扫码”。
  2. 对准面单条码,成功后自动回到本页,显示图片、路径与像素尺寸。
  3. 在原页填写自己的 HTTPS 上传接口。开启“抓图后自动上传”,下次扫码成功后会自动上传;也可点击“上传 / 重试当前图片”。这是上传操作,无需手动拍照。
  4. 后端识别通过后显示“可以进入下一步”;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。

发给测试客户的操作步骤

  1. 使用新安装的测试包进入扫码页。当前完整示例已默认开启“客户问题诊断 → 记录相机诊断日志”,确认开关保持开启后点“打开原生扫码”;自己的页面则由开发者设置上述参数。
  2. 对准原先难以识别的同一个码,保持通常的距离约 10 秒;轻点画面中的码尝试对焦,等待几秒,记录画面是否变清楚。若仍失败,再改变距离复现一次。
  3. 点击扫码页中的“复制日志”,将复制出的全部文本粘贴给开发者,同时说明“始终模糊 / 点按后清楚 / 改变距离后清楚”等实际表现。
  4. 如果扫码成功自动返回,或已关闭扫码页,在完整示例中点击“复制诊断日志”。先复制,再关闭 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 全屏原生扫码页:

  1. 不传时保持默认扫码框样式。
  2. 比例参数使用 0~1 坐标系:widthRatio / heightRatio / topRatio。
  3. cornerRadius 单位:Android / Harmony 按 vp 视觉尺寸、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,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 全屏原生扫码页,用于解决“隐藏胶囊后图标离边太远”场景:

  1. 坐标语义统一:x > 0 向右,y > 0 向下;支持负值。
  2. 单位:Android / Harmony 按 vp 视觉尺寸、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

回调说明(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 共用全屏扫码配置。使用时请按以下差异处理:

  1. startScan:普通扫码与 captureOnSuccess=true 的抓图扫码都使用 CameraKit 原生全屏界面;预览按相机画面比例等比铺满,扫码框、遮罩、扫描线、文案、图片图标、布局偏移和元素显隐使用同一套参数。
  2. enableAlbum=true:普通扫码页显示相册入口,选图后按当前 formats 识别;取消、无码或失败后回到相机预览。抓图模式不显示相册入口。
  3. showContinuousToggle=true:页面内可实时切换单次/连续模式;continuousIntervalMs 继续控制连续回调最小间隔,业务仍应自行去重。
  4. setTorchEnabled / setZoomRatio:直接控制当前 CameraKit 会话,设备不支持或未生效时返回明确失败。
  5. formats:CameraKit 识别阶段按二维码、Data Matrix、PDF417、Code39、Code128、EAN、UPC 等细分格式过滤;minBarcodeLength 继续用于过滤过短的一维码结果。
  6. returnAllResults=true:相机帧可返回同帧多条结果;Harmony 相册识别当前仍返回单条结果。
  7. enableMultiCodeSelection=true:Harmony 当前不支持人工点选多个候选,返回 9010009。
  8. 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 中放嵌入式组件

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

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

生命周期必须这样处理

页面时机/动作 应调用 说明
首次进入页面 通常无需手动调用 默认 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 使用规则

  1. 每个已挂载组件使用一个非空、唯一且固定的 scannerId,推荐按页面或业务命名,例如 warehouseInboundScanner。
  2. 通过公共 API 控制组件时,API 参数中的 scannerId 必须与组件完全一致。
  3. 为保证 Android/iOS 行为一致,组件挂载后不要动态修改 scannerId;需要换 ID 时先卸载旧组件,再挂载新组件。
  4. 同一个 scannerId 不能同时属于全屏扫码和嵌入式组件,否则返回 9010011 scanner id occupied。stop() 不会释放组件注册;必须复用同 ID 时需要先 dispose() 或卸载组件。
  5. 即使使用不同 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()
扫码框外的码也被识别 误以为自定义扫码框会裁剪识别区域 扫码框只是视觉提示;在业务层校验结果或调整相机预览范围

隐私与数据处理

  1. 二维码/条形码图像和识别结果默认在设备端处理;插件不会主动把扫码内容上传到作者服务器,也不内置广告或账号追踪。
  2. Android 默认使用 Google ML Kit Barcode Scanning,可在打包前选用华为 Scan Kit。ML Kit 可能联系 Google 服务以获取模型、错误修复、硬件兼容信息或相关运行指标;华为 Scan Kit 也包含网络通信及运维统计能力。设备端识别不等于 SDK 完全不联网,请按实际选择的 SDK 核对官方隐私条款并完成应用披露。
  3. getDebugTrace() 和 getCrashReports() 用于本地诊断。业务仍不应把账号、口令、Token、完整证件号或其他敏感内容写入扫码参数、页面日志或反馈材料。
  4. 应用开发者仍需根据自身业务、上架地区和目标应用商店要求,在应用隐私政策中说明相机、相册、扫码数据和所用 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 微信登录、分享、支付、小程序与客服 查看插件

隐私、权限声明

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

相机、相册、闪光灯、震动

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

扫码图片和结果默认在设备端处理;Android 默认使用 Google ML Kit,可在打包前选用华为 Scan Kit;所选 SDK 的网络通信、运行统计与数据处理适用其官方条款

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

无