如何在Flutter Web项目中引入JavaScript类库实现条码扫描
Flutter Web 条码扫描实现方案(基于JS库集成)
因为pub.dev上多数条码扫描库不支持Web端,用js和import_js_library集成ZXing-js是可行方案,具体操作步骤如下:
1. 添加依赖
在项目的pubspec.yaml中添加两个依赖:
dependencies: flutter: sdk: flutter js: ^0.6.7 import_js_library: ^1.0.1
执行flutter pub get安装依赖。
2. 引入JS库到Web入口
在web/index.html的<head>标签内插入ZXing-js的CDN链接:
<script src="https://unpkg.com/@zxing/library@latest"></script>
3. 封装JS类的Dart绑定
新建barcode_scanner_web.dart文件,用js库绑定ZXing的核心类:
import 'package:js/js.dart'; // 绑定ZXing的BrowserMultiFormatReader类 @JS('ZXing.BrowserMultiFormatReader') class BrowserMultiFormatReader { external factory BrowserMultiFormatReader(); // 绑定从视频流解码的方法 external void decodeFromVideoElement(String videoId, Function(String result) callback); // 绑定停止扫描的方法 external void reset(); }
4. 实现扫描页面Widget
创建包含扫描逻辑的Flutter Widget,用HtmlElementView嵌入视频元素并调用JS扫描功能:
import 'dart:html' as html; import 'package:flutter/material.dart'; import 'package:import_js_library/import_js_library.dart'; import 'barcode_scanner_web.dart'; class BarcodeScannerWeb extends StatefulWidget { const BarcodeScannerWeb({super.key}); @override State<BarcodeScannerWeb> createState() => _BarcodeScannerWebState(); } class _BarcodeScannerWebState extends State<BarcodeScannerWeb> { final String videoId = 'barcode-scan-video'; BrowserMultiFormatReader? _scanner; @override void initState() { super.initState(); // 等待JS库加载完成后初始化扫描器 importLibrary('https://unpkg.com/@zxing/library@latest').then((_) { _initScanner(); }); } void _initScanner() { _scanner = BrowserMultiFormatReader(); // 启动扫描,传入视频元素ID和扫描结果回调 _scanner!.decodeFromVideoElement(videoId, allowInterop((String result) { if (mounted) { // 处理扫描结果,这里用SnackBar展示 ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('扫描到条码:$result')), ); // 停止扫描释放资源 _scanner?.reset(); } })); } @override void dispose() { _scanner?.reset(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Web条码扫描')), body: Center( child: SizedBox( width: 320, height: 240, // 嵌入HTML视频元素用于摄像头采集 child: HtmlElementView( viewType: videoId, onPlatformViewCreated: (int id) { final videoElement = html.VideoElement() ..id = videoId ..width = 320 ..height = 240 ..autoplay = true ..style.border = '1px solid #ddd'; // 请求摄像头权限并绑定视频流 html.window.navigator.mediaDevices.getUserMedia({'video': true}) .then((stream) { videoElement.srcObject = stream; }).catchError((err) { // 处理用户拒绝摄像头权限的情况 if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('需要摄像头权限才能扫描')), ); } }); // 将视频元素添加到页面DOM html.document.body?.append(videoElement); }, ), ), ), ); } }
关键注意事项
- 测试时必须用HTTPS环境(本地
localhost除外),浏览器摄像头权限仅支持安全上下文 - 务必处理用户拒绝摄像头权限的情况,避免无提示报错
- 扫描完成后调用
reset()方法停止扫描,避免资源浪费
内容的提问来源于stack exchange,提问作者KM Flutter
相关产品推荐
相关产品推荐

