Flutter二维码扫描插件qr_code_scanner_plus的使用

发布于 1周前 作者 yuanlaile 来自 Flutter

Flutter二维码扫描插件qr_code_scanner_plus的使用

描述

qr_code_scanner_plus 是一个基于 qr_code_scanner 库的分支,包含一些额外的维护工作。这个插件可以在Flutter应用程序中嵌入原生视图以进行二维码扫描,同时在iOS和Android上都具有无缝集成的效果。

需要注意的是,由于底层框架(Android上的 zxing 和 iOS 上的 MTBBarcodeScanner)都不再被维护,因此该插件也仅处于维护模式,只会考虑修复错误和进行小幅度增强。开发者正在开发一个新的插件 mobile_scanner,它使用最新的MLKit版本来检测条形码和二维码,并且在Android上使用CameraX,在iOS上使用AVFoundation来获得最佳的相机性能。

使用方法

添加依赖

首先,在您的pubspec.yaml文件中添加qr_code_scanner_plus作为依赖项:

dependencies:
  qr_code_scanner_plus: ^latest_version # 替换为最新版本号

然后运行flutter pub get来安装包。

示例代码

下面是一个完整的示例Demo,展示了如何使用qr_code_scanner_plus创建一个简单的二维码扫描页面。

import 'dart:developer';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart';

void main() => runApp(const MaterialApp(home: MyHome()));

class MyHome extends StatelessWidget {
  const MyHome({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Flutter Demo Home Page')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(
              builder: (context) => const QRViewExample(),
            ));
          },
          child: const Text('Open QR Scanner'),
        ),
      ),
    );
  }
}

class QRViewExample extends StatefulWidget {
  const QRViewExample({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _QRViewExampleState();
}

class _QRViewExampleState extends State<QRViewExample> {
  Barcode? result;
  QRViewController? controller;
  final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');

  // 热重载时暂停或恢复摄像头
  @override
  void reassemble() {
    super.reassemble();
    if (Platform.isAndroid) {
      controller!.pauseCamera();
    }
    controller!.resumeCamera();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          Expanded(flex: 4, child: _buildQrView(context)),
          Expanded(
            flex: 1,
            child: FittedBox(
              fit: BoxFit.contain,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  if (result != null)
                    Text(
                        'Barcode Type: ${describeEnum(result!.format)}   Data: ${result!.code}')
                  else
                    const Text('Scan a code'),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      Container(
                        margin: const EdgeInsets.all(8),
                        child: ElevatedButton(
                            onPressed: () async {
                              await controller?.toggleFlash();
                              setState(() {});
                            },
                            child: FutureBuilder(
                              future: controller?.getFlashStatus(),
                              builder: (context, snapshot) {
                                return Text('Flash: ${snapshot.data}');
                              },
                            )),
                      ),
                      Container(
                        margin: const EdgeInsets.all(8),
                        child: ElevatedButton(
                            onPressed: () async {
                              await controller?.flipCamera();
                              setState(() {});
                            },
                            child: FutureBuilder(
                              future: controller?.getCameraInfo(),
                              builder: (context, snapshot) {
                                if (snapshot.data != null) {
                                  return Text(
                                      'Camera facing ${describeEnum(snapshot.data!)}');
                                } else {
                                  return const Text('loading');
                                }
                              },
                            )),
                      )
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      Container(
                        margin: const EdgeInsets.all(8),
                        child: ElevatedButton(
                          onPressed: () async {
                            await controller?.pauseCamera();
                          },
                          child: const Text('Pause', style: TextStyle(fontSize: 20)),
                        ),
                      ),
                      Container(
                        margin: const EdgeInsets.all(8),
                        child: ElevatedButton(
                          onPressed: () async {
                            await controller?.resumeCamera();
                          },
                          child: const Text('Resume', style: TextStyle(fontSize: 20)),
                        ),
                      )
                    ],
                  ),
                ],
              ),
            ),
          )
        ],
      ),
    );
  }

  Widget _buildQrView(BuildContext context) {
    var scanArea = (MediaQuery.of(context).size.width < 400 ||
            MediaQuery.of(context).size.height < 400)
        ? 150.0
        : 300.0;

    return QRView(
      key: qrKey,
      onQRViewCreated: _onQRViewCreated,
      overlay: QrScannerOverlayShape(
          borderColor: Colors.red,
          borderRadius: 10,
          borderLength: 30,
          borderWidth: 10,
          cutOutSize: scanArea),
      onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
    );
  }

  void _onQRViewCreated(QRViewController controller) {
    setState(() {
      this.controller = controller;
    });
    controller.scannedDataStream.listen((scanData) {
      setState(() {
        result = scanData;
      });
    });
  }

  void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
    log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
    if (!p) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('No permission')),
      );
    }
  }

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

此代码实现了以下功能:

  • 打开一个新的页面用于扫描二维码。
  • 显示扫描结果,包括条码类型和数据内容。
  • 提供了切换闪光灯、翻转摄像头以及暂停/恢复扫描的功能按钮。

平台特定配置

Android 配置

确保您已经更新了Gradle、Kotlin以及Kotlin Gradle Plugin到最新版本,并调整了最低SDK版本。

  • android/build.gradle中将ext.kotlin_version设置为’1.5.10’及以上。
  • 同样在android/build.gradle中将classpath 'com.android.tools.build:gradle:设置为4.2.0及以上。
  • android/gradle/wrapper/gradle-wrapper.properties中将distributionUrl设置为gradle-6.9-all.zip及以上。
  • android/app/build.gradle中将minSdkVersion设置为20及以上。

iOS 配置

为了使用此插件,请在Info.plist文件中添加以下键值对:

<key>io.flutter.embedded_views_preview</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan QR codes</string>

此外,如果遇到与Flutter Beta或Dev通道相关的错误,可以尝试通过向gradle.properties文件添加android.enableDexingArtifactTransform=false来解决。

注意事项

  • Web端支持尚处于早期阶段,目前仅支持扫描二维码,其他类型的条形码和二维条码不被支持。
  • 对于Web端,某些特性如闪光灯控制、暂停/恢复等功能尚未实现。

希望这些信息能帮助您顺利地在Flutter项目中集成并使用qr_code_scanner_plus插件!如果有任何问题或者需要进一步的帮助,请随时提问。


更多关于Flutter二维码扫描插件qr_code_scanner_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter二维码扫描插件qr_code_scanner_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter应用中使用qr_code_scanner_plus插件来扫描二维码的详细代码案例。

首先,确保你已经在你的pubspec.yaml文件中添加了qr_code_scanner_plus依赖项:

dependencies:
  flutter:
    sdk: flutter
  qr_code_scanner_plus: ^1.0.0  # 请检查最新版本号

然后运行flutter pub get来安装依赖。

接下来,你需要配置Android和iOS的权限。对于Android,在android/app/src/main/AndroidManifest.xml中添加以下权限:

<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中添加以下权限:

<key>NSCameraUsageDescription</key>
<string>需要访问相机来扫描二维码</string>

现在,你可以在你的Flutter项目中编写代码来实现二维码扫描功能。下面是一个完整的示例:

import 'package:flutter/material.dart';
import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart';
import 'package:qr_code_scanner_plus_platform_interface/models/qr_code_result.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: QrCodeScannerScreen(),
    );
  }
}

class QrCodeScannerScreen extends StatefulWidget {
  @override
  _QrCodeScannerScreenState createState() => _QrCodeScannerScreenState();
}

class _QrCodeScannerScreenState extends State<QrCodeScannerScreen> {
  final QRCodeScannerController _controller = QRCodeScannerController();
  bool _isScanning = false;
  String? _result;

  @override
  void initState() {
    super.initState();
    _controller.initialize().then((_) {
      if (mounted) {
        setState(() {});
      }
      _controller.scannedDataStream.listen((qrCodeResult) {
        setState(() {
          _result = qrCodeResult?.text;
          _isScanning = false;
          _controller.pauseCamera();
        });
      });
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('二维码扫描'),
      ),
      body: _isScanning
          ? Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Expanded(
                  flex: 5,
                  child: QRCodeScanner(
                    controller: _controller,
                    overlay: QrScannerOverlayShape(
                      borderColor: Colors.blue,
                      borderRadius: 10,
                      borderLength: 30,
                      borderWidth: 10,
                      topOffset: 20,
                      rightOffset: 20,
                      bottomOffset: 40,
                      leftOffset: 20,
                      cutOutSize: 50,
                    ),
                  ),
                ),
              ],
            )
          : Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('扫描结果: $_result'),
                SizedBox(height: 20),
                ElevatedButton(
                  onPressed: () {
                    setState(() {
                      _isScanning = true;
                      _result = null;
                      _controller.resumeCamera();
                    });
                  },
                  child: Text('重新扫描'),
                ),
              ],
            ),
    );
  }
}

在这个示例中,我们创建了一个QrCodeScannerScreen,它使用QRCodeScannerController来管理二维码扫描器的状态。我们在initState中初始化控制器,并监听扫描到的数据流。当扫描到二维码时,我们更新状态,停止扫描,并显示结果。

你可以根据需要调整UI和逻辑,例如添加错误处理、优化扫描界面等。希望这个示例对你有帮助!

回到顶部