在移动应用开发中,条形码和二维码扫描是一个常见的需求。很多应用都自带了扫码功能,但是只能做单码扫描,一般用于个人登录,付款等简单场景。在物流,仓储等商业场景中,扫码需求则更加复杂,需要支持多码识别,高精度识别以及多种码制的支持。
本文将分享如何在微信小程序中集成 Dynamsoft Barcode Reader JS WebAssembly SDK,实现高性能的1D/2D多码扫描功能。

一、技术选型:为什么选择 Dynamsoft Barcode Reader
1.1 需求背景
微信小程序虽然提供了原生的 wx.scanCode API,但在某些场景下存在明显的局限性:
- 无法自定义扫码界面和交互逻辑
- 识别精度和速度受限于系统实现
- 无法满足复杂的扫码需求(如批量扫码、特定格式识别等)
因此,我们需要一个能够在小程序环境中运行的高性能扫码引擎。
1.2 Dynamsoft Barcode Reader 的优势
Dynamsoft Barcode Reader 是一款企业级的条码识别 SDK,其 WebAssembly 版本特别适合在微信小程序中使用:
- 高精度识别:支持多种条码格式,识别率高
- 高性能:基于 WebAssembly,性能接近原生
- 丰富的配置:提供多种识别模板和参数调优选项
- 跨平台:同一套代码可在不同平台运行
SDK包含:
BarcodeReader.js
dbr.worker.js
dynamsoft-barcode-reader-bundle-ml-simd.js
dynamsoft-barcode-reader-bundle-ml-simd.wasm.br
二、初步集成:从 WASM 加载开始
2.1 微信小程序的 WASM 支持
微信小程序提供了 WXWebAssembly.instantiate API 来加载 WASM 模块。与标准的 Web 环境不同,小程序有一些特殊的限制:
- 不支持直接使用
WebAssembly对象,必须使用WXWebAssembly - WASM 文件必须放在小程序包内,不能动态下载
- 主包大小限制为 2MB,总包大小限制为 20MB
2.2 WASM 文件的加载
在 Dynamsoft Barcode Reader 中,我们需要正确配置 WASM 文件的路径:
await DBR.BarcodeReader.loadWasm("workers/dbr.worker.js", "subpackages/dbr/wasm/dynamsoft-barcode-reader-bundle-ml-simd.wasm.br");
三、分包加载:解决主包大小限制
Dynamsoft Barcode Reader 的 WASM 文件压缩(.wasm.br)后小于2MB。将 WASM 文件放入分包目录 subpackages/dbr/ 中,这样就不会占用主包的空间。
{
"subpackages": [
{
"root": "subpackages/dbr",
"name": "dbr",
"pages": [
"pages/scan/index",
"pages/camera-scan/index",
"pages/file-scan/index"
]
}
]
}
3.1 延迟初始化策略
由于 WASM 文件位于分包中,如果主包启动时(app.js 的 onLaunch)立即尝试加载 WASM,可能会因为分包尚未下载完成而失败。
最佳实践是采用延迟初始化:
- 在
app.js中定义initSDK方法,但不立即调用。 - 在分包页面的
onLoad生命周期中调用app.initSDK()。
// app.js
initSDK: async function () {
if (this.globalData.wasmInitialized) return;
// 加载 WASM
await DBR.BarcodeReader.loadWasm("workers/dbr.worker.js", "subpackages/dbr/wasm/dynamsoft-barcode-reader-bundle-ml-simd.wasm.br");
// 初始化 License
await DBR.BarcodeReader.initLicense("YOUR_LICENSE");
this.globalData.wasmInitialized = true;
}
// subpackages/dbr/pages/scan/index.js
onLoad: async function() {
await getApp().initSDK();
}
四、视频帧数据传输和处理
通过onCameraFrame接口获取视频帧数据,然后发送到worker中进行处理。针对iOS, Android和HarmonyOS,需要使用不同的方法。capture接口封装了worker以及帧数据处理逻辑。
const listener = context.onCameraFrame(async (frame) => {
if (!this.data.isDetecting || this.isProcessing) return;
this.isProcessing = true;
try {
const app = getApp();
if (app.globalData.BarcodeReader) {
this.currentFrameSize = { width: frame.width, height: frame.height };
let captureOptions = {
width: frame.width,
height: frame.height,
stride: frame.width * 4,
format: 10
};
let transfer = false;
if (this.data.isAndroid) {
captureOptions.bytes = frame.data;
transfer = true;
} else if (this.data.isHarmony) {
captureOptions.bytes = frame.data;
transfer = false;
} else if (this.data.isIOS) {
captureOptions.bytes = null;
} else {
captureOptions.bytes = frame.data;
}
try {
const result = await app.globalData.BarcodeReader.capture(captureOptions, this.dynamsoftTemplate, transfer);
this.handleDynamsoftResult({ captureResult: result });
} catch (e) {
console.error("Capture failed:", e);
this.isProcessing = false;
}
} else {
this.isProcessing = false;
}
} catch (ex) {
console.error(ex);
if (this.data.isDetecting) {
this.setData({ scanResult: "Error: " + (ex.message || ex) });
}
this.isProcessing = false;
}
});
const app = getApp();
listener.start({
worker: app.globalData.BarcodeReader.worker
});
- iOS上可以通过getCameraFrameData在worker中获取帧数据。这样就不需要通过前端获取帧数据,提升性能。
- Android上可以通过
postMessage(buf, [buf])传输ArrayBuffer,避免数据复制,实现零拷贝。 - HarmonyOS上支持比较差,只能通过
postMessage(buf)拷贝数据的方式传输。
五、源码获取
需要源码,可以联系cnsupport@damingsoft.com,或者微信hzdamingsoft。

六、小程序演示

