更新记录

0.3.6(2026-11-14)

  1. 优化 iOS 全屏扫码控制层与按钮显示。
  2. 修复 iOS 原生日志字段转换异常。
  3. 修复 iOS 全屏扫码布局约束导致的崩溃。
  4. 示例页支持点击整张能力卡片触发试用。

平台兼容性

uni-app(4.84)

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

uni-app x(4.84)

Chrome Safari Android Android插件版本 iOS iOS插件版本 鸿蒙 鸿蒙插件版本 微信小程序
× × 6.0 0.3.6 15 0.3.6 20 0.3.6 ×

其他

多语言 暗黑模式 宽屏模式 蒸汽模式
√ × × √

安澜扫码(anlan-scan)使用说明

本文面向业务开发者,说明如何在 uni-app / uni-app x 项目中接入 anlan-scan。插件当前版本为 0.3.6。

问题反馈:如果在试用或使用过程中遇到问题,请将错误日志贴到插件市场评论区,或发送到沟通群中,两种方式都可以。看到后会及时回复。

1. 功能概览

anlan-scan 提供统一的跨端原生扫码接口,支持:

  • 二维码与常见条形码识别
  • 全屏原生扫码
  • 相册图片识别
  • 连续扫码和同帧多码返回
  • 前后摄像头切换、手电筒、缩放和点击对焦
  • 识别成功提示音、震动和画面抓取
  • 页面内嵌入式相机预览
  • 自定义扫码框、颜色、文案和交互显隐
  • 原生日志回传、读取、复制和清空

扫码内容默认只在设备本地处理,不会由插件上传到业务服务器。

2. 平台与版本

平台 全屏扫码 相册识别 连续扫码 抓图 页面内预览
Android 支持 支持 支持 支持 支持
iOS 支持 支持 支持 支持 支持
HarmonyOS 支持 支持 受系统扫码页限制 暂不支持 暂不支持

版本要求:

  • HBuilderX 最低版本:5.09
  • uni-app / uni-app x 最低版本:4.84.0
  • Android 最低版本:Android 5.0(API 21)
  • iOS 最低部署版本:iOS 15.0
  • HarmonyOS 蒸汽模式:API 20 及以上

3. 安装与原生基座

插件位于:

uni_modules/anlan-scan

如果项目尚未放入该目录,可将插件目录完整复制到项目的 uni_modules 下。

重要:重新制作自定义基座

插件包含 Android、iOS 和 HarmonyOS 原生代码。首次接入或修改插件原生源码、原生依赖后,需要重新制作自定义调试基座或正式安装包。

只修改业务侧传入的颜色、文案、显隐、尺寸等参数时,不需要重新制作基座。

在标准基座中调用插件时,HBuilderX 可能提示原生配置或三方 SDK 不生效。这是标准基座不含当前插件原生实现的正常表现。

4. 全屏扫码

4.1 最小示例

import {
  startScan,
  ScanOptions
} from '@/uni_modules/anlan-scan'

startScan({
  scannerId: 'main',
  formats: ['all'],
  continuous: false,
  onResult: (result) => {
    console.log(result.results[0]?.value)
  },
  onError: (error) => {
    console.error(error.errMsg, error.errCode)
  }
} as ScanOptions)

startScan 会打开插件提供的原生扫码页面。单次模式下,识别成功后页面自动关闭;连续模式下,页面保持打开并通过 onResult 多次返回结果。

4.2 带界面配置的示例

import {
  startScan,
  ScanOptions,
  ScanUiConfig
} from '@/uni_modules/anlan-scan'

const ui = {
  colors: {
    primary: '#2F6BFF',
    mask: '#99000000',
    title: '#FFFFFF',
    tip: '#D1D5DB',
    actionBackground: '#66000000',
    actionText: '#FFFFFF',
    success: '#22C55E'
  },
  titleText: '扫描商品码',
  tipText: '请将二维码或条形码放入框内',
  showAlbumButton: true,
  showTorchButton: true,
  showScanFrameBorder: false,
  showScanFrameCorners: true,
  showScanLine: true
} as ScanUiConfig

startScan({
  scannerId: 'product',
  formats: ['qrCode', 'ean13', 'code128'],
  enableAlbum: true,
  enableTorch: false,
  vibrateOnScan: true,
  ui,
  onResult: (result) => {
    const first = result.results[0]
    if (first != null) {
      console.log(first.value, first.format)
    }
  },
  onError: (error) => {
    if (error.errCode != 9010008) {
      console.error(error)
    }
  }
} as ScanOptions)

5. 相册识别

import {
  pickImageAndScan,
  ScanOptions
} from '@/uni_modules/anlan-scan'

pickImageAndScan({
  scannerId: 'album',
  formats: ['all'],
  returnAllResults: true,
  onResult: (result) => {
    result.results.forEach((item) => {
      console.log(item.value)
    })
  },
  onError: (error) => {
    console.error(error.errMsg)
  }
} as ScanOptions)

相册图片只在设备本地读取和识别。若用户取消选择图片,可能返回用户取消错误。

6. 连续扫码

startScan({
  scannerId: 'batch',
  formats: ['all'],
  continuous: true,
  continuousIntervalMs: 500,
  vibrateOnScan: true,
  onResult: (result) => {
    const value = result.results[0]?.value
    if (value != null) {
      console.log('扫描到:', value)
    }
  }
} as ScanOptions)

连续模式下:

  • onResult 可被多次调用。
  • continuousIntervalMs 控制相邻结果回调的最小间隔。
  • 用户关闭页面或调用 destroyScanner 后,本次扫码会话结束。
  • complete 表示会话结束,不代表每次都识别成功。

7. 页面内嵌入式预览

7.1 模板

<template>
  <view class="scanner-host">
    <anlan-scan
      id="embedded-scanner"
      scanner-id="embedded-demo"
      :formats="['all']"
      :auto-start="true"
      :continuous="false"
      :vibrate-on-scan="true"
      @ready="onReady"
      @scan="onScan"
      @error="onError"
      @statechange="onStateChange"
      @log="onLog"
    />
  </view>
</template>

7.2 处理事件

function onScan(event: UniNativeViewEvent): void {
  const detail = event.detail as UTSJSONObject
  const result = detail['result'] as UTSJSONObject | null
  if (result == null) return

  const results = result['results'] as Array<UTSJSONObject> | null
  if (results == null || results.length == 0) return

  const first = results[0] as UTSJSONObject
  console.log(first['value'] as string | null)
}

function onError(event: UniNativeViewEvent): void {
  console.error('embedded scan error', event.detail)
}

function onReady(event: UniNativeViewEvent): void {
  console.log('embedded scanner ready', event.detail)
}

function onStateChange(event: UniNativeViewEvent): void {
  console.log('embedded scanner state', event.detail)
}

宿主页面需要为组件容器设置明确宽高,例如:

.scanner-host {
  width: 100%;
  height: 420px;
  overflow: hidden;
  border-radius: 16px;
}

组件支持 start、stop、pause、resume、dispose、applyTorchEnabled、applyZoomRatio、setScanFormats 和 getState 等实例方法。

8. 主要参数

8.1 扫码参数

参数 类型 默认值 说明
scannerId string default 扫码会话标识,不同场景建议使用不同值
formats ScanFormat[] ['all'] 要识别的码制
minBarcodeLength number 0 条形码最小长度
returnAllResults boolean false 是否返回同一帧中的全部结果
continuous boolean false 是否开启连续扫码
continuousIntervalMs number 0 连续结果的最短回调间隔
captureOnSuccess boolean false 是否保存识别成功时的画面
enableAlbum boolean false 是否允许从相册识别
enableTorch boolean false 是否默认开启手电筒
zoomRatio number 1.0 初始缩放倍率
nearFocusLock boolean false 是否启用近距离扫描优化
autoZoom boolean false 是否自动尝试调整缩放
beepOnScan boolean false 识别成功时是否播放提示音
vibrateOnScan boolean false 识别成功时是否震动

支持的码制:

all, qrCode, aztec, codabar, code39, code93, code128,
dataMatrix, ean8, ean13, itf, pdf417, upcA, upcE

8.2 界面参数

通过 ui 字段传入:

参数 说明
colors.primary 扫码框、扫描线和手电高亮颜色
colors.mask 扫码框外遮罩颜色
colors.title / colors.tip 标题与提示文字颜色
colors.actionBackground / colors.actionText 操作按钮背景和文字颜色
colors.success 识别成功描边颜色
titleText / tipText 标题与提示文案
closeText / albumText 关闭和相册按钮的无障碍说明
showTitle / showTip 是否显示标题和提示
showCloseButton / showAlbumButton 是否显示关闭和相册按钮
showTorchButton 是否允许显示手电按钮
showMaskOverlay 是否显示框外遮罩
showScanFrameBorder 是否显示完整扫码框边框
showScanFrameCorners 是否显示四角
showScanLine 是否显示扫描线
frameWidthRatio / frameHeightRatio 扫码框宽高比例
frameTopRatio 扫码框距顶部比例
frameCornerRadius / frameCornerLength 圆角和四角线段长度
initialCameraFacing back 或 front
allowCameraSwitch 是否允许切换前后摄像头
enableTapToFocus 是否允许点击预览区域对焦

颜色支持 #RRGGBB 或 #AARRGGBB。九位颜色统一按 #AARRGGBB 解析。

8.3 配色默认值

插件没有 preset 模板参数,全屏扫码页直接使用宿主传入的颜色:

参数 默认兜底值 使用位置
colors.primary #FFFFFF 扫码框四角、扫描线、可选完整边框、手电开启状态
colors.mask #99000000 扫码框外的遮罩
colors.title #FFFFFF 顶部标题
colors.tip #D1D5DB 扫码框下方提示
colors.actionBackground #66000000 顶部和底部图标按钮的圆形底色
colors.actionText #FFFFFF 按钮图标和底部按钮文字
colors.success #22C55E 识别成功描边

界面使用原生图标控件:顶部关闭和相册为圆形图标按钮,底部手电和摄像头切换为圆形图标加短文字。设备没有闪光灯时,手电按钮会自动隐藏。扫描框默认显示四角,完整边框可通过 showScanFrameBorder: true 开启。

8.4 完整界面参数示例

startScan({
  scannerId: 'brand',
  ui: {
    colors: {
      primary: '#2F6BFF',
      mask: '#99000000',
      title: '#FFFFFF',
      tip: '#D1D5DB',
      actionBackground: '#66000000',
      actionText: '#FFFFFF',
      success: '#22C55E'
    },
    titleText: '扫描商品码',
    tipText: '请将二维码或条形码放入框内',
    closeText: '关闭',
    albumText: '相册',
    torchOnText: '关闭手电',
    torchOffText: '打开手电',
    cameraSwitchText: '前后摄像头',
    showTitle: true,
    showCloseButton: true,
    showAlbumButton: true,
    showTorchButton: true,
    showTip: true,
    showMaskOverlay: true,
    showScanFrameBorder: false,
    showScanFrameCorners: true,
    showScanLine: true,
    frameWidthRatio: 0.76,
    frameHeightRatio: 0.28,
    frameTopRatio: 0.27,
    frameCornerRadius: 14,
    frameCornerLength: 24,
    frameBorderWidth: 2.5,
    scanLineThickness: 2,
    scanLineDurationMs: 1800,
    successFlashMs: 220,
    closeDelayMs: 260,
    topBarInsetDp: 12,
    bottomBarInsetDp: 24,
    tipGapDp: 14,
    actionGapDp: 18,
    initialCameraFacing: 'back',
    allowCameraSwitch: true,
    enableTapToFocus: true
  }
} as ScanOptions)

9. 结果结构

onResult 接收到 ScanFrameResult:

type ScanFrameResult = {
  scannerId: string
  timestamp: number
  frameIndex: number
  results: Array<ScanResultItem>
  imagePath?: string | null
  imageWidth?: number | null
  imageHeight?: number | null
}

单个结果:

type ScanResultItem = {
  value: string
  format: ScanFormat
  rawType: string
  cornerPoints?: Array<number> | null
  bounds?: ScanRect | null
  center?: ScanPoint | null
  normalizedBounds?: ScanRect | null
  normalizedCenter?: ScanPoint | null
}

业务代码应始终先判断 results.length,不要直接访问不存在的结果。

10. 生命周期与控制接口

import {
  stopScan,
  pauseScan,
  resumeScan,
  setTorchEnabled,
  setZoomRatio,
  setScanFormats,
  destroyScanner
} from '@/uni_modules/anlan-scan'

setTorchEnabled({ scannerId: 'main', enabled: true })
setZoomRatio({ scannerId: 'main', zoomRatio: 1.5 })
setScanFormats({ scannerId: 'main', formats: ['qrCode'] })
pauseScan({ scannerId: 'main' })
resumeScan({ scannerId: 'main' })
stopScan({ scannerId: 'main' })
destroyScanner({ scannerId: 'main' })

业务页面卸载时,建议调用 destroyScanner 清理仍存在的扫码会话和原生资源。

11. 原生日志

通过 onLog 接收实时日志:

startScan({
  scannerId: 'debug',
  onLog: (entry) => {
    console.log(
      `[${entry.level.toUpperCase()}][${entry.stage}] ${entry.message}`,
      entry.details
    )
  }
} as ScanOptions)

也可以主动读取:

import {
  getDebugLogs,
  getDebugTrace,
  clearDebugTrace
} from '@/uni_modules/anlan-scan'

console.log(getDebugLogs())
console.log(getDebugTrace())
clearDebugTrace()

插件在内存中最多保留 500 条日志。日志可能包含扫码原文等业务敏感信息,只应在排查问题时复制或上传。

12. 错误码

错误码 含义
9010001 平台不支持
9010002 相机权限被拒绝
9010003 相机不可用
9010004 未识别到有效码
9010005 参数无效
9010006 相册不可用
9010007 相册识别失败
9010008 用户取消
9010009 不支持的能力组合
9010010 闪光灯不可用
9010011 缩放参数无效
9010012 扫码会话不存在
9010013 抓图失败

用户主动关闭扫码页时通常返回 9010008,业务侧一般不需要向用户显示错误提示。

13. 权限与数据处理

插件可能申请以下系统权限:

  • 相机:扫描二维码和条形码
  • 相册:选择图片进行本地识别
  • 闪光灯:控制手电筒
  • 震动:识别成功时提供触觉反馈

数据处理说明:

  • 扫码内容、相册图片和相机画面默认仅在设备本地处理。
  • 插件不向业务服务器上传扫码内容或图片。
  • 开启 captureOnSuccess 后,识别画面保存在 App 临时目录,后续处理由宿主业务决定。
  • Android 使用 Google ML Kit 在设备本地识别,适用其官方数据处理条款。
  • iOS 使用 Apple Vision 在设备本地识别。
  • HarmonyOS 使用系统 Scan Kit。

14. 常见问题

标准基座中提示插件能力不可用

请制作包含 anlan-scan 的自定义基座。修改原生代码或原生依赖后也必须重新制作。

相机权限被拒绝

检查宿主 App 的系统权限配置和用户授权状态。iOS 需要在原生配置中声明相机、相册用途;Android 需要声明相机权限。

模拟器显示相机不可用

部分 iOS 模拟器没有可用摄像头,扫码相机无法正常启动。应在真机上完成相机、相册和闪光灯相关验收。

识别框显示但无法识别

扫描框只作为视觉引导,实际识别覆盖预览画面,但应保证二维码或条形码清晰、完整、不过曝,并尝试靠近或调整拍摄距离。

修改颜色后需要重新打包吗

通过 ui 参数修改颜色、文案、显隐、位置和尺寸不需要重新制作基座。修改插件原生源码或第三方 SDK 时才需要重新打包。

15. 开发验收建议

  • 使用正式 App ID 制作自定义基座。
  • 在至少一台 Android 真机和一台 iOS 真机上验收相机流程。
  • 验收首次授权拒绝与再次授权场景。
  • 验收单次扫码、连续扫码、相册识别和多码返回。
  • 验收页面退出、后台切换和重复进入后的资源释放。
  • HarmonyOS 重点验收系统 Scan Kit 页面和权限流程。
  • 发布前检查 readme.md、更新日志、隐私声明和权限说明。

16. 实现结构

  1. interface.uts 定义跨端 API、结果、UI 配置和错误码。
  2. ui.uts 合并宿主传入的颜色、文案、显隐和尺寸参数。
  3. Android AnlanScanActivity.kt 负责 CameraX 预览、ML Kit 识别、权限、相册和全屏扫码页。
  4. Android AnlanScanControlView.kt 绘制统一图标的原生操作按钮。
  5. iOS AnlanScanViewController.swift 负责 AVFoundation、Vision、全屏布局和操作按钮。
  6. HarmonyOS index.uts 通过系统 Scan Kit 打开扫码页面。

17. 重新打包

Android 使用 CameraX 与 ML Kit,iOS 使用相机、相册和 Vision。修改插件原生源码或第三方依赖后,必须重新制作自定义调试基座或正式安装包。页面级颜色、文案、显隐、位置和尺寸可以随前端资源更新,不需要重新制作基座。

隐私、权限声明

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

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

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

扫码内容与可选抓图默认仅在设备端处理。Android 使用 Google ML Kit,适用其官方数据处理条款。

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

无

暂无用户评论。