You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 19:03:39