Generating and Scanning QR Codes in Flutter

QR codes are ubiquitous in the modern world, serving as a quick and convenient way to share information, whether it’s website URLs, contact details, or payment requests. Flutter, Google’s UI toolkit for building natively compiled applications for mobile, web, and desktop from a single codebase, makes it straightforward to integrate QR code generation and scanning capabilities into your apps.

Why Use QR Codes in Flutter?

QR codes offer numerous advantages for Flutter application development:

  • Seamless Information Sharing: Enables users to quickly share data without manual input.
  • Mobile Payments: Facilitates secure and contactless payment options.
  • Authentication: Simplifies user authentication processes.
  • Inventory Management: Streamlines inventory tracking and management systems.
  • Marketing Campaigns: Allows for engaging and interactive marketing experiences.

Prerequisites

Before you begin, ensure that you have the following installed:

  • Flutter SDK: Set up Flutter on your development machine.
  • Dart SDK: Dart comes bundled with the Flutter SDK.
  • Android Studio or VS Code: Code editors for Flutter development.

Setting Up a Flutter Project

Create a new Flutter project by running:

flutter create qr_code_app

Navigate into the project directory:

cd qr_code_app

Generating QR Codes in Flutter

To generate QR codes in Flutter, we’ll use the qr_flutter package, which provides a simple way to create QR code images.

Step 1: Add the qr_flutter Dependency

Open the pubspec.yaml file and add the qr_flutter package to your dependencies:

dependencies:
  flutter:
    sdk: flutter
  qr_flutter: ^4.1.0

Run flutter pub get in the terminal to install the package.

Step 2: Implement QR Code Generation

Now, let’s create a widget that generates a QR code from a given string.

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

class QRCodeGenerator extends StatelessWidget {
  final String data;

  const QRCodeGenerator({Key? key, required this.data}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: QrImageView(
        data: data,
        version: QrVersions.auto,
        size: 200.0,
        gapless: false,
        errorStateBuilder: (cxt, err) {
          return const Center(
            child: Text(
              "Uh oh! Something went wrong...",
              textAlign: TextAlign.center,
            ),
          );
        },
      ),
    );
  }
}

In this example:

  • QrImageView is the widget provided by qr_flutter for rendering QR codes.
  • data is the string you want to encode into the QR code.
  • version determines the QR code version (QrVersions.auto lets the library choose).
  • size defines the dimensions of the QR code image.
  • gapless controls whether to add a gap around the QR code’s data modules.
  • errorStateBuilder is a callback for handling errors during QR code generation.

Step 3: Use the QRCodeGenerator Widget

Integrate the QRCodeGenerator into your main app:

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

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'QR Code Generator',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('QR Code Generator'),
        ),
        body: const QRCodeGenerator(data: 'https://www.example.com'),
      ),
    );
  }
}

Replace 'https://www.example.com' with the data you want to encode.

Scanning QR Codes in Flutter

To scan QR codes, we’ll use the qr_code_scanner package, which provides a view for scanning QR codes using the device’s camera.

Step 1: Add the qr_code_scanner Dependency

Open the pubspec.yaml file and add the qr_code_scanner package to your dependencies:

dependencies:
  flutter:
    sdk: flutter
  qr_code_scanner: ^1.0.1

Run flutter pub get in the terminal to install the package.

Step 2: Add Camera Permissions

For Android, add the camera permission to android/app/src/main/AndroidManifest.xml:

For iOS, add the camera usage description to ios/Runner/Info.plist:

NSCameraUsageDescription
This app needs camera access to scan QR codes.

Step 3: Implement QR Code Scanning

Create a widget that scans QR codes using the device’s camera.

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

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

  @override
  State createState() => _QRCodeScannerState();
}

class _QRCodeScannerState extends State {
  final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
  Barcode? result;
  QRViewController? controller;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Expanded(flex: 4, child: _buildQrView(context)),
          Expanded(
            flex: 1,
            child: FittedBox(
              fit: BoxFit.contain,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  if (result != null)
                    Text(
                        'Barcode Type: ${describeEnum(result!.format)}   Data: ${result!.code}')
                  else
                    const Text('Scan a code'),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      Container(
                        margin: const EdgeInsets.all(8),
                        child: ElevatedButton(
                            onPressed: () async {
                              await controller?.toggleFlash();
                              setState(() {});
                            },
                            child: FutureBuilder(
                              future: controller?.getFlashStatus(),
                              builder: (context, snapshot) {
                                return Text('Flash: ${snapshot.data}');
                              },
                            )),
                      ),
                      Container(
                        margin: const EdgeInsets.all(8),
                        child: ElevatedButton(
                            onPressed: () async {
                              await controller?.flipCamera();
                              setState(() {});
                            },
                            child: FutureBuilder(
                              future: controller?.getCameraInfo(),
                              builder: (context, snapshot) {
                                if (snapshot.data != null) {
                                  return Text(
                                      'Camera facing ${describeEnum(snapshot.data!)}');
                                } else {
                                  return const Text('loading');
                                }
                              },
                            )),
                      )
                    ],
                  ),
                ],
              ),
            ),
          )
        ],
      ),
    );
  }

  Widget _buildQrView(BuildContext context) {
    // For this example we check how width or tall the device is and change the layout 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 detect orientation changes.
    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) {
      setState(() {
        result = scanData;
      });
    });
  }

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

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

In this example:

  • QRView is the widget provided by qr_code_scanner for displaying the camera view and scanning QR codes.
  • _onQRViewCreated is called when the QR view is created, allowing you to interact with the QRViewController.
  • scannedDataStream listens for scanned QR code data.
  • Camera permissions are requested and handled.

Step 4: Use the QRCodeScanner Widget

Integrate the QRCodeScanner into your main app:

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

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'QR Code Scanner',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('QR Code Scanner'),
        ),
        body: const QRCodeScanner(),
      ),
    );
  }
}

Testing Your Flutter QR Code App

Run the Flutter app on an emulator or a physical device to test QR code generation and scanning:

flutter run

Make sure to grant camera permissions when prompted.

Conclusion

Integrating QR code generation and scanning capabilities into your Flutter apps is straightforward using packages like qr_flutter and qr_code_scanner. These features can enhance user experience, streamline processes, and provide innovative solutions for information sharing and more. By following this guide, you can easily implement QR code functionality in your Flutter projects, making them more versatile and user-friendly.