广告位联系
返回顶部
分享到

基于Flutter实现扫描二维码功能

Android 来源:互联网 作者:佚名 发布时间:2024-11-22 08:58:40 人浏览
摘要

在今天的移动开发中,二维码扫描已经成为了常见的功能之一。Flutter作为一款跨平台的开发框架,提供了丰富的插件和功能,使得开发者可以轻松实现二维码扫描以及图像识别功能。本文将介

在今天的移动开发中,二维码扫描已经成为了常见的功能之一。Flutter作为一款跨平台的开发框架,提供了丰富的插件和功能,使得开发者可以轻松实现二维码扫描以及图像识别功能。本文将介绍如何在Flutter中通过结合 scan 插件、permission_handler 插件以及 image_picker 插件,实现二维码扫描和从相册选择二维码图片的功能。

效果图

1、相机扫描二维码

2、相册选择二维码并扫描

1、项目依赖

首先,我们需要在 pubspec.yaml 文件中添加以下依赖:

1

2

3

4

5

6

dependencies:

  flutter:

    sdk: flutter

  scan: ^1.6.0          # 用于扫描二维码

  permission_handler: ^10.2.0  # 用于权限请求

  image_picker: ^1.0.7    # 用于从相册选择图片

这些插件的作用如下:

scan:提供二维码扫描功能。

permission_handler:用于请求相机权限,确保用户授权后才能使用相机进行二维码扫描。

image_picker:允许从相册选择图片,便于用户上传二维码图片进行识别。

2、配置权限

在 Android 平台上,为了使用相机功能,需要在 AndroidManifest.xml 文件中添加必要的权限:

1

<uses-permission android:name="android.permission.CAMERA"/>

在 IOS平台上修改 Info.plist 文件,打开 ios/Runner/Info.plist 文件,确保添加以下配置(iOS用虚拟机是调试不了的,实测打不开相机):

<key>NSCameraUsageDescription</key>
<string>需要访问相机用于二维码扫描</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册选择图片</string>

3、实现二维码扫描功能

接下来,我们来看看如何实现二维码扫描功能。我们需要创建一个主界面,在其中添加按钮来请求相机权限,并进行二维码扫描。

没有二维码的小伙伴可以查看上一篇文章:Flutter 生成二维码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

import 'package:flutter/material.dart';

import 'package:scan/scan.dart';  // 导入 scan 插件

import 'package:permission_handler/permission_handler.dart';  // 导入权限请求插件

import 'package:image_picker/image_picker.dart';  // 导入相册选择插件

  

void main() {

  runApp(MyApp());

}

  

class MyApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return MaterialApp(

      theme: ThemeData(

        primarySwatch: Colors.blue,

        visualDensity: VisualDensity.adaptivePlatformDensity,

      ),

      home: QRScannerScreen(),

    );

  }

}

  

class QRScannerScreen extends StatefulWidget {

  @override

  _QRScannerScreenState createState() => _QRScannerScreenState();

}

  

class _QRScannerScreenState extends State<QRScannerScreen> {

  ScanController controller = ScanController();  // 创建扫描控制器

  String qrcode = 'Unknown';  // 默认二维码内容

  

  // 执行二维码扫描前请求权限

  _requestPermissions() async {

    var cameraStatus = await Permission.camera.request();

    if (cameraStatus.isGranted) {

      // 权限已授予,开始扫描

      print("相机权限已授予,开始扫描");

      // 点击按钮后跳转到全屏扫描界面

      Navigator.push(

        context,

        MaterialPageRoute(builder: (context) => QRScanPage(controller: controller)),

      ).then((result) {

        controller.pause();  // 暂停扫描

        // 扫描完成后获取返回的二维码数据并更新显示

        if (result != null) {

          setState(() {

            qrcode = result;  // 更新二维码内容

          });

        }

      });

    } else {

      // 权限被拒绝或未授权

      print("相机权限未授予,请授权");

      // 可以引导用户去设置页面

    }

  }

  

  // 选择相册中的二维码图片

  _selectImageFromGallery() async {

    final picker = ImagePicker();

    final pickedFile = await picker.pickImage(source: ImageSource.gallery);

    if (pickedFile != null) {

      String result = await Scan.parse(pickedFile.path) ?? '';  // 解析选中的图片

      setState(() {

        qrcode = result;  // 更新二维码内容

      });

    }

  }

  

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(

        title: const Text('二维码扫描器'),

      ),

      body: Center(

        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,

          children: <Widget>[

            // 显示二维码扫描结果

            const Text(

              '二维码扫描结果:',

              style: TextStyle(fontSize: 18),

            ),

            const SizedBox(height: 10),

            Text(

              qrcode,

              style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),

            ),

            const SizedBox(height: 30),

            // 扫描按钮

            ElevatedButton(

              onPressed: _requestPermissions,  // 执行权限请求

              child: const Text('请求权限并开始扫描'),

            ),

            const SizedBox(height: 30),

            // 选择相册按钮

            ElevatedButton(

              onPressed: _selectImageFromGallery,  // 选择相册

              child: const Text('从相册选择二维码图片'),

            ),

          ],

        ),

      ),

    );

  }

}

代码解释

权限请求:我们通过 permission_handler 插件请求相机权限。用户允许后才能进行二维码扫描。

扫描功能:我们使用 ScanController 来控制扫描过程。点击按钮后,跳转到全屏扫描页面 QRScanPage,在该页面,用户可以通过相机扫描二维码。

从相册选择图片:我们利用 image_picker 插件允许用户从相册选择图片,并解析二维码。

4、全屏扫描页面

当用户点击扫描按钮时,应用会进入一个全屏扫描页面。在该页面中,二维码扫描功能全屏展示,并且添加了一个“选择相册”按钮,让用户可以在扫描时直接选择图片。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

class QRScanPage extends StatelessWidget {

  final ScanController controller;

  const QRScanPage({super.key, required this.controller});

  

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(title: Text('扫描二维码')),

      body: Stack(

        alignment: Alignment.center,

        children: [

          // 使用 ScanView 进行全屏扫描

          ScanView(

            controller: controller,

            scanAreaScale: 0.8,  // 设置扫描区域占满整个屏幕

            scanLineColor: Colors.green.shade400,  // 设置扫描线颜色

            onCapture: (data) {

              // 扫描到二维码后,返回数据

              controller.pause();  // 暂停扫描

              Navigator.pop(context, data);  // 返回扫描结果

            },

          ),

          // 在屏幕上添加选择相册按钮

          Positioned(

            bottom: 100,

            child: ElevatedButton(

              onPressed: () async {

                // 选择相册

                final picker = ImagePicker();

                final pickedFile = await picker.pickImage(source: ImageSource.gallery);

                if (pickedFile != null) {

                  String result = await Scan.parse(pickedFile.path) ?? '';  // 解析选中的图片

                  Navigator.pop(context, result);  // 返回二维码结果

                }

              },

              child: const Text(

                '选择相册',

                style: TextStyle(

                  fontSize: 18,

                  color: Colors.white,

                  fontWeight: FontWeight.bold,

                ),

              ),

            ),

          ),

        ],

      ),

    );

  }

}

代码解释

ScanView:提供扫描界面,支持自定义扫描区域和扫描线颜色。

onCapture:当扫描到二维码时,会返回扫描结果并暂停扫描。

选择相册按钮:点击按钮可以让用户从相册选择二维码图片进行解析。

完整demo

可以直接复制到新项目跑起来

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

import 'package:flutter/material.dart';

import 'package:scan/scan.dart';  // 导入 scan 插件

import 'package:permission_handler/permission_handler.dart';  // 导入权限请求插件

import 'package:image_picker/image_picker.dart';  // 导入相册选择插件

  

void main() {

  runApp(MyApp());

}

  

class MyApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return MaterialApp(

      theme: ThemeData(

        primarySwatch: Colors.blue,

        visualDensity: VisualDensity.adaptivePlatformDensity,

      ),

      home: QRScannerScreen(),

    );

  }

}

  

class QRScannerScreen extends StatefulWidget {

  @override

  _QRScannerScreenState createState() => _QRScannerScreenState();

}

  

class _QRScannerScreenState extends State<QRScannerScreen> {

  ScanController controller = ScanController();  // 创建扫描控制器

  String qrcode = 'Unknown';  // 默认二维码内容

  

  // 执行二维码扫描前请求权限

  _requestPermissions() async {

    var cameraStatus = await Permission.camera.request();

    if (cameraStatus.isGranted) {

      // 权限已授予,开始扫描

      print("相机权限已授予,开始扫描");

      // 点击按钮后跳转到全屏扫描界面

      Navigator.push(

        context,

        MaterialPageRoute(builder: (context) => QRScanPage(controller: controller)),

      ).then((result) {

        controller.pause();  // 暂停扫描

        // 扫描完成后获取返回的二维码数据并更新显示

        if (result != null) {

          setState(() {

            qrcode = result;  // 更新二维码内容

          });

        }

      });

    } else {

      // 权限被拒绝或未授权

      print("相机权限未授予,请授权");

      // 可以引导用户去设置页面

    }

  }

  

  // 选择相册中的二维码图片

  _selectImageFromGallery() async {

    final picker = ImagePicker();

    final pickedFile = await picker.pickImage(source: ImageSource.gallery);

    if (pickedFile != null) {

      String result = await Scan.parse(pickedFile.path) ?? '';  // 解析选中的图片

      setState(() {

        qrcode = result;  // 更新二维码内容

      });

    }

  }

  

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(

        title: const Text('二维码扫描器'),

      ),

      body: Center(

        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,

          children: <Widget>[

            // 显示二维码扫描结果

            const Text(

              '二维码扫描结果:',

              style: TextStyle(fontSize: 18),

            ),

            const SizedBox(height: 10),

            Text(

              qrcode,

              style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),

            ),

            const SizedBox(height: 30),

            // 扫描按钮

            ElevatedButton(

              onPressed: _requestPermissions,  // 执行权限请求

              child: const Text('请求权限并开始扫描'),

            ),

            const SizedBox(height: 30),

            // 选择相册按钮

            ElevatedButton(

              onPressed: _selectImageFromGallery,  // 选择相册

              child: const Text('从相册选择二维码图片'),

            ),

          ],

        ),

      ),

    );

  }

}

  

class QRScanPage extends StatelessWidget {

  final ScanController controller;

  const QRScanPage({super.key, required this.controller});

  

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(title: Text('扫描二维码')),

      body: Stack(

        alignment: Alignment.center,

        children: [

          // 使用 ScanView 进行全屏扫描

          ScanView(

            controller: controller,

            scanAreaScale: 0.8,  // 设置扫描区域占满整个屏幕

            scanLineColor: Colors.green.shade400,  // 设置扫描线颜色

            onCapture: (data) {

              // 扫描到二维码后,返回数据

              controller.pause();  // 暂停扫描

              Navigator.pop(context, data);  // 返回扫描结果

            },

          ),

          // 在屏幕上添加选择相册按钮

          Positioned(

            bottom: 100,

            child: ElevatedButton(

              onPressed: () async {

                // 选择相册

                final picker = ImagePicker();

                final pickedFile = await picker.pickImage(source: ImageSource.gallery);

                if (pickedFile != null) {

                  String result = await Scan.parse(pickedFile.path) ?? '';  // 解析选中的图片

                  Navigator.pop(context, result);  // 返回二维码结果

                }

              },

              child: const Text(

                '选择相册',

                style: TextStyle(

                  fontSize: 18,

                  color: Colors.white,

                  fontWeight: FontWeight.bold,

                ),

              ),

            ),

          ),

        ],

      ),

    );

  }

}

总结

本文展示了如何在 Flutter 中实现二维码扫描和从相册选择二维码图片的功能。通过使用 scan、permission_handler 和 image_picker 插件,我们可以轻松地添加二维码扫描和图片识别功能。在开发实际应用时,可能还需要处理更多细节,例如处理不同平台的权限请求、优化扫描体验等。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • 基于Flutter实现扫描二维码功能

    基于Flutter实现扫描二维码功能
    在今天的移动开发中,二维码扫描已经成为了常见的功能之一。Flutter作为一款跨平台的开发框架,提供了丰富的插件和功能,使得开发者可
  • Android Service功能使用介绍
    在Android开发中,Service是一个在后台长时间运行的组件,不会提供用户界面。它可以用来处理一些需要在后台进行的操作,比如播放音乐、下
  • Android封装常用工具类的介绍
    日志封装类-MyLog 是对androidlog的封装,封装后 可以设置显示级别 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
  • Flutter web bridge通信总结分析介绍

    Flutter web bridge通信总结分析介绍
    公司医疗业务人手比较少【小而美】的团队~ 较少采用的前端技术架构是: toC:小程序 toB2C: Flutter + H5(SPA - React)【build ???????? Android + IOS】
  • Android Flutter自定义动画路由的介绍

    Android Flutter自定义动画路由的介绍
    flutter中有默认的Route组件,叫做MaterialPageRoute,一般情况下我们在flutter中进行跳转的话,只需要向Navigator中传入一个MaterialPageRoute就可以了。
  • Android实现获取短信验证码并自动填充

    Android实现获取短信验证码并自动填充
    最近弄了个短信自动填充功能,一开始觉得很简单,不就是动态注册个广播接收器去监听短信消息不就可以了吗?结果没这么简单,问题就
  • Android studio六大基本布局介绍
    Android中常用的布局方式有以下几种: 线性布局LinearLayout 相对布局RelativeLayout 表格布局TableLayout 层布局FrameLayout 绝对布局AbsoluteLayout 网格布
  • Android Service启动绑定流程介绍
    本文基于Android 11,参考《Android进阶解密》一书资料。了解Service的启动和绑定流程,以及Service的Context创建过程。 由于基于分析流程,忽略
  • Android自定义有限制区域的图例角度自识别涂鸦工

    Android自定义有限制区域的图例角度自识别涂鸦工
    上文Android:实现一个自定义有限制区域的图例(角度自识别)涂鸦工具类(中)中我们已经实现了在复杂的异形区域中涂鸦,最后生成图片
  • Android自定义有限制区域图例角度自识别涂鸦工具

    Android自定义有限制区域图例角度自识别涂鸦工具
    上文Android:实现一个自定义有限制区域的图例(角度自识别)涂鸦工具类(上)中我们已经实现了自定义View签名的功能,包含撤回、清除方
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计