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

Flutter在Linux及Chrome Web平台实现QR扫码遇qrview不支持错误求助

解决Flutter Linux/Web平台二维码扫码的不支持错误

错误原因

你使用的qr_code_scanner库仅支持iOS和Android平台,没有为Linux、Web提供默认实现,因此运行时抛出Unsupported operation: Trying to use the default qrview implementation for TargetPlatform.linux but there isn't a default one错误。


方案1:切换支持多平台的扫码库(推荐)

使用mobile_scanner库,它原生支持Android、iOS、Web、Linux等多平台,无需额外适配即可实现摄像头扫码。

步骤1:替换依赖

修改pubspec.yaml,移除qr_code_scanner,添加mobile_scanner:

dependencies:
  flutter:
    sdk: flutter
  mobile_scanner: ^4.0.0 # 使用最新版本
  url_launcher: ^6.2.0

步骤2:修改扫码组件代码

替换原Scanner组件为以下适配代码:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:url_launcher/url_launcher.dart';

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

  @override
  _ScannerState createState() => _ScannerState();
}

class _ScannerState extends State<Scanner> {
  MobileScannerController? controller;
  bool isScanning = true;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Center(child: Text("Scan the Building QR Code")),
      ),
      body: Stack(
        children: [
          MobileScanner(
            controller: MobileScannerController(
              detectionSpeed: DetectionSpeed.normal,
              facing: CameraFacing.back,
            ),
            onDetect: (capture) async {
              if (!isScanning) return;
              isScanning = false;

              final List<Barcode> barcodes = capture.barcodes;
              if (barcodes.isNotEmpty) {
                final code = barcodes.first.rawValue;
                if (code != null) {
                  if (await canLaunchUrl(Uri.parse(code))) {
                    await launchUrl(Uri.parse(code));
                  } else {
                    await showDialog(
                      context: context,
                      builder: (context) => AlertDialog(
                        title: const Text('Could not find viable URL'),
                        content: SingleChildScrollView(
                          child: ListBody(
                            children: [
                              Text('Barcode Type: ${barcodes.first.format.name}'),
                              Text('Data: $code'),
                            ],
                          ),
                        ),
                        actions: [
                          TextButton(
                            child: const Text('OK'),
                            onPressed: () => Navigator.of(context).pop(),
                          ),
                        ],
                      ),
                    );
                  }
                }
              }
              // 延迟恢复扫描,避免重复触发
              await Future.delayed(const Duration(seconds: 2));
              isScanning = true;
            },
          ),
          Center(
            child: Container(
              width: 300,
              height: 300,
              decoration: BoxDecoration(
                border: Border.all(color: Colors.black, width: 4),
                borderRadius: BorderRadius.circular(12),
              ),
            ),
          )
        ],
      ),
    );
  }
}

方案2:针对Linux/Web平台做兼容适配(保留原库)

如果需要继续使用qr_code_scanner,可以通过平台判断,为Linux/Web提供图片解析扫码的替代方案:

步骤1:添加依赖

新增图片选择和二维码解析库:

dependencies:
  qr_code_scanner: ^1.0.1
  url_launcher: ^6.2.0
  image_picker: ^1.0.4
  qr_code_parser: ^1.0.0

步骤2:修改组件代码,添加平台判断

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:qr_code_parser/qr_code_parser.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:image/image.dart' as img;

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

  @override
  _ScannerState createState() => _ScannerState();
}

class _ScannerState extends State<Scanner> {
  final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
  late QRViewController controller;

  @override
  void dispose() {
    if (!kIsWeb && defaultTargetPlatform != TargetPlatform.linux) {
      controller.dispose();
    }
    super.dispose();
  }

  // 解析本地图片二维码
  Future<void> _scanFromImage() async {
    final picker = ImagePicker();
    final pickedFile = await picker.pickImage(source: ImageSource.gallery);
    if (pickedFile == null) return;

    final bytes = await pickedFile.readAsBytes();
    final image = img.decodeImage(bytes);
    if (image == null) return;

    final result = await QrCodeParser().parse(image);
    if (result != null) {
      _handleScanResult(result.code);
    }
  }

  // 处理扫描结果
  Future<void> _handleScanResult(String? code) async {
    if (code == null) return;
    if (await canLaunchUrl(Uri.parse(code))) {
      await launchUrl(Uri.parse(code));
    } else {
      await showDialog(
        context: context,
        builder: (context) => AlertDialog(
          title: const Text('Could not find viable URL'),
          content: SingleChildScrollView(
            child: ListBody(
              children: [
                const Text('Barcode Type: QR Code'),
                Text('Data: $code'),
              ],
            ),
          ),
          actions: [
            TextButton(
              child: const Text('OK'),
              onPressed: () => Navigator.of(context).pop(),
            ),
          ],
        ),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Center(child: Text("Scan the Building QR Code")),
      ),
      body: kIsWeb || defaultTargetPlatform == TargetPlatform.linux
          ? Center(
              child: ElevatedButton(
                onPressed: _scanFromImage,
                child: const Text("选择二维码图片扫码"),
              ),
            )
          : Stack(
              children: [
                Column(
                  children: [
                    Expanded(
                      flex: 4,
                      child: Stack(
                        children: [
                          QRView(
                            key: qrKey,
                            onQRViewCreated: (QRViewController controller) {
                              this.controller = controller;
                              controller.scannedDataStream.listen((scanData) {
                                controller.pauseCamera();
                                _handleScanResult(scanData.code).then((_) => controller.resumeCamera());
                              });
                            },
                          ),
                          Center(
                            child: Container(
                              width: 300,
                              height: 300,
                              decoration: BoxDecoration(
                                border: Border.all(color: Colors.black, width: 4),
                                borderRadius: BorderRadius.circular(12),
                              ),
                            ),
                          )
                        ],
                      ),
                    ),
                  ],
                ),
              ],
            ),
    );
  }
}

额外注意事项

  • Web平台:如果使用摄像头扫码,需要在web/index.html中添加摄像头权限声明:
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="permission" content="camera">
    
  • Linux平台:如果使用摄像头扫码,需要确保应用已获取摄像头权限,可通过系统设置手动授权。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:54:24