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

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

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

插件概述

barcode_scan2 是一个用于扫描2D条形码和QR码的Flutter插件。它提供了对iOS和Android平台的支持,并且在原barcode_scan插件停止维护后,作为其替代品重生,支持空安全(null safety)。以下是该插件的一些特性:

  • ✅ 扫描2D条形码
  • ✅ 扫描QR码
  • ✅ 控制扫描时的闪光灯
  • ✅ 权限处理

开始使用

Android配置

  1. 添加相机权限:在AndroidManifest.xml中添加相机权限。

    <uses-permission android:name="android.permission.CAMERA" />
    
  2. 添加Kotlin支持:确保项目支持Kotlin。可以参考Kotlin官方文档进行设置。

  3. 修改build.gradle文件

    • 项目级build.gradle:
      buildscript {
          ext.kotlin_version = '1.3.61'
          dependencies {
              classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
          }
      }
      
    • 应用级build.gradle:
      apply plugin: 'kotlin-android'
      dependencies {
          implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
      }
      
  4. 依赖插件:在pubspec.yaml中添加barcode_scan2依赖。

    dependencies:
        barcode_scan2: any
    
  5. 获取包:点击Android Studio中的"Packages get"或运行flutter packages get

iOS配置

  1. 添加相机使用描述:在Info.plist中添加相机使用描述。
    <dict>
        <key>NSCameraUsageDescription</key>
        <string>Camera permission is required for barcode scanning.</string>
    </dict>
    

使用示例

以下是一个完整的示例代码,展示了如何使用barcode_scan2插件进行二维码扫描,并显示扫描结果。

import 'dart:async';
import 'dart:io' show Platform;

import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(const App());

class App extends StatefulWidget {
  const App({Key? key}) : super(key: key);
  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  ScanResult? scanResult;

  final _flashOnController = TextEditingController(text: 'Flash on');
  final _flashOffController = TextEditingController(text: 'Flash off');
  final _cancelController = TextEditingController(text: 'Cancel');

  var _aspectTolerance = 0.00;
  var _numberOfCameras = 0;
  var _selectedCamera = -1;
  var _useAutoFocus = true;
  var _autoEnableFlash = false;

  static final _possibleFormats = BarcodeFormat.values.toList()
    ..removeWhere((e) => e == BarcodeFormat.unknown);

  List<BarcodeFormat> selectedFormats = [..._possibleFormats];

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

    Future.delayed(Duration.zero, () async {
      _numberOfCameras = await BarcodeScanner.numberOfCameras;
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Barcode Scanner Example'),
          actions: [
            IconButton(
              icon: const Icon(Icons.camera),
              tooltip: 'Scan',
              onPressed: _scan,
            ),
          ],
        ),
        body: ListView(
          shrinkWrap: true,
          children: <Widget>[
            if (scanResult != null)
              Card(
                child: Column(
                  children: <Widget>[
                    ListTile(
                      title: const Text('Result Type'),
                      subtitle: Text(scanResult!.type.toString()),
                    ),
                    ListTile(
                      title: const Text('Raw Content'),
                      subtitle: Text(scanResult!.rawContent),
                    ),
                    ListTile(
                      title: const Text('Format'),
                      subtitle: Text(scanResult!.format.toString()),
                    ),
                    ListTile(
                      title: const Text('Format note'),
                      subtitle: Text(scanResult!.formatNote),
                    ),
                  ],
                ),
              ),
            const ListTile(
              title: Text('Camera selection'),
              dense: true,
              enabled: false,
            ),
            RadioListTile(
              onChanged: (v) => setState(() => _selectedCamera = -1),
              value: -1,
              title: const Text('Default camera'),
              groupValue: _selectedCamera,
            ),
            ...List.generate(
              _numberOfCameras,
              (i) => RadioListTile(
                onChanged: (v) => setState(() => _selectedCamera = i),
                value: i,
                title: Text('Camera ${i + 1}'),
                groupValue: _selectedCamera,
              ),
            ),
            const ListTile(
              title: Text('Button Texts'),
              dense: true,
              enabled: false,
            ),
            ListTile(
              title: TextField(
                decoration: const InputDecoration(
                  floatingLabelBehavior: FloatingLabelBehavior.always,
                  labelText: 'Flash On',
                ),
                controller: _flashOnController,
              ),
            ),
            ListTile(
              title: TextField(
                decoration: const InputDecoration(
                  floatingLabelBehavior: FloatingLabelBehavior.always,
                  labelText: 'Flash Off',
                ),
                controller: _flashOffController,
              ),
            ),
            ListTile(
              title: TextField(
                decoration: const InputDecoration(
                  floatingLabelBehavior: FloatingLabelBehavior.always,
                  labelText: 'Cancel',
                ),
                controller: _cancelController,
              ),
            ),
            if (Platform.isAndroid) ...[
              const ListTile(
                title: Text('Android specific options'),
                dense: true,
                enabled: false,
              ),
              ListTile(
                title: Text(
                  'Aspect tolerance (${_aspectTolerance.toStringAsFixed(2)})',
                ),
                subtitle: Slider(
                  min: -1,
                  value: _aspectTolerance,
                  onChanged: (value) {
                    setState(() {
                      _aspectTolerance = value;
                    });
                  },
                ),
              ),
              CheckboxListTile(
                title: const Text('Use autofocus'),
                value: _useAutoFocus,
                onChanged: (checked) {
                  setState(() {
                    _useAutoFocus = checked!;
                  });
                },
              ),
            ],
            const ListTile(
              title: Text('Other options'),
              dense: true,
              enabled: false,
            ),
            CheckboxListTile(
              title: const Text('Start with flash'),
              value: _autoEnableFlash,
              onChanged: (checked) {
                setState(() {
                  _autoEnableFlash = checked!;
                });
              },
            ),
            const ListTile(
              title: Text('Barcode formats'),
              dense: true,
              enabled: false,
            ),
            ListTile(
              trailing: Checkbox(
                tristate: true,
                materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                value: selectedFormats.length == _possibleFormats.length
                    ? true
                    : selectedFormats.isEmpty
                        ? false
                        : null,
                onChanged: (checked) {
                  setState(() {
                    selectedFormats = [
                      if (checked ?? false) ..._possibleFormats,
                    ];
                  });
                },
              ),
              dense: true,
              enabled: false,
              title: const Text('Detect barcode formats'),
              subtitle: const Text(
                'If all are unselected, all possible '
                'platform formats will be used',
              ),
            ),
            ..._possibleFormats.map(
              (format) => CheckboxListTile(
                value: selectedFormats.contains(format),
                onChanged: (i) {
                  setState(
                    () => selectedFormats.contains(format)
                        ? selectedFormats.remove(format)
                        : selectedFormats.add(format),
                  );
                },
                title: Text(format.toString()),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> _scan() async {
    try {
      final result = await BarcodeScanner.scan(
        options: ScanOptions(
          strings: {
            'cancel': _cancelController.text,
            'flash_on': _flashOnController.text,
            'flash_off': _flashOffController.text,
          },
          restrictFormat: selectedFormats,
          useCamera: _selectedCamera,
          autoEnableFlash: _autoEnableFlash,
          android: AndroidOptions(
            aspectTolerance: _aspectTolerance,
            useAutoFocus: _useAutoFocus,
          ),
        ),
      );
      setState(() => scanResult = result);
    } on PlatformException catch (e) {
      setState(() {
        scanResult = ScanResult(
          rawContent: e.code == BarcodeScanner.cameraAccessDenied
              ? 'The user did not grant the camera permission!'
              : 'Unknown error: $e',
        );
      });
    }
  }
}

高级用法

你可以通过传递选项来定制扫描行为。以下是支持的选项及其说明:

选项 类型 描述 支持平台
strings.cancel String iOS上的取消按钮文本 iOS only
strings.flash_on String 闪光灯开启按钮文本 iOS + Android
strings.flash_off String 闪光灯关闭按钮文本 iOS + Android
restrictFormat BarcodeFormat[] 限制识别的格式 iOS + Android
useCamera int 使用的摄像头索引(见BarcodeScanner.numberOfCameras iOS + Android
autoEnableFlash bool 开始扫描时自动启用闪光灯 iOS + Android
android.aspectTolerance double Android上启用自动对焦 Android only
android.useAutoFocus bool 设置Android上使用的自动对焦选项 Android only

常见问题

Android “Could not find org.jetbrains.kotlin:kotlin-stdlib-jre…”

解决方案是将org.jetbrains.kotlin:kotlin-stdlib-jre改为org.jetbrains.kotlin:kotlin-stdlib-jdk。详情请参阅StackOverflow

通过以上步骤和示例代码,你应该能够顺利地在Flutter项目中集成并使用barcode_scan2插件进行二维码扫描。如果有任何问题或需要进一步的帮助,请随时提问!


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

1 回复

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


当然,以下是如何在Flutter项目中使用barcode_scan2插件来实现二维码扫描功能的代码示例。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加barcode_scan2依赖:

dependencies:
  flutter:
    sdk: flutter
  barcode_scan2: ^2.0.0  # 确保使用最新版本,版本号可能会更新

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

2. 导入插件

在你的Dart文件中(例如main.dart),导入barcode_scan2插件:

import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:flutter/material.dart';

3. 创建扫描页面

接下来,创建一个按钮来触发二维码扫描,并处理扫描结果。以下是一个简单的示例:

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

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

class ScanPage extends StatefulWidget {
  @override
  _ScanPageState createState() => _ScanPageState();
}

class _ScanPageState extends State<ScanPage> {
  String _result = "";

  Future<void> _scanQR() async {
    try {
      String result = await BarcodeScanner.scan();
      setState(() {
        _result = result;
      });
    } on PlatformException catch (e) {
      if (e.code == BarcodeScanner.CameraAccessDenied) {
        setState(() {
          _result = "相机权限被拒绝,请检查应用权限设置。";
        });
      } else {
        setState(() {
          _result = "扫描失败: ${e.message}";
        });
      }
    } catch (e) {
      setState(() {
        _result = "扫描失败: $e";
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('二维码扫描示例'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              _result,
              style: TextStyle(fontSize: 24),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _scanQR,
              child: Text('扫描二维码'),
            ),
          ],
        ),
      ),
    );
  }
}

4. 请求权限(可选)

在某些平台上(特别是Android),你可能需要在运行时请求相机权限。你可以在AndroidManifest.xml中声明权限,并使用permission_handler插件来请求权限(如果需要)。

AndroidManifest.xml中声明权限:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

使用permission_handler插件请求权限(如果你选择这样做):

首先,在pubspec.yaml中添加permission_handler依赖:

dependencies:
  permission_handler: ^8.0.0  # 确保使用最新版本,版本号可能会更新

然后在你的代码中请求权限:

import 'package:permission_handler/permission_handler.dart';

Future<void> _requestCameraPermission() async {
  var status = await Permission.camera.status;
  if (!status.isGranted) {
    var result = await Permission.camera.request();
    if (!result.isGranted) {
      _result = "相机权限被拒绝,请检查应用权限设置。";
      setState(() {});
    }
  }
}

// 在_scanQR方法之前调用_requestCameraPermission
Future<void> _scanQR() async {
  await _requestCameraPermission();
  // 接下来的代码与之前相同...
}

总结

以上代码展示了如何在Flutter项目中使用barcode_scan2插件来实现二维码扫描功能。包括添加依赖、导入插件、创建扫描页面以及请求相机权限(可选)。希望这能帮助你快速上手二维码扫描功能。

回到顶部