You need to enable JavaScript to run this app. Flutter zxing2 pub包官方示例运行报错,求可用的实现示例
优惠活动
大模型
产品
解决方案
定价
更多

Flutter zxing2 pub包官方示例运行报错,求可用的实现示例

ZXing2 Flutter 可用运行示例及问题修复

错误说明

你遇到的报错核心原因是官方示例没有正确处理相机初始化的异步逻辑,在CameraController的initialize()方法执行完成前就调用了startImageStream(),触发了未初始化异常。

前置配置

依赖配置

在pubspec.yaml中添加如下依赖:

dependencies:
  flutter:
    sdk: flutter
  zxing2: ^0.2.1
  camera: ^0.10.5+5

权限配置

  • Android端:在android/app/src/main/AndroidManifest.xml的manifest标签内添加:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
  • iOS端:在ios/Runner/Info.plist的dict标签内添加:
<key>NSCameraUsageDescription</key>
<string>需要相机权限扫描二维码/条形码</string>

完整可运行代码

import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:zxing2/zxing2.dart';

late List<CameraDescription> cameras;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  cameras = await availableCameras();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ZXing2 扫描示例',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const ScanPage(),
    );
  }
}

class ScanPage extends StatefulWidget {
  const ScanPage({super.key});

  @override
  State<ScanPage> createState() => _ScanPageState();
}

class _ScanPageState extends State<ScanPage> {
  CameraController? _cameraController;
  final BarcodeReader _barcodeReader = BarcodeReader();
  String? _scanResult;
  bool _isScanning = false;

  @override
  void initState() {
    super.initState();
    _initCamera();
  }

  Future<void> _initCamera() async {
    // 优先选择后置摄像头
    final CameraDescription backCamera = cameras.firstWhere(
      (cam) => cam.lensDirection == CameraLensDirection.back,
      orElse: () => cameras.first,
    );

    _cameraController = CameraController(
      backCamera,
      ResolutionPreset.medium,
      enableAudio: false,
      imageFormatGroup: ImageFormatGroup.yuv420,
    );

    // 等待相机完全初始化后再执行后续操作
    await _cameraController?.initialize();
    if (!mounted) return;
    setState(() {});

    _startScanning();
  }

  Future<void> _startScanning() async {
    if (_isScanning || _cameraController == null || !_cameraController!.value.isInitialized) return;
    _isScanning = true;

    await _cameraController?.startImageStream((cameraImage) async {
      try {
        final PlanarYUVLuminanceSource source = PlanarYUVLuminanceSource(
          cameraImage.planes[0].bytes,
          cameraImage.width,
          cameraImage.height,
          0,
          0,
          cameraImage.width,
          cameraImage.height,
          false,
        );
        final BinaryBitmap bitmap = BinaryBitmap(HybridBinarizer(source));
        final Result result = _barcodeReader.decode(bitmap);

        if (result.text.isNotEmpty) {
          // 扫描到结果后停止流
          await _cameraController?.stopImageStream();
          _isScanning = false;
          setState(() {
            _scanResult = result.text;
          });
        }
      } catch (_) {
        // 未识别到条码时静默处理
      }
    });
  }

  @override
  void dispose() {
    _cameraController?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (_cameraController == null || !_cameraController!.value.isInitialized) {
      return const Scaffold(
        body: Center(child: CircularProgressIndicator()),
      );
    }

    return Scaffold(
      appBar: AppBar(title: const Text('ZXing2 扫描演示')),
      body: Column(
        children: [
          Expanded(child: CameraPreview(_cameraController!)),
          if (_scanResult != null)
            Padding(
              padding: const EdgeInsets.all(16),
              child: Text(
                '扫描结果:$_scanResult',
                style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
              ),
            ),
          if (_scanResult != null)
            ElevatedButton(
              onPressed: () {
                setState(() => _scanResult = null);
                _startScanning();
              },
              child: const Text('重新扫描'),
            ),
          const SizedBox(height: 24),
        ],
      ),
    );
  }
}

核心修复点

  • 主函数中提前初始化相机列表,避免页面初始化时异步获取相机导致的时序问题
  • 相机控制器初始化添加await,完全初始化完成后再启动图像流
  • 新增扫描状态标记,避免重复启动图像流导致异常
  • 增加未初始化状态的加载页,避免空视图问题
  • 识别到结果后自动停止图像流,减少性能消耗

内容的提问来源于stack exchange,提问作者Nirmala Sudhir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 15:39:02