Flutter二维码生成与扫描插件qr_plus的使用

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

Flutter二维码生成与扫描插件qr_plus的使用

qr_plus 是一个高级的一体化二维码包,提供了多层安全防护。该包作为一些最流行的二维码相关包的封装器,使用 qr_flutter 渲染二维码,并使用 mobile_scanner 读取二维码。

平台支持

Reader

Android iOS macOS Web Linux Windows

Renderer

Android iOS macOS Web Linux Windows

动机

在当今世界,二维码用于各种用途,从支付到访问安全信息。然而,二维码的易用性和便利性也使它们容易受到恶意攻击。为了应对这些安全问题,QR Plus 提供了多层安全保护,确保数据的安全性。

例如,在组织寻宝活动时,需要确保每个团队的进度被准确和公平地记录。团队在各个地点扫描二维码以获得积分。为防止作弊,需要一种解决方案来确保每个团队只为其实际访问的位置获得积分。这就是我们创建 qr_plus 的原因:让二维码安全而不必编写大量自定义逻辑。

开始使用(推荐设置)

重要提示:您需要在读取器和渲染器上使用相同的模式,否则读取器将无法接受数据。

1. 配置平台

由于此包是 mobile_scanner 的封装器,请遵循其文档中的平台特定配置步骤。

2. 添加渲染器

QrPlusRenderer(
    data: 'https://youtu.be/dQw4w9WgXcQ',
    mode: const QrPlusMode.snowden(
        encryptionKey: '<your-encryption-key>', // 您的加密密钥来自 .env 文件。参见 https://pub.dev/packages/flutter_dotenv
    ),
),

3. 添加读取器

QrPlusReader(
    mode: const QrPlusMode.snowden(
        encryptionKey: '<your-encryption-key>', // 您的加密密钥来自 .env 文件。参见 https://pub.dev/packages/flutter_dotenv
    ),
    onData: (data, authenticity) {
        /// 处理数据
        print(authenticity);
        print(data);
    },
),

4. 完成设置

享受您的新安全二维码吧。

多层安全

QR Plus 提供多层安全保护,每层修复前一层的安全漏洞。以下是包中的安全层,从低到高:

1. QrPlusMode.plain

不包含任何安全性。

2. QrPlusMode.safe

问题

恶意用户可以截屏二维码。

解决方案

将数据拆分为多个部分并一次显示一部分。

3. QrPlusMode.robust

问题

恶意用户可以录屏二维码。

解决方案

添加数据的时间生存期(TTL)。二维码仅在给定时间内有效。

4. QrPlusMode.sound

问题

恶意用户可以修改设备时间。

解决方案

从远程NTP服务器添加时间同步。

5. QrPlusMode.paranoid

问题

恶意用户可以共享屏幕或断开网络连接以欺骗TTL和NTP。

解决方案

检测可能的作弊行为。如果设备正在共享屏幕或录制视频,或用户断开了网络连接,则将可疑活动信息通过二维码发送给读取器。

6. QrPlusMode.snowden

问题

恶意用户可以使用其他二维码读取器读取数据、操纵JSON并创建新的有效二维码。

解决方案

在发送之前对数据进行加密。只有提供的读取器才能解密数据。

示例代码

以下是一个完整的示例应用程序,展示如何使用 qr_plus 包生成和读取二维码。

// ignore_for_file: avoid_print

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

const kHomeRoute = '/';
const kRendererRoute = '/renderer';
const kReaderRoute = '/reader';

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'qr_plus example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      initialRoute: kHomeRoute,
      routes: {
        kHomeRoute: (context) => const Home(),
        kRendererRoute: (context) => const Renderer(),
        kReaderRoute: (context) => const Reader(),
      },
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextButton(
              onPressed: () {
                Navigator.pushNamed(context, kRendererRoute);
              },
              child: const Text('Renderer'),
            ),
            TextButton(
              onPressed: () {
                Navigator.pushNamed(context, kReaderRoute);
              },
              child: const Text('Reader'),
            ),
          ],
        ),
      ),
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Renderer'),
      ),
      body: Center(
        child: QrPlusRenderer(
          data: 'https://youtu.be/dQw4w9WgXcQ',
          mode: const QrPlusMode.snowden(
            encryptionKey: '<your-encryption-key>',
          ),
        ),
      ),
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Reader'),
      ),
      body: Center(
        child: QrPlusReader(
          mode: const QrPlusMode.snowden(
            encryptionKey: '<your-encryption-key>',
          ),
          onData: (data, authenticity) {
            print(authenticity);
            print(data);
          },
        ),
      ),
    );
  }
}

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

1 回复

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


当然,以下是如何在Flutter项目中使用qr_plus插件来生成和扫描二维码的示例代码。qr_plus插件结合了二维码生成和扫描的功能,使用起来非常方便。

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

dependencies:
  flutter:
    sdk: flutter
  qr_plus: ^x.y.z  # 请替换为最新版本号

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

生成二维码

下面是一个简单的例子,展示如何使用qr_plus生成二维码:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('QR Code Generator'),
        ),
        body: Center(
          child: QrCodeGenerator(
            data: 'https://flutter.dev',
            version: QrVersions.auto,
            size: 250.0,
            onError: (context, error) {
              // 处理错误
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Error generating QR code: $error')),
              );
            },
          ),
        ),
      ),
    );
  }
}

扫描二维码

接下来是一个如何扫描二维码的例子:

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

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> {
  final BarcodeScannerController _controller = BarcodeScannerController();
  String? _result;

  @override
  void initState() {
    super.initState();
    _controller.addListener(() {
      if (mounted) {
        setState(() {});
      }
      if (_controller.value.data != null) {
        _result = _controller.value.data!;
        _controller.pause();
      }
    });
    _controller.resume();
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('QR Code Scanner'),
      ),
      body: Center(
        child: _result != null
            ? Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    'Scanned: $_result',
                    style: TextStyle(fontSize: 24),
                  ),
                  SizedBox(height: 20),
                  ElevatedButton(
                    onPressed: () {
                      setState(() {
                        _result = null;
                        _controller.resume();
                      });
                    },
                    child: Text('Scan Again'),
                  ),
                ],
              )
            : Container(
                width: double.infinity,
                height: double.infinity,
                child: BarcodeScannerOverlay(
                  controller: _controller,
                ),
              ),
      ),
    );
  }
}

完整项目结构

确保你的项目结构大致如下:

your_flutter_app/
├── lib/
│   ├── main.dart (包含上述生成和扫描代码,或者拆分成两个文件)
├── pubspec.yaml

运行项目

将上述代码添加到你的项目中后,使用flutter run命令运行项目。你应该能够在你的设备上看到一个可以生成二维码的页面和一个可以扫描二维码的页面。

注意:在实际应用中,你可能需要处理更多的错误和边界情况,并根据需要进行UI定制。

回到顶部