尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

微信小程序连续扫码实战:camera组件避坑与性能优化指南

微信小程序连续扫码实战:camera组件避坑与性能优化指南 1. 从一个真实需求说起为什么要死磕连续扫码去年接了一个仓储盘点的小程序项目需求方开口第一句话就是“我要能一直扫扫完一个自动接着扫下一个中间不要让我点任何按钮。”听起来很简单对吧微信小程序官方提供了wx.scanCodeAPI调一次扫一个扫完再调一次不就行了实际动手之后才发现这里面的坑比想象中多得多。wx.scanCode每次调用都会拉起一个全屏的原生扫码界面扫完之后界面关闭回到小程序页面然后你才能再次调用。这个“拉起-关闭-再拉起”的过程在安卓上大概有 300-500ms 的闪烁间隙在 iOS 上更明显用户会看到屏幕反复闪白体验非常割裂。而且每次调用都会有一次明显的相机启动延迟连续扫十几个码下来操作员直接跟我说“眼睛都要闪瞎了”。后来我把目光转向了camera组件。微信小程序从基础库 2.7.0 开始camera组件支持了modescanCode模式可以在组件内部直接完成扫码识别不需要反复拉起原生界面。这意味着你可以把 camera 组件嵌在页面里配合bindscancode事件实现真正的“连续扫码”——扫完一个码界面不关闭直接接着扫下一个。但事情没有这么简单。官方文档对camera组件的scanCode模式描述非常简略很多关键细节需要自己踩坑才能摸清楚。比如扫到同一个码会不会重复触发连续扫码时如何避免重复录入不同机型上 camera 组件的表现差异有多大页面隐藏后相机资源怎么释放这些问题在官方文档里几乎找不到答案。这篇文章就是把我这段时间踩过的坑、试过的方案、总结出来的经验完整地分享出来。如果你也在做微信小程序的扫码功能尤其是需要连续扫码的场景仓储盘点、图书录入、资产盘点、门票核销等这篇文章应该能帮你省下不少时间。我会从方案选型开始讲然后深入 camera 组件的核心机制再给出完整的实操代码和避坑指南最后整理一份常见问题速查表。内容比较长建议先收藏再慢慢看。2. 方案选型scanCode API 还是 camera 组件2.1 两种扫码方式的本质区别在微信小程序里做扫码摆在面前的有两条路一是调用wx.scanCodeAPI二是使用camera组件的scanCode模式。很多人一开始都会用wx.scanCode因为它简单一行代码就能调起来。但如果你要做连续扫码这个方案很快就会暴露出问题。wx.scanCode的本质是调用微信客户端原生的扫码界面。你调用它微信就弹出一个全屏的原生页面这个页面不属于你的小程序你无法控制它的 UI也无法在它上面叠加任何东西。扫完之后原生页面关闭结果通过回调返回给你的小程序。整个过程是“你的小程序 → 原生扫码页 → 你的小程序”这样一个来回切换的过程。camera组件则完全不同。它是嵌入在你小程序页面里的一个原生组件相机画面直接显示在你指定的区域里。当设置modescanCode时组件内部会自动识别画面中的二维码/条形码识别到之后通过bindscancode事件把结果抛给你。整个过程你的页面始终在前台相机画面不会中断用户看到的是一个连续的取景框体验上更接近“专业扫码枪”的感觉。2.2 连续扫码场景下的性能对比我分别在安卓和 iOS 上做了对比测试用同一台设备连续扫 20 个二维码记录总耗时和用户可感知的闪烁次数。测试机型安卓端是某骁龙 870 机型iOS 端是 iPhone 13。对比维度wx.scanCode APIcamera 组件 scanCode 模式单次扫码平均耗时800-1200ms200-400ms连续扫 20 个码总耗时约 20-25 秒约 6-8 秒界面闪烁每次都有明显闪烁无闪烁画面连续相机启动延迟每次调用都有仅首次有自定义 UI不支持完全支持连续扫码体验差需要反复等待好接近无缝最低基础库要求1.0.02.7.0从表格可以清楚看到camera组件在连续扫码场景下的优势是压倒性的。总耗时差了 3 倍以上而且没有闪烁用户体验完全不是一个级别。当然代价是基础库要求更高2.7.0以及你需要自己处理相机权限、页面生命周期等细节。2.3 什么场景该选哪个方案不是说wx.scanCode就一无是处。如果你的场景是“偶尔扫一次”比如用户点击按钮扫一个码就完事那用wx.scanCode完全没问题代码简单兼容性好不需要处理相机权限的复杂逻辑。但如果你符合以下任何一个特征就应该认真考虑camera组件方案需要连续扫多个码中间不希望用户有多余操作对扫码速度有要求比如高峰期需要快速核销需要自定义扫码界面的 UI比如加个手电筒按钮、加个已扫列表需要在扫码的同时显示其他信息比如当前盘点进度我个人的建议是只要你的场景涉及连续扫码直接上camera组件方案不要犹豫。前期多花一两个小时处理细节后期省下的是无数次的用户投诉。3. camera 组件连续扫码的核心机制拆解3.1 bindscancode 事件的触发逻辑camera组件的bindscancode事件是整个连续扫码的核心。当modescanCode时组件会自动识别相机画面中的码识别成功就触发一次bindscancode回调参数里包含扫码结果。这里有一个非常关键的细节同一个码在画面中持续存在时bindscancode 会不会重复触发官方文档没有明确说明我实测的结果是会重复触发但触发频率不固定。在安卓上同一个码大约每 500-800ms 会触发一次在 iOS 上大约每 300-500ms 触发一次。这意味着如果你不做去重处理同一个码会被连续录入多次。这个机制的设计初衷可能是为了“容错”——万一第一次识别结果不完整后续还能补上。但对于连续扫码场景来说这就是一个必须处理的陷阱。解决方案后面会详细讲。3.2 相机资源的生命周期管理camera组件是原生组件相机资源是独占的。这意味着当页面隐藏时比如用户按了 Home 键或者跳转到其他页面相机应该被释放否则会一直占用摄像头导致其他应用无法使用相机当页面显示时相机需要重新初始化如果页面上有多个 camera 组件只有最后一个生效微信小程序提供了页面生命周期函数onHide和onShow以及组件级别的wx.createCameraContext来管理相机。但实际使用中我发现单纯依赖页面生命周期还不够因为 camera 组件的初始化是异步的页面onShow触发时相机可能还没准备好。一个比较稳妥的做法是用一个data字段控制 camera 组件的渲染与销毁。页面隐藏时把字段设为false组件被销毁相机释放页面显示时设为true组件重新创建。这样虽然会有一点初始化延迟但能确保相机资源被正确释放。3.3 连续扫码的去重策略前面提到同一个码会重复触发bindscancode所以去重是必须的。去重的核心思路是记录最近一次扫码的结果和时间戳如果新结果和上一次相同且时间间隔小于某个阈值就忽略。但这里有个问题如果用户真的需要连续扫两个相同的码呢比如盘点时有两个相同的资产标签。这种情况下简单的“结果相同就忽略”会误杀。所以去重策略需要更精细一些。我的做法是维护一个“已扫码集合”每扫到一个码先检查是否在集合中。如果不在加入集合并触发业务逻辑如果在检查距离上次扫码的时间间隔如果超过一定时间比如 3 秒认为是用户有意重复扫允许通过如果小于 3 秒认为是重复触发忽略。这个策略在实际使用中效果不错既避免了重复触发又不会误杀合理的重复扫码需求。4. 完整实操从零实现一个连续扫码页面4.1 页面结构与基础配置先来看页面的 WXML 结构。核心就是一个camera组件加上一些辅助 UI。view classscan-container !-- 相机区域 -- camera wx:if{{cameraVisible}} classcamera-area modescanCode device-positionback flash{{flashOn ? torch : off}} bindscancodeonScanCode binderroronCameraError !-- 扫码框覆盖层 -- cover-view classscan-frame cover-view classscan-corner top-left/cover-view cover-view classscan-corner top-right/cover-view cover-view classscan-corner bottom-left/cover-view cover-view classscan-corner bottom-right/cover-view /cover-view /camera !-- 相机不可用时的提示 -- view wx:else classcamera-placeholder text相机初始化中.../text /view !-- 底部操作栏 -- view classbottom-bar view classscan-count已扫 {{scanList.length}} 个/view view classbtn-group button classbtn-flash bindtaptoggleFlash {{flashOn ? 关闭闪光灯 : 打开闪光灯}} /button button classbtn-finish bindtapfinishScan完成/button /view /view !-- 已扫列表 -- scroll-view classscan-list scroll-y view wx:for{{scanList}} wx:keyindex classscan-item text classscan-index{{index 1}}/text text classscan-result{{item}}/text /view /scroll-view /view这里有几个关键点需要注意camera组件用wx:if控制显示与隐藏而不是hidden。因为hidden只是隐藏了 UI相机资源并没有释放。用wx:if才能真正销毁组件、释放相机。modescanCode是开启扫码模式的关键属性。device-positionback指定使用后置摄像头扫码场景基本都用后置。flash属性控制闪光灯torch是常亮模式适合扫码补光。bindscancode是扫码结果的回调。binderror是相机出错的回调必须处理否则出错时用户看不到任何提示。4.2 核心逻辑扫码事件处理与去重接下来是 JS 部分的逻辑。核心是onScanCode事件处理函数以及去重逻辑。Page({ data: { cameraVisible: true, flashOn: false, scanList: [], lastScanResult: , lastScanTime: 0, scannedSet: {}, // 用于去重的集合 }, onLoad() { // 页面加载时检查相机权限 this.checkCameraAuth(); }, onShow() { // 页面显示时重新渲染 camera 组件 this.setData({ cameraVisible: true }); }, onHide() { // 页面隐藏时销毁 camera 组件释放相机 this.setData({ cameraVisible: false }); }, onUnload() { // 页面卸载时确保相机释放 this.setData({ cameraVisible: false }); }, // 检查相机权限 checkCameraAuth() { wx.getSetting({ success: (res) { if (!res.authSetting[scope.camera]) { wx.authorize({ scope: scope.camera, success: () { console.log(相机权限已授权); }, fail: () { wx.showModal({ title: 需要相机权限, content: 扫码功能需要使用相机请在设置中开启, confirmText: 去设置, success: (modalRes) { if (modalRes.confirm) { wx.openSetting(); } } }); } }); } } }); }, // 扫码结果处理 onScanCode(e) { const { result } e.detail; const now Date.now(); const DEDUP_INTERVAL 3000; // 3秒内相同结果视为重复 // 去重逻辑 if (result this.data.lastScanResult) { if (now - this.data.lastScanTime DEDUP_INTERVAL) { // 3秒内相同结果忽略 return; } } // 更新最近扫码记录 this.setData({ lastScanResult: result, lastScanTime: now, }); // 检查是否已经扫过 if (this.data.scannedSet[result]) { // 已经扫过给出提示但不重复添加 wx.showToast({ title: 该码已扫描过, icon: none, duration: 1000, }); return; } // 新码加入列表 const newList [...this.data.scanList, result]; const newSet { ...this.data.scannedSet, [result]: true }; this.setData({ scanList: newList, scannedSet: newSet, }); // 震动反馈 wx.vibrateShort({ type: medium }); // 提示音可选 // this.playBeep(); }, // 相机错误处理 onCameraError(e) { console.error(相机错误:, e.detail); wx.showToast({ title: 相机启动失败请检查权限, icon: none, duration: 2000, }); }, // 切换闪光灯 toggleFlash() { this.setData({ flashOn: !this.data.flashOn }); }, // 完成扫码 finishScan() { const { scanList } this.data; if (scanList.length 0) { wx.showToast({ title: 还没有扫描任何码, icon: none }); return; } // 这里可以把 scanList 提交到后端 console.log(扫码结果:, scanList); wx.showModal({ title: 扫码完成, content: 共扫描 ${scanList.length} 个码是否提交, success: (res) { if (res.confirm) { // 提交逻辑 this.submitScanResults(scanList); } } }); }, // 提交扫码结果 submitScanResults(list) { wx.showLoading({ title: 提交中... }); // 模拟提交 setTimeout(() { wx.hideLoading(); wx.showToast({ title: 提交成功, icon: success }); // 重置状态 this.setData({ scanList: [], scannedSet: {}, lastScanResult: , lastScanTime: 0, }); }, 1000); }, });这段代码有几个关键设计点需要展开说明。去重逻辑的双层设计。第一层是“时间窗口去重”用lastScanResult和lastScanTime判断是否在 3 秒内重复触发。第二层是“集合去重”用scannedSet记录所有已扫过的码防止同一个码在间隔较长时间后被再次扫入。两层配合既能防止连续触发导致的重复又能防止用户无意中重复扫描同一个码。震动反馈的重要性。在连续扫码场景中用户往往不会一直盯着屏幕看可能在看商品或者看货架。这时候声音和震动反馈就非常重要。wx.vibrateShort是微信提供的短震动 API在扫码成功时触发用户能通过触感确认扫码成功不需要看屏幕。这个细节在实际使用中能大幅提升效率。页面生命周期的处理。onHide和onUnload里都把cameraVisible设为false确保相机资源被释放。onShow里重新设为true让相机重新初始化。这里有一个小问题页面从隐藏到显示时camera 组件重新创建需要一点时间用户会看到短暂的“相机初始化中”提示。这个延迟在安卓上大约 200-300msiOS 上大约 100-200ms基本可以接受。4.3 样式处理与 UI 细节camera 组件是原生组件层级最高普通的view无法覆盖在它上面。所以扫码框、提示文字这些覆盖层必须用cover-view和cover-image。.scan-container { display: flex; flex-direction: column; height: 100vh; background: #000; } .camera-area { flex: 1; width: 100%; position: relative; } .scan-frame { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 500rpx; height: 500rpx; } .scan-corner { position: absolute; width: 60rpx; height: 60rpx; border-color: #00ff00; border-style: solid; } .top-left { top: 0; left: 0; border-width: 4rpx 0 0 4rpx; } .top-right { top: 0; right: 0; border-width: 4rpx 4rpx 0 0; } .bottom-left { bottom: 0; left: 0; border-width: 0 0 4rpx 4rpx; } .bottom-right { bottom: 0; right: 0; border-width: 0 4rpx 4rpx 0; } .bottom-bar { display: flex; justify-content: space-between; align-items: center; padding: 20rpx 30rpx; background: #1a1a1a; } .scan-count { color: #fff; font-size: 28rpx; } .btn-group { display: flex; gap: 20rpx; } .btn-flash, .btn-finish { font-size: 26rpx; padding: 10rpx 30rpx; border-radius: 40rpx; } .btn-flash { background: #333; color: #fff; } .btn-finish { background: #07c160; color: #fff; } .scan-list { height: 300rpx; background: #111; } .scan-item { display: flex; align-items: center; padding: 16rpx 30rpx; border-bottom: 1rpx solid #222; } .scan-index { width: 50rpx; color: #07c160; font-size: 26rpx; } .scan-result { flex: 1; color: #ccc; font-size: 26rpx; word-break: break-all; }样式方面有几个经验点。扫码框用四个角的边框来画比画一个完整的矩形框更清爽也不会遮挡太多相机画面。底部操作栏用深色背景和相机画面形成对比按钮用微信绿#07c160作为主操作色符合用户习惯。已扫列表放在底部高度固定可以滚动用户扫完一个码可以快速确认结果。5. 那些官方文档不会告诉你的坑5.1 安卓与 iOS 的行为差异这是最让人头疼的部分。camera组件在安卓和 iOS 上的表现差异比想象中大得多。识别速度差异。iOS 的识别速度明显快于安卓。同一个二维码iPhone 基本是“对准即识别”安卓有时候需要稍微停留一下。这个差异在扫密集排列的条码时特别明显。我的应对策略是在 UI 上给用户一个“正在识别”的视觉反馈比如扫码框呼吸灯效果让用户知道系统在工作不要急着移开。重复触发频率差异。前面提到过iOS 上同一个码的重复触发间隔大约是 300-500ms安卓上是 500-800ms。这意味着去重的时间窗口不能设得太短否则安卓上会漏掉一些重复触发。我最终把去重窗口设为 3 秒这个值在两端都能很好地工作。闪光灯行为差异。在 iOS 上flashtorch会打开常亮补光灯效果很好。但在部分安卓机型上torch模式可能不生效或者亮度很低。如果闪光灯对你的场景很重要建议在代码里加一个检测逻辑如果torch不生效降级为flashon模式虽然这个模式在扫码时体验不好但至少能补光。相机初始化时间差异。iOS 上 camera 组件初始化大约 100-200ms安卓上 200-500ms 不等低端安卓机可能超过 1 秒。所以“相机初始化中”的提示是必要的不要让用户面对一个黑屏。5.2 基础库版本与兼容性处理camera组件的scanCode模式要求基础库 2.7.0 及以上。虽然现在大部分用户的微信版本都远高于这个但仍然需要做兼容处理。我的做法是在页面加载时检查基础库版本onLoad() { const systemInfo wx.getSystemInfoSync(); const SDKVersion systemInfo.SDKVersion; const compareVersion (v1, v2) { const arr1 v1.split(.).map(Number); const arr2 v2.split(.).map(Number); const len Math.max(arr1.length, arr2.length); while (arr1.length len) arr1.push(0); while (arr2.length len) arr2.push(0); for (let i 0; i len; i) { if (arr1[i] arr2[i]) return 1; if (arr1[i] arr2[i]) return -1; } return 0; }; if (compareVersion(SDKVersion, 2.7.0) 0) { wx.showModal({ title: 版本过低, content: 当前微信版本不支持连续扫码功能请升级微信后再试, showCancel: false, }); return; } }这段版本比较函数是通用的建议放在工具函数里复用。如果版本低于 2.7.0直接提示用户升级不要尝试降级方案因为降级到wx.scanCode的体验落差太大不如不做。5.3 相机权限被拒绝后的处理相机权限是敏感权限用户可能拒绝。如果用户拒绝了camera组件会触发binderror但错误信息比较模糊。更好的做法是主动检查权限状态。wx.getSetting({ success: (res) { if (res.authSetting[scope.camera] false) { // 用户之前拒绝过引导去设置页开启 wx.showModal({ title: 相机权限未开启, content: 扫码需要使用相机请在设置中开启相机权限, confirmText: 去设置, success: (modalRes) { if (modalRes.confirm) { wx.openSetting({ success: (settingRes) { if (settingRes.authSetting[scope.camera]) { // 用户开启了权限重新初始化相机 this.setData({ cameraVisible: true }); } } }); } } }); } } });这里有一个细节wx.openSetting只能由用户点击触发不能在代码里自动调用。所以必须通过showModal引导用户点击“去设置”按钮才能打开设置页。这个流程虽然多了一步但符合微信的规范不会被审核拒绝。5.4 连续扫码时的性能优化连续扫几十个码之后页面可能会变得卡顿。原因主要有两个一是setData频繁调用导致数据传输量大二是已扫列表越来越长渲染压力大。优化方案合并 setData 调用。扫码事件里不要多次调用setData把需要更新的数据合并成一次调用。比如scanList和scannedSet一起更新。限制列表渲染长度。已扫列表不需要显示全部只显示最近 20 条即可。用scanList.slice(-20)来截取。使用虚拟列表。如果确实需要显示全部考虑用recycle-view等虚拟列表组件但实现复杂度较高一般场景用截取就够了。避免在扫码回调里做复杂计算。扫码回调应该尽量轻量复杂的业务逻辑比如网络请求应该异步处理不要阻塞扫码事件。我实测下来做了这些优化之后连续扫 100 个码页面依然流畅没有明显卡顿。6. 常见问题速查表与排查思路6.1 扫码相关高频问题问题现象可能原因排查思路解决方案camera 组件不显示基础库低于 2.7.0检查 SDKVersion提示用户升级微信扫码无反应相机权限被拒绝检查 authSetting引导用户去设置页开启同一个码重复录入未做去重处理检查 onScanCode 逻辑加时间窗口集合去重页面隐藏后相机仍占用未销毁 camera 组件检查 onHide 逻辑用 wx:if 控制组件销毁安卓上闪光灯不亮机型兼容性问题真机测试降级为 flashon扫码识别慢相机对焦问题检查 device-position确保使用后置摄像头连续扫码后页面卡顿setData 频繁调用检查 setData 次数合并 setData限制列表长度iOS 上扫码框被遮挡cover-view 层级问题检查 cover-view 使用确保覆盖层用 cover-view扫码结果乱码编码问题检查二维码编码格式用 decodeURIComponent 处理相机启动失败其他应用占用相机检查后台应用提示用户关闭其他相机应用6.2 几个容易被忽略的细节扫码结果的编码处理。有些二维码的内容是 URL 编码的直接显示会是乱码。建议在拿到结果后做一次decodeURIComponent但要注意捕获异常因为不是所有结果都是编码过的。let result e.detail.result; try { result decodeURIComponent(result); } catch (err) { // 解码失败使用原始结果 console.warn(解码失败使用原始结果:, err); }扫码结果为空的情况。极少数情况下bindscancode会触发但result为空字符串。这种情况直接忽略即可不要加入列表。连续扫码的节流。虽然 camera 组件本身有识别间隔但在业务层面加一个节流会更稳妥。比如设置一个 500ms 的节流窗口窗口内的扫码事件直接丢弃。这样可以进一步降低重复触发的概率。页面跳转时的处理。如果扫码过程中用户点击了某个按钮跳转到其他页面要确保在跳转前把cameraVisible设为false否则相机可能在新页面加载后仍然被占用。6.3 真机调试 vs 开发者工具这里必须强调camera 组件的很多行为在开发者工具里和真机上完全不一样。开发者工具里 camera 组件可能根本不显示或者显示的是电脑摄像头画面扫码识别逻辑也可能不触发。所以 camera 相关的功能必须用真机调试。真机调试的步骤在开发者工具里点击“真机调试”用手机微信扫描弹出的二维码在手机上进行扫码测试通过开发者工具的调试面板查看日志和错误如果真机调试时发现 camera 组件不显示先检查手机是否给了微信相机权限。安卓上还要检查是否被其他应用占用了相机。7. 一些进阶玩法与扩展思路7.1 扫码结果实时校验在仓储盘点场景中扫到的码需要和系统里的数据进行比对。可以在扫码回调里加一个校验逻辑如果扫到的码不在预期列表中给出不同的提示音和震动模式。onScanCode(e) { const { result } e.detail; // ... 去重逻辑 ... // 校验逻辑 const isValid this.checkCodeValidity(result); if (isValid) { wx.vibrateShort({ type: medium }); // 正常提示音 } else { wx.vibrateLong(); wx.showToast({ title: 无效码, icon: none }); // 错误提示音 } }这种即时反馈能让操作员立刻知道扫的码对不对不需要事后核对效率提升明显。7.2 批量扫码后的数据提交连续扫码会产生一批数据这些数据通常需要提交到后端。提交时要注意数据量大时分批提交避免单次请求体过大提交失败时要保留本地数据支持重试提交过程中要防止用户重复提交我的做法是用一个submitting标志位控制提交时禁用“完成”按钮提交成功后再重置状态。7.3 扫码历史记录与断点续扫如果扫码过程中小程序被意外关闭比如用户接了个电话已扫的数据会丢失。对于需要扫几百个码的场景这是不可接受的。解决方案是把已扫列表实时存入wx.setStorageSync页面加载时从缓存恢复。这样即使小程序被关闭重新打开后还能继续扫。// 每次扫码后保存 wx.setStorageSync(scan_list, this.data.scanList); // 页面加载时恢复 onLoad() { const savedList wx.getStorageSync(scan_list) || []; if (savedList.length 0) { wx.showModal({ title: 发现未完成的扫码记录, content: 上次扫描了 ${savedList.length} 个码是否继续, success: (res) { if (res.confirm) { this.setData({ scanList: savedList }); } else { wx.removeStorageSync(scan_list); } } }); } }这个功能在实际使用中非常实用尤其是盘点场景操作员可能扫到一半需要去做别的事断点续扫能避免重复劳动。8. 我个人在实际项目中的几点体会做这个连续扫码功能前前后后花了大概两周时间其中大部分时间不是在写代码而是在真机上测试和调整。有几点体会比较深。第一不要相信开发者工具里的表现。camera 组件在开发者工具里基本没法用所有测试都必须上真机。而且至少要准备一台安卓和一台 iOS因为两端差异真的很大。第二去重逻辑要比想象中复杂。一开始我以为简单判断一下就行后来发现要考虑时间窗口、集合去重、用户有意重复扫等多种情况。最终的去重逻辑改了三四版才稳定下来。第三用户体验的细节决定成败。震动反馈、提示音、扫码框动画、已扫列表的实时更新这些细节看起来不起眼但在连续扫码场景中每一个都能明显影响操作效率。尤其是震动反馈操作员不用看屏幕就能知道扫码成功这个体验提升是巨大的。第四异常处理要全面。相机权限被拒、相机启动失败、扫码结果为空、页面隐藏后相机未释放这些异常情况在开发阶段可能不会遇到但上线后一定会出现。提前处理好这些异常能省下很多客服成本。最后分享一个小技巧如果扫码场景的光线条件不好除了开闪光灯还可以在扫码框周围加一圈半透明的白色边框利用屏幕自身的光来补光。这个技巧在扫反光材质的条码时特别有用能明显提升识别率。
返回列表