【5分】FlutterでQRコードの生成・読み取りする方法まとめ

image

今回はFlutterでQRコードを生成・読み取りする方法をご紹介します。
QRコードの生成と読み取りをセットで実装することは多々あると思います。
一緒に実装したい!という方はぜひ参考にしてください。

環境

  • Flutter version 2.2.2
  • Dart version 2.13.3

使用パッケージ(qr_flutter,qr_code_scanner)

  • qr_flutter: ^4.0.0

  • qr_code_scanner: ^0.5.2

    QRコードの生成はqr_flutter、読み取りはqr_code_scannerというパッケージを使用します。
    どちらもサクッと実装できると思います。

QRコードを生成する(qr_flutter)

pubspec.yamldependenciesに以下を追加

dependencies:
  qr_flutter: ^4.0.0 #なるべく最新のものを使用してください

そしてflutter pub getでOKです。
詳細は公式のインストールページを参照してください。

qr_flutterの基本実装

ios,androidともにOSごとの設定は不要なので、もう以下をコピペするだけで実装完了です!

import 'package:qr_flutter/qr_flutter.dart';
       QrImage(
          data: 'https://www.kamo-it.org/blog/36/',
          version: QrVersions.auto,
          size: 200.0,
        )

QRコードの生成

例として、このブログのリンク情報を含んだQRコードを生成できます。
他のQRコードリーダーで読み取って、このブログに遷移したら成功です!

生成するQRコードのカスタマイズ

せっかくのなので、生成するQRコードをカスタマイズしてみましょう!

      QrImage(
          data: 'https://www.kamo-it.org/blog/36/',
          version: QrVersions.auto,
          size: 300.0, //QRコードのサイズ
          foregroundColor: Colors.pink, //QRコードの色
          backgroundColor: Colors.grey, //QRコードの背景色
          padding: const EdgeInsets.all(40),
          embeddedImage: Image.network(
              'https://icooon-mono.com/i/icon_11354/icon_113541_64.png')
              .image, //QRコードの真ん中に表示する画像
        )

カスタマイズも含め、QRコードの生成はかなりシンプルに実装できますね。

QRコードのカスタマイズ

QRコードの読み取る(qr_code_scanner)

QRコードの読み取り画面

作成するのは上記の画像のような画面です。
pubspec.yamldependenciesに以下を追加

dependencies:
  qr_code_scanner: ^0.5.2 #なるべく最新のものを使用してください

そしてflutter pub getでOKです。
詳細は公式のインストールページを参照してください。

注意事項

Requires at least SDK 21 (Android 5.0). Requires at least iOS 8.
こちらも考慮しながら設定しましょう。

iosの設定

プロジェクト/ios/Podfileの(だいたい)2行目あたりにあるiosのバージョン指定を8.0以降にしましょう。
この記事を書いている現在は、デフォルトでios8.0になっているので、問題はなさそうですが。
僕はios10.0を使用しています。

platform :ios, '10.0'

info.plistファイルに以下を追加

<key>io.flutter.embedded_views_preview</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan QR codes(カメラの使用許可のための文言)</string>

Androidの設定

Requires at least SDK 21 (Android 5.0) という注意事項があるので、まずはこの部分を確認しましょう。
プロジェクト/android/app/build.gradleminSdkVersionを確認します。

defaultConfig {
        applicationId "ApplicationID"
        minSdkVersion 21 //ここ
        targetSdkVersion 30
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

この部分はデフォルトのままだと、16になっていました。21に変更しましょう。

android/build.gradleで、

ext.kotlin_version = '1.5.10'
...
classpath 'com.android.tools.build:gradle:4.2.0'
...

を指定。

android/gradle/wrapper/gradle-wrapper.propertiesで、

distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip

を指定。

上記のバージョン指定は、パッケージのアップデートとともに更新されていくので、パッケージのREADMEを参考にしてください。

QR読み取りの実装例

以下に実装例を示します。
コードの詳細については、別途説明しています。

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

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

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

  
  _QrScanViewState createState() => _QrScanViewState();
}

class _QrScanViewState extends State<QrScanView> {
  final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
  QRViewController? controller;

  // In order to get hot reload to work we need to pause the camera if the platform
  // is android, or resume the camera if the platform is iOS.
  
  void reassemble() {
    super.reassemble();
    if (Platform.isAndroid) {
      controller?.pauseCamera();
    }
    controller?.resumeCamera();
  }

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

  
  Widget build(BuildContext context) {
    return Scaffold(
          appBar: AppBar(
            title: Text('QR読み取り'),
            centerTitle: true,
          ),
          body: _buildQrView(context),
        );
  }

  Widget _buildQrView(BuildContext context) {
    // For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
    var scanArea = (MediaQuery.of(context).size.width < 400 ||
            MediaQuery.of(context).size.height < 400)
        ? 150.0
        : 300.0;
    // To ensure the Scanner view is properly sizes after rotation
    // we need to listen for Flutter SizeChanged notification and update controller
    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) async {
      print(scanData.code);
    });
  }

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

QRコードの読み取り実装の詳細

ホットリロードすると呼ばれる処理です。
パッケージのREADMEのコメントを引用していますが、ホットリロードを使用するために必要な処理です。

  // In order to get hot reload to work we need to pause the camera if the platform
  // is android, or resume the camera if the platform is iOS.
  
  void reassemble() {
    super.reassemble();
    if (Platform.isAndroid) {
      controller?.pauseCamera();
    }
    controller?.resumeCamera();
  }

QRカメラの初期化時に呼ばれます。

  • controllerをセット
  • スキャンしたデータを取得できるように、listenしています。
  void _onQRViewCreated(QRViewController controller) {
    setState(() {
      this.controller = controller;
    });
    controller.scannedDataStream.listen((scanData) async {
      print(scanData.code);
    });
  }

こちらもカメラのパーミッションがセットされた時点で呼ばれる処理です。
iosシミュレータを使用していると、no Permissionというスナックバーが表示されると思います。
テストは実機で行いましょう!

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

QRコードスキャナーの表示部分です。
QrScannerOverlayShapeのプロパティをカスタマイズすることで、QR読み取り部分のUIを調整できます。

  Widget _buildQrView(BuildContext context) {
    // For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
    var scanArea = (MediaQuery.of(context).size.width < 400 ||
            MediaQuery.of(context).size.height < 400)
        ? 150.0
        : 300.0;
    // To ensure the Scanner view is properly sizes after rotation
    // we need to listen for Flutter SizeChanged notification and update controller
    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),
    );
  }

まとめ

いかがでしたでしょうか。
QRコードの生成・読み取り部分は実装できたでしょうか。
QRコード周りは意外とシンプルに実装できるので、めげずに立ち向かってみましょう。
この記事が参考になれば幸いです。

参考

https://pub.dev/packages/qr_code_scanner https://pub.dev/packages/qr_flutter