资讯动态

uni-app 跨端扫码插件 uni-scanCode 深度解析:UTS 插件架构、三端实现与调用指南

发布时间:2026/9/20 21:04:39 来源:尧图企业网站定制
uni-app 跨端扫码插件 uni-scanCode 深度解析UTS 插件架构、三端实现与调用指南【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-appuni-scanCode 是 uni-app 生态中基于 UTS 语言实现的相机扫码一维码/二维码能力插件对应uni.scanCode扩展 API。本文以其在仓库中的 readme.md 为骨架结合utssdk下 Android、iOS、HarmonyOS 三端的真实实现源码与示例页面系统讲解 UTS 插件从类型定义、事件通信到原生扫码调用的完整链路帮助读者既能在业务中正确调用uni.scanCode也能理解 UTS 插件如何实现一套代码、三端原生。一、插件定位与整体能力按 readme.md 的定义uni-scanCode 实现的是效用相机扫码功能即通过相机识别一维码条形码与二维码并返回识别结果。从 interface.uts 中uniPlatform注释声明的支持矩阵看本插件的能力覆盖情况如下√表示支持x表示不支持数字为最低/对应版本要求| 平台 | 支持情况 | 版本要求取自源码注释 | | -- | -- | -- | | App-Android | 支持 | uniVer √unixVer 4.71 | | App-iOS | 支持 | uniVer √unixVer 4.71unixUtsPlugin 4.71 | | App-HarmonyOS | 支持 | uniVer 4.23unixVer 4.61unixVaporVer 5.0 | | 微信小程序 | 支持 | hostVer √uniVer √unixVer 4.41 | | 支付宝/百度/头条/飞书/QQ/快手/京东小程序 | 支持 | hostVer √uniVer √unixVer 标记为 x | | Web | 不支持 | uniVer xunixVer x |同时声明支持 Vue 2 与 Vue 3uniVueVersion 2,3。该矩阵与 package.json 中platforms.client的声明一致Vue2/Vue3 为 yApp-Android 为 yApp-iOS 为 u。更完整的参数说明可继续阅读仓库文档 docs/api/scan-code.md。从平台实现看小程序的扫码能力直接复用了宿主微信、支付宝等自带的扫码能力因此interface.uts中标注hostVer: √而 App 三端则由本插件的 UTS 源码调用原生框架实现这正是它作为 UTS 插件的价值所在。二、UTS 语言与 UTS 插件理解本插件的前提readme 用了较大篇幅介绍 UTS 语言与 UTS 插件概念这是理解 uni-scanCode 代码组织方式的基础。2.1 UTS 语言utsuni type script是一门跨平台、高性能、强类型的现代编程语言由 uni-app 生态引入。它可以被编译为不同平台的编程语言| 平台 | 编译目标语言 | | -- | -- | | Android | Kotlin | | iOS | Swift | | HarmonyOS鸿蒙 | ArkTS | | Web / 小程序 | JavaScript |uts 采用与 TypeScript 基本一致的语法规范支持绝大部分 ES6 API。为了跨端uts 做了一些约束和特定平台的增补过去在 JS 引擎下支持的语法大部分在 uts 处理下可以平滑地在 Kotlin 和 Swift 中使用但有一些差异无法抹平需要使用条件编译处理。与 uni-app 的条件编译类似uts 也支持条件编译写在条件编译分支里的代码可以调用平台特有的扩展语法。本仓库源码中大量使用了条件编译指令例如 app-android/index.uts 中的// #ifdef VUE3-VAPOR以及 scanCode.uvue 中的// #ifdef APP-ANDROID、// #ifdef APP-IOS、// #ifndef VUE3-VAPOR等用于区分不同运行时与渲染引擎下的实现细节。2.2 UTS 插件UTS 插件是一种特定的 uni_modules 插件其核心目的是允许 uni-app / uni-app x 开发者使用 UTS 语法来调用扩展 API封装原生系统的 API 或三方 SDK。UTS 插件的实现代码主要位于utssdk目录下并按平台分离和组织readme 原文表格| 目录/文件 | 目标平台 | 实现语言 | 作用描述 | | -- | -- | -- | -- | | utssdk/app-android | Android | UTS, Kotlin, Java | 存放 UTS 插件在 Android 平台上的具体实现源码 | | utssdk/app-ios | iOS | UTS, Swift | 存放 UTS 插件在 iOS 平台上的具体实现源码 | | utssdk/app-harmony | HarmonyOS鸿蒙 | UTS, ArkTS | 存放 UTS 插件在 HarmonyOS 平台上的具体实现源码 | | utssdk/*.uts | 多平台共用 | UTS | 存放使用 UTS 语言编写的、可供所有平台共用的实现源码 |uni-scanCode 插件的实际目录结构与这一约定完全吻合详见下一节。三、插件目录结构三端实现与共享代码的布局仓库中 uni-scanCode 插件的完整结构如下src/uni_modules/uni-scanCodeuni-scanCode/ ├── pages/scanCode/scanCode.uvue # 扫码交互页面相机、激光线、相册、多码选择等 ├── static/font/uni-scanCode.ttf # 页面图标字体 ├── utssdk/ │ ├── interface.uts # 共享API 类型与 uni.scanCode 接口声明 │ ├── protocol.uts # 共享API 名称常量 │ ├── app-android/ │ │ ├── index.uts # Android 平台实现 │ │ ├── config.json # Android 原生依赖配置 │ │ └── DrawHelper.kt # Android 截图绘制辅助Kotlin │ ├── app-ios/ │ │ ├── index.uts # iOS 平台实现 │ │ └── config.json # iOS 原生依赖配置 │ └── app-harmony/ │ └── index.uts # HarmonyOS 平台实现 ├── changelog.md ├── package.json # 插件元数据、依赖与平台声明 └── readme.mdutssdk/interface.uts、utssdk/protocol.uts属于 readme 表格中多平台共用的*.uts层定义类型与协议常量utssdk/app-android、utssdk/app-ios、utssdk/app-harmony三个目录分别承载三端原生实现其中 Android 目录还包含一个 Kotlin 文件DrawHelper.kt印证了 readme 中Android 平台实现语言包含 Kotlin的描述。四、共享类型层interface.uts 与 protocol.utsinterface.uts 是插件对外暴露的契约层三端实现与业务侧都依赖它。4.1 成功/失败/完成回调export type ScanCodeSuccess { result: string, // 扫码结果内容 scanType: string // 扫码类型如 QR_CODE、EAN_13 等具体格式 } export type ScanCodeFail {} export type ScanCodeSuccessCallback (res: ScanCodeSuccess) void export type ScanCodeFailCallback (res: ScanCodeFail) void export type ScanCodeCompleteCallback (res: any) void成功回调携带result码内容与scanType具体码制complete回调无论成功失败都会触发。4.2 支持的扫码类型export type ScanCodeSupportedTypes barCode | qrCode | datamatrix | pdf417scanType是筛选参数而非精确指定语义为允许识别的码的大类barCode表示一维码、qrCode表示二维码、datamatrix与pdf417分别是两种特定二维矩阵码。业务侧不传时默认识别所有类型。4.3 调用参数export type ScanCodeOptions { onlyFromCamera?: boolean | null, // 是否只能从相机扫码不允许从相册选择图片 scanType?: ScanCodeSupportedTypes[] | null, // 扫码类型 success?: ScanCodeSuccessCallback | null, // 接口调用成功的回调函数 fail?: ScanCodeFailCallback | null, // 接口调用失败的回调函数 complete?: ScanCodeCompleteCallback | null // 接口调用结束的回调函数成功、失败都会执行 }随后通过Uni接口把scanCode(options?: ScanCodeOptions | null): void声明为uni全局对象的扩展方法并导出独立函数类型ScanCode。而 protocol.uts 中只定义了一个常量API_SCAN_CODE scanCode它是 API 名称的唯一来源例如 HarmonyOS 实现中defineAsyncApiScanCodeOptions, ScanCodeSuccess(API_SCAN_CODE, ...)即引用该常量。五、调用入口事件通信 弹层页面的通用模式Android 与 iOS 两个平台在 app-android/index.uts 与 app-ios/index.uts 中的scanCode()入口实现几乎一致构成API 入口 —— 事件总线 —— 对话框页面的完整闭环生成唯一事件名以时间戳加随机数生成uni_scan_code_${uuid}前缀并派生出_success、_fail两个事件名避免多页面并发扫码时事件串扰。订阅回调通过uni.$on(successEventName, ...)与uni.$on(failEventName, ...)注册监听收到事件后把UTSJSONObject转成ScanCodeSuccess/ScanCodeFail再依次触发success/fail与complete回调。解析参数并拼 URLonlyFromCamera默认false允许相册选图scanType数组以逗号拼接成查询串仅在非空时附加scanType...。打开扫码页通过uni.openDialogPage打开插件自带的页面/uni_modules/uni-scanCode/pages/scanCode/scanCode以 query 形式透传successEventName、failEventName、onlyFromCamera、scanTypetriggerParentHide: true隐藏上一页面animationType: zoom-fade-out指定转场动画。若打开失败则在fail回调里uni.$off清理已注册的事件监听。页面回传扫码页识别成功后调用uni.$emit(successEventName, {...})把结果发回入口随后uni.closeDialogPage关闭弹层。// 入口实现关键代码Android/iOS 一致 const uuid ${Date.now()}${Math.floor(Math.random() * 1e7)} const baseEventName uni_scan_code_${uuid} const successEventName ${baseEventName}_success const failEventName ${baseEventName}_fail const onlyFromCamera options?.onlyFromCamera ?? false uni.$on(successEventName, (result: UTSJSONObject) { const successResult: ScanCodeSuccess { result: result[result] as string, scanType: result[scanType] as string, } options?.success?.(successResult) options?.complete?.(successResult) }) uni.openDialogPage({ triggerParentHide: true, animationType: zoom-fade-out, url: /uni_modules/uni-scanCode/pages/scanCode/scanCode?successEventName${successEventName}failEventName${failEventName}onlyFromCamera${onlyFromCamera}${scanTypeQuery}, fail(err) { uni.$off(successEventName); uni.$off(failEventName); } })这一入口函数 dialogPage 事件总线的组合是 uni-app x 中 UTS 扩展 API 封装 UI 型能力的典型范式。六、扫码交互页面scanCode.uvue 的完整能力扫码页面 pages/scanCode/scanCode.uvue共 1045 行是本插件最复杂的部分包含以下交互能力相机渲染使用camera组件设置resolutionhigh高分辨率、frame-sizelarge大帧尺寸flash绑定手电筒开关状态监听initdone事件激光扫描线动画通过页面getElementById(laser)拿到元素用animate在屏幕高度 20%80% 之间循环往返时长 2500ms、无限迭代模拟经典扫码动效手电筒开关handleLight在flash off与torch之间切换相册入口仅当onlyFromCamera ! true时显示相册按钮点击后走图片识码流程多码选择当一帧中识别到多个码barcodeInformation.length 1时暂停帧流、把当前帧截图绘制到全屏image上并根据每个码的scanArea4 元素数组left/top/width/height在对应位置渲染可点击的圆形 marker用户点选后emitSuccess返回所选码双击变焦监听相机区域 click300ms 内二次点击视为双击调用uni.createCameraContext().setZoom把变焦倍率提升 1.2 倍上限maxZoom自动补光提示通过扫码监听器的onLight回调在暗光环境提示开启闪光灯多语言文案内置 en/es/fr/zh-Hans/zh-Hant 五套文案覆盖扫描到多个二维码请选择一个打开未识别到一维/二维码等场景。扫码结果的具体码制判定也在这层完成isQRcode/isBarCode通过比对scanType字符串如QR_CODE、AZTEC、DATA_MATRIX、PDF_417、EAN_13、CODE_128等决定提示文案与分类。七、业务侧最小调用示例仓库自带示例页 src/pages/API/scan-code/scan-code.uvue 给出了最简用法script setup languts const title ref(scanCode) const result ref() const scan () { uni.scanCode({ success: (res: ScanCodeSuccess) { console.log(res: , res); result.value res.result }, fail: (err: ScanCodeFail) { console.log(err: , err); // 需要注意的是小程序扫码不需要申请相机权限 } }); } /script调用要点传入success/fail回调即可完成基础扫码onlyFromCamera默认false此时用户既可以从相机扫码也可以从相册选择包含码的图片识别需要限定码制时传scanType: [qrCode]或scanType: [barCode, pdf417]等示例注释特别提醒小程序端扫码复用宿主能力不需要申请相机权限App 端则需在 manifest 中按平台要求配置相机权限。八、Android 平台实现CameraX 帧流 原生扫码器8.1 原生依赖配置app-android/config.json 声明了 Android 侧的原生依赖{ minSdkVersion: 21, dependencies: [ androidx.camera:camera-core:1.4.1, androidx.appcompat:appcompat:1.7.0 ] }即 Android 端要求 minSdk 21Android 5.0依赖 CameraX 1.4.1 与 AppCompat 1.7.0由编译期自动接入。8.2 实时帧流扫码相机在非 VAPOR 分支中页面startAnalysis通过uni.createCameraContext()创建相机上下文用onAndroidCameraOriginalFrame订阅原始帧ImageProxy每一帧构造AndroidFrameScannerOptions交给getAndroidScanner().processScanBarCode处理const context uni.createCameraContext(); const ratio uni.getWindowInfo().pixelRatio; const width page.width * ratio; const height page.height * ratio; context?.onAndroidCameraOriginalFrame((imageProxy: ImageProxy) { const options: AndroidFrameScannerOptions { imageProxy: imageProxy, scanType: scanType.value, autoZoom: true, // 自动变焦辅助对焦 width: width.toInt(), height: height.toInt(), androidScannerListenner: new (class implements AndroidScannerListener { override onScanSuccess(barcodeInformation, screenShot) { /* 识别结果处理 */ } override onScanFailure(error) {} override needZoom() { /* 调 setZoom 放大 */ } override onLight(light) { /* 暗光时展示补光按钮 */ } }), }; getAndroidScanner()?.processScanBarCode(options); });其中getAndroidScanner、AndroidFrameScannerOptions、AndroidScannerListener、BarcodeInformation、ScreenShot等均来自插件依赖的 uni-camera 模块扫码核心条码解析由 uni-barcode-scanning 模块提供。BarcodeInformation携带result、scanType、charset、rawData、scanArea字段页面据此渲染多码选择 marker。VUE3-VAPOR 分支则把同样的逻辑下沉到插件侧函数utsNativeProcessScanBarCodeUTSJS.keepAlive保持常驻通过回调参数把多码截图、缩放、补光等事件上抛给页面。8.3 相册图片扫码相册识码调用processScanBarCodeWithPhoto构造AndroidPhotoScannerOptions含UTSAndroid.getAppContext()应用上下文、filePath图片路径与scanType成功/失败通过AndroidScannerPhotoListenerImpl回调const options: AndroidPhotoScannerOptions { context, filePath, scanType, androidScannerListenner: new AndroidScannerPhotoListenerImpl(...), } getAndroidScanner()?.processScanBarCodeWithPhoto(options)多码截图绘制由 Kotlin 文件 DrawHelper.kt 提供drawImageWithBitmap把帧截图 Bitmap 直接画到ImageView上作为多码选择背景。九、iOS 平台实现AVFoundation 帧流 原生扫码器iOS 端 app-ios/index.uts 与 Android 结构对称入口scanCode()与 Android 完全一致事件通信 openDialogPage实时帧流createCameraContext().onIosCameraOriginalFrame订阅CMSampleBuffer来自 CoreMedia构造IosFrameScannerOptionssampleBuffer、scanType、autoZoom: true、宽高、IosScannerListener调用getIosScanner().processScanBarCode相册识码processScanBarCodeWithPhoto传入IosPhotoScannerOptionsfilePathscanType多码选择IosScannerFrameListenerImpl.onScanSuccess中当一帧识别到多个码且存在IosScreenShot时暂停帧流通过drawImagesetTimeout100ms 后把UIImage赋给UIImageView显示截图并上抛 marker 数据iOS 侧同样导出了utsNativeProcessScanBarCode/utsNativeProcessScanBarCodeWithPhoto/setScanCodeSelectionShowStatus供 VAPOR 场景使用。从源码结构看iOS 的扫码能力同样建立在 uni-camera 提供的相机上下文与扫码器抽象之上插件本身不直接触碰 AVFoundation 细节这保证了 Android/iOS 两侧交互行为的高度一致。十、HarmonyOS 平台实现ScanKit 直连鸿蒙端 app-harmony/index.uts 的实现路径与 Android/iOS 不同——它直接调用系统扫码服务kit.ScanKitscanBarcode/scanCore未走 dialogPage 自绘页面方案因此实现更精简。10.1 能力探测与类型映射const isScanCoreSupported canIUse(SystemCapability.Multimedia.Scan.Core);运行时先探测系统是否具备扫码核心能力不支持时直接exec.reject(not support)。随后建立两套映射表仅在支持时初始化HarmonyScanTypeMap把 uni 层barCode/qrCode/datamatrix/pdf417映射为scanCore.ScanType.ONE_D_CODE / TWO_D_CODE / DATAMATRIX_CODE / PDF417_CODEUniScanTypeMap把 Harmony 返回的AZTEC_CODE / CODE128_CODE / EAN13_CODE / QR_CODE / PDF417_CODE等码制映射回 uni 层字符串AZTEC / CODE_128 / EAN_13 / QR_CODE / PDF_417供scanType字段使用。10.2 调用系统扫码export const scanCode: ScanCode defineAsyncApiScanCodeOptions, ScanCodeSuccess( API_SCAN_CODE, function (options: ScanCodeOptions, exec: ApiExecutorScanCodeSuccess) { if (!isScanCoreSupported) { exec.reject(not support); return } // 组装 scanTypes let scanTypes: scanCore.ScanType[] []; if (options.scanType Array.isArray(options.scanType) options.scanType.length 0) { // 逐项经 HarmonyScanTypeMap 转换 } if (scanTypes.length 0) { scanTypes [scanCore.ScanType.ALL]; // 未指定时识别全部类型 } const scanOptions: scanBarcode.ScanOptions { scanTypes, enableMultiMode: true, // 支持一次识别多个码 enableAlbum: !options.onlyFromCamera // onlyFromCamera 控制相册入口 }; scanBarcode.startScanForResult(UTSHarmony.getUIAbilityContext()!, scanOptions, (err, data) { if (err) { exec.reject(err.message); return } exec.resolve({ result: data.originalValue, scanType: UniScanTypeMap.get(data.scanType as HarmonyScanResultTypes) || , } as ScanCodeSuccess) }) } ) as ScanCode关键点通过defineAsyncApi注册异步 API与protocol.uts中的API_SCAN_CODE常量关联以UTSHarmony.getUIAbilityContext()获取 UIAbility 上下文作为扫码入口enableAlbum: !options.onlyFromCamera直接复用系统扫码页的相册能力enableMultiMode: true开启多码识别成功结果取data.originalValue作为resultdata.scanType经映射后写入scanType。这一实现也解释了interface.uts中 HarmonyOS 的版本要求为何单独标注uniVer 4.23、unixVer 4.61鸿蒙侧的 ScanKit 能力与 HBuilder 版本强相关。十一、依赖关系与安装方式从 package.json 可确认插件的依赖与分发信息{ id: uni-scanCode, version: 1.0.0, engines: { HBuilderX: ^3.6.8 }, dcloudext: { type: uts }, uni_modules: { pages: { app-harmony: false, app-ios: true, app-android: true }, dependencies: [ uni-framework, uni-camera, uni-barcode-scanning, uni-media, uni-getSystemInfo, uni-dialogPage, uni-event ], uni-ext-api: { uni: { scanCode: { name: scanCode, app: { js: false, kotlin: true, swift: true, arkts: true } } } } } }要点解读版本要求需要 HBuilderX 3.6.8 及以上版本插件类型为uts售价为 0免费插件页面归属扫码弹层页仅在 app-ios 与 app-android 打包harmony 为 false因为鸿蒙复用了系统扫码页运行时依赖uni-camera相机上下文与扫码器抽象、uni-barcode-scanning条码解析核心、uni-dialogPage弹层页面、uni-event事件总线等安装本插件时会自动一并引入API 注册方式通过uni-ext-api声明把scanCode注册为uni全局对象上的扩展 APIApp 侧分别编译为 Kotlin/Swift/ArkTSjs: false表示不提供 JS 实现平台声明Vue2/Vue3 项目为y完全支持App-Android 为yApp-iOS 为u需在 HBuilderX 中确认兼容性。安装方式与普通 uni_modules 插件一致将uni-scanCode目录放入项目的uni_modules目录或通过 HBuilderX 插件市场一键导入即可在代码中直接调用uni.scanCode无需手动引入模块。十二、应用场景与使用注意事项综合源码实现给出以下实战建议码制限定业务只需二维码时传scanType: [qrCode]可避免一维码误识别并提升识别速度多类型场景按需组合数组。相册 vs 相机onlyFromCamera默认false允许从相册识图涉及隐私合规或产品要求必须现场扫码时置为true。多码场景Android/iOS 端识别到多个码时会冻结画面并提供点选交互marker 位置来自scanArea鸿蒙端依赖系统enableMultiMode结果仍按单码返回需要注意行为差异。权限处理小程序端复用宿主扫码能力无需申请相机权限App 端需在 manifest 配置相机权限Android 还需满足 minSdk 21 以上对应 CameraX 依赖要求。失败回调ScanCodeFail目前为空对象失败原因信息有限源码中 errMsg 已被注释建议业务侧在fail中做通用提示兜底。Web 端不支持插件不提供 Web 实现uniVer xH5 项目无法通过本插件扫码需使用其他方案。十三、继续深入仓库完整 API 参数与各端说明docs/api/scan-code.mdUTS 语言介绍docs/uts/README.mdUTS 与 TS 差异docs/uts/uts_diff_ts.mdUTS 插件开发docs/plugin/uts-plugin.md原生语言混编docs/plugin/uts-plugin-hybrid.md各端开发注意事项docs/plugin/uts-for-android.md、docs/plugin/uts-for-ios.md、docs/plugin/uts-for-harmony.md插件三端实现utssdk/app-android/index.uts、utssdk/app-ios/index.uts、utssdk/app-harmony/index.uts扫码页面与示例pages/scanCode/scanCode.uvue、src/pages/API/scan-code/scan-code.uvue【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价