Flutter自制插件之r_scan二維碼&條形碼掃描(支持文件、url、內(nèi)存、相機(jī))

image

介紹

二維碼作為信息的載體,廣泛應(yīng)用于我們生活的方方面面,例如:使用支付寶支付,二維碼加好友,二維碼推廣等等,能舉例的例子多不勝數(shù),而如果你的應(yīng)用支持二維碼的掃描,用戶和體驗將會翻倍的增長,如果你是應(yīng)用的開發(fā)者,歡迎來使用此二維碼掃描插件!并希望能給予項目一個star,謝謝!項目地址:https://github.com/rhymelph/r_scan

使用

你可以在pub.dev網(wǎng)站上面搜索r_scan即可找到該插件,添加下面代碼到pubspec.yaml文件

dependencies:
    r_scan: last version
  • last version 可以在pub.dev網(wǎng)站搜索r_scan得到

各設(shè)備注意事項

  • Android平臺下

android6.0系統(tǒng)以上請動態(tài)授權(quán),可以結(jié)合permission_handler插件使用,代碼如下:

import 'package:permission_handler/permission_handler.dart';

Future<bool> canReadStorage() async {
    if(Platform.isIOS) return true;
    var status = await PermissionHandler()
        .checkPermissionStatus(PermissionGroup.storage);
    if (status != PermissionStatus.granted) {
      var future = await PermissionHandler()
          .requestPermissions([PermissionGroup.storage]);
      for (final item in future.entries) {
        if (item.value != PermissionStatus.granted) {
          return false;
        }
      }
    } else {
      return true;
    }
    return true;
  }

Future<bool> canOpenCamera() async {
    var status =
        await PermissionHandler().checkPermissionStatus(PermissionGroup.camera);
    if (status != PermissionStatus.granted) {
      var future = await PermissionHandler()
          .requestPermissions([PermissionGroup.camera]);
      for (final item in future.entries) {
        if (item.value != PermissionStatus.granted) {
          return false;
        }
      }
    } else {
      return true;
    }
    return true;
  }
  • IOS平臺下

需要在info.plist文件下添加如下代碼:

    <key>NSCameraUsageDescription</key>
    <string>掃描二維碼時需要使用您的相機(jī)</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>掃描二維碼時需要訪問您的相冊</string>
    <key>io.flutter.embedded_views_preview</key>
    <true/>

導(dǎo)包

import 'package:r_scan/r_scan.dart';

1.掃描文件圖片二維碼

final result=await RScan.scanImagePath('你的文件路徑');
if(result.isNotEmpty){
    //result 為二維碼內(nèi)容
}

2.掃描圖片鏈接二維碼

final result=await RScan.scanImagePath('你的圖片鏈接');
if(result.isNotEmpty){
    //result 為二維碼內(nèi)容
}

3.掃描內(nèi)存圖片二維碼

ByteData data=await rootBundle.load('images/qrCode.png');
final result=await RScan.scanImageMemory(data.buffer.asUint8List());
if(result.isNotEmpty){
    //result 為二維碼內(nèi)容
}

4.(NEW)基于Texture使用相機(jī)掃描二維碼/條形碼

  • 步驟1:獲取可用相機(jī)
List<RScanCameraDescription> rScanCameras = await availableRScanCameras();;

如果你在main()方法下獲取可用相機(jī),請使用下面代碼

List<RScanCameraDescription> rScanCameras;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  rScanCameras = await availableRScanCameras();
  runApp(...);
}
  • 步驟2:開始使用
class RScanCameraDialog extends StatefulWidget {
  @override
  _RScanCameraDialogState createState() => _RScanCameraDialogState();
}

class _RScanCameraDialogState extends State<RScanCameraDialog> {
  RScanCameraController _controller;
  bool isFirst = true;

  @override
  void initState() {
    super.initState();
    //判斷當(dāng)前是否有可用相機(jī)
    if (rScanCameras != null && rScanCameras.length > 0) {
    //初始化相機(jī)控制器,一般rScanCameras[0]為后置,rScanCameras[1]為前置攝像頭
      _controller = RScanCameraController(
          rScanCameras[0], RScanCameraResolutionPreset.max)
        ..addListener(() {
        //監(jiān)聽掃碼返回結(jié)果
          final result = _controller.result;
          if (result != null) {
            if (isFirst) {
            //如果掃描到二維碼將結(jié)果返回到上一頁
              Navigator.of(context).pop(result);
              isFirst = false;
            }
          }
        })
        ..initialize().then((_) {
        //初始化相機(jī)
          if (!mounted) {
            return;
          }
          setState(() {});
        });
    }
  }

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

  @override
  Widget build(BuildContext context) {
  //判斷是否有可用相機(jī)
    if (rScanCameras == null || rScanCameras.length == 0) {
      return Scaffold(
        body: Container(
          alignment: Alignment.center,
          child: Text('not have available camera'),
        ),
      );
    }
    //判斷相機(jī)如果沒有初始化,給它一個加載頁面
    if (!_controller.value.isInitialized) {
      return Container();
    }
    //獲取到相機(jī)
    return Scaffold(
      backgroundColor: Colors.black,
      body: Stack(
        children: <Widget>[
          ScanImageView(
            child: AspectRatio(
            //拿到相機(jī)的aspectRatio
              aspectRatio: _controller.value.aspectRatio,
              child: RScanCamera(_controller),
            ),
          ),
          //閃光燈
          Align(
              alignment: Alignment.bottomCenter,
              child: FutureBuilder(
                future: getFlashMode(),
                builder: _buildFlashBtn,
              ))
        ],
      ),
    );
  }
  //獲取閃光燈是否打開
  Future<bool> getFlashMode() async {
    bool isOpen = false;
    try {
      isOpen = await _controller.getFlashMode();
    } catch (_) {}
    return isOpen;
  }

//構(gòu)建閃光燈按鈕
  Widget _buildFlashBtn(BuildContext context, AsyncSnapshot<bool> snapshot) {
    return snapshot.hasData
        ? Padding(
      padding:  EdgeInsets.only(bottom:24+MediaQuery.of(context).padding.bottom),
      child: IconButton(
          icon: Icon(snapshot.data ? Icons.flash_on : Icons.flash_off),
          color: Colors.white,
          iconSize: 46,
          onPressed: () {
            if (snapshot.data) {
              _controller.setFlashMode(false);
            } else {
              _controller.setFlashMode(true);
            }
            setState(() {});
          }),
    )
        : Container();
  }
}

5.(已棄用)基于PlatformView使用相機(jī)掃描二維碼/條形碼

import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:r_scan/r_scan.dart';

class RScanDialog extends StatefulWidget {
  @override
  _RScanDialogState createState() => _RScanDialogState();
}

class _RScanDialogState extends State<RScanDialog> {
  RScanController _controller;

  @override
  void initState() {
    super.initState();
    initController();
  }
  bool isFirst=true;


  Future<void> initController() async {
    _controller = RScanController();
    _controller.addListener(() {//監(jiān)聽掃描到的二維碼
      final result = _controller.result;
      if (result != null) {
        if(isFirst){
          Navigator.of(context).pop(result);
          isFirst=false;
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.black,
        body: FutureBuilder<bool>(
          future: canOpenCameraView(),
          builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
            if (snapshot.hasData && snapshot.data == true) {
              return ScanImageView(//這個為自己寫的前景
                child: RScanView(
                  controller: _controller,
                ),
              );
            } else {
              return Container();
            }
          },
        ),
      ),
    );
  }

  Future<bool> canOpenCameraView() async {
    var status =
        await PermissionHandler().checkPermissionStatus(PermissionGroup.camera);
    if (status != PermissionStatus.granted) {
      var future = await PermissionHandler()
          .requestPermissions([PermissionGroup.camera]);
      for (final item in future.entries) {
        if (item.value != PermissionStatus.granted) {
          return false;
        }
      }
    } else {
      return true;
    }
    return true;
  }
}

6. 打開閃光燈/獲取閃光燈狀態(tài)

使用RScanController類的實例直接調(diào)用

//關(guān)閉閃光燈
await _controller.setFlashMode(false);

//打開閃光燈
await _controller.setFlashMode(true);

// 獲取閃光燈狀態(tài)
bool isOpen = await _controller.getFlashMode();

7.RScanResult(二維碼掃描結(jié)果)

當(dāng)掃描到二維碼&條形碼將返回該對象,包含如下內(nèi)容

class RScanResult {
  /// 條形碼類型
  final RScanBarType type;

  ///附帶的信息
  final String message;

  ///條形碼對應(yīng)的區(qū)域 包含 [x , y] 坐標(biāo)
  final List<RScanPoint> points;
}

后續(xù)開發(fā)

  1. 支持自定義區(qū)域觸發(fā)掃描
  2. 還有更多...
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容