【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

お知らせ

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。

Read More
U30可茂ITインターンハッカソン

U30可茂ITインターンハッカソン

12月28,29日開催。2日間でアプリ開発の企画から完成までを目指す!U30可茂ITインターンハッカソンを開催します。

Read More

タグ

Flutter (110)初心者向け (28)イベント (18)Google Apps Script (15)Nextjs (12)可茂IT塾 (8)Firebase (7)riverpod (6)React (6)ChatGPT (5)vscode (5)デザイン (5)新卒 (4)就活 (4)Figma (4)Dart (4)JavaScript (4)お知らせ (4)FlutterWeb (3)Prisma (3)NestJS (3)Slack (3)TypeScript (3)ワーケーション (3)インターン (3)設計 (2)線型計画法 (2)事例 (2)Git (2)Image (2)File (2)Material Design (2)画像 (2)iOS (2)アプリ開発 (2)React Hooks (2)tailwindcss (2)社会人 (2)大学生 (2)RSS (1)Google (1)Web (1)CodeRunner (1)個人開発 (1)Android (1)Unity (1)WebView (1)Twitter (1)フルリモート (1)TextScaler (1)textScaleFactor (1)学生向け (1)supabase (1)Java (1)Spring Boot (1)shell script (1)正規表現 (1)パワーポイント (1)趣味 (1)モンスターボール (1)CSS (1)SCSS (1)Cupertino (1)ListView (1)就活浪人 (1)既卒 (1)保守性 (1)iPad (1)シェアハウス (1)スクレイピング (1)PageView (1)画面遷移 (1)flutter_hooks (1)Gmail (1)GoogleWorkspace (1)ShaderMask (1)google map (1)Google Places API (1)GCPコンソール (1)Google_ML_Kit (1)Vercel (1)Google Domains (1)DeepLeaning (1)深層学習 (1)Google Colab (1)コード生成 (1)GitHub Copilot (1)オンラインオフィス (1)オブジェクト指向 (1)クラスの継承 (1)ポリモーフィズム (1)LINE (1)Bitcoin (1)bitFlyer (1)コミュニティー (1)文系エンジニア (1)Freezed (1)permission_handler (1)flutter_local_notifications (1)markdown (1)GlobalKey (1)ValueKey (1)Key (1)アイコン (1)go_router (1)debug (1)datetime_picker (1)Apple Store Connect (1)FlutterGen (1)デバッグ (1)Widget Inspector (1)検索機能 (1)Shader (1)Navigator (1)メール送信 (1)Firebase App Distribution (1)Fastlane (1)Dio (1)CustomClipper (1)ClipPath (1)カスタム認証 (1)アニメーション (1)Arduino (1)ESP32 (1)経験談 (1)フリーランス (1)mac (1)csv (1)docker (1)GithubActions (1)Dialog (1)BI (1)LifeHack (1)ショートカット (1)Chrome (1)高校生 (1)キャリア教育 (1)非同期処理 (1)生体認証 (1)BackdropFilter (1)レビュー (1)getAuth (1)Algolia (1)コンサルティング (1)Symbol (1)

お知らせ

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。

Read More
U30可茂ITインターンハッカソン

U30可茂ITインターンハッカソン

12月28,29日開催。2日間でアプリ開発の企画から完成までを目指す!U30可茂ITインターンハッカソンを開催します。

Read More