How to create a QR code generator with Flutter

Sebastian Kotarski
Deviniti Technology-Driven Blog
7 min readNov 25, 2021

In this tutorial, we will jump into Flutter for Web development, and we aim to build an application for QR code generation and PDF generation. It would be easy to build such a tool with Flutter because it will be compatible with all popular web browsers. Do you have a mobile background but barely know HTML and CSS? That’s not an obstacle but actually a great way to start a web project. So, how to program a QR code generator? Let’s get into it.

A little history first

Flutter is a framework developed by Google, which you can use to build apps for mobile, desktop, and web. It uses Dart as a programming language, which is very similar to currently most popular technologies like Java or C#.

It’s perfect to share code between different platforms so you don’t need to employ iOS and Android engineers to build an app. Flutter for web (previous codename “Flutter Hummingbird”) was introduced in 2018, presenting popular game 2048 fully implemented in Flutter, stable at 60fps.

Fig. 1 2048 game
2048 game, source

Tools we will need

We will use VS Code for coding on macOS. For debugging purposes, Chrome web browser will be used. Flutter version 2.5.2 and Dart SDK 2.14.3.

Let’s just start coding, please

First, we need to upgrade Flutter SDK to the latest version. In Terminal perform:

$ flutter channel stable
$ flutter upgrade

When you are ready, let’s check whether your Chrome is correctly installed using the command.

$ flutter devices

You should see something like this.

1 connected device:

Chrome (web) • chrome • web-javascript • Google Chrome 94.0.4606.81

After that, create a new Flutter project.

$ flutter create qr_code_generator

After the directory will be created, let’s run it.

$ cd qr_code_generator
$ flutter run -d chrome

As a result, the Chrome browser should open up and you should see a startup template for the Flutter project.

Flutter for web startup project
Flutter for web startup project

Building UI

Let’s dive into the code. Open the project in VS Code to have a view like below.

Project root directories view
Project root directories view

Open main.dart and inside that file fill it with the code.

import ‘package:flutter/material.dart’;
import ‘package:qr_code_generator/pages/code_viewer.dart’;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: "QR Code generator",
routes: {'viewer': (context) => CodeViewerPage(title: "Generated code")},
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: "QR generator"),
);
}
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _controller = TextEditingController();

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
"Type what you want to encode into QR code",
),
const Padding(padding: EdgeInsets.all(10)),
TextField(
controller: _controller,
decoration: const InputDecoration(
border: OutlineInputBorder(), hintText: "Enter your text"),
),
const Padding(padding: EdgeInsets.all(10)),
TextButton(
style: TextButton.styleFrom(primary: Colors.blue),
onPressed: _showCode,
child: const Text("Generate"),
)
],
),
),
);
}

void _showCode() {
Navigator.of(context).pushNamed("viewer");
}
}

Save the file and refresh Chrome browser (it should be done automatically, but sometimes Chrome will relaunch too early and Dart will not finish recompiling). The result should look like this.

Home page
Home page

Next, we need to prepare a new page for displaying a QR code. Create a new directory named pages inside libs. Let’s create a new file inside it and call it code_viewer.dart. The new class should be located inside that newly-created directory.

Fill it with below code:

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

class CodeViewerPage extends StatefulWidget {
const CodeViewerPage({Key key, this.title}) : super(key: key);

final String title;

@override
State<CodeViewerPage> createState() => _CodeViewerPageState();
}

class _CodeViewerPageState extends State<CodeViewerPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
"This is your qr code",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24),
),
Container(
child: _buildQrCode(""),
width: 400,
height: 400,
color: Colors.red,
),
TextButton(
style: TextButton.styleFrom(primary: Colors.blue),
onPressed: _downloadPdf,
child: const Text("Download as PDF"),
)
],
),
),
);
}

Widget _buildQrCode(String message) {
// TODO
return Container();
}

void _downloadPdf() {
// TODO
}
}

As you can see, we have some unfinished methods but we will come back here later, after we finish building the UI. For now, let’s consider it as a placeholder.

Now, when opening the app, after clicking on “Generate”, you should see a page shown below.

Code Viewer page
Code Viewer page

Adding new libraries

  • QR code is a two-dimensional matrix, where you can store alphanumeric data. Let’s use the ready and stable version of qr_flutter.
  • For PDF generation, we need two libraries: pdf and screenshot.

Let’s open pubspec.yaml and update the environment (this is required by qr_flutter library),

environment:
sdk: “>=2.11.0 <3.0.0”

also, add these dependencies:

dependencies:
pdf: ^3.6.0
qr_flutter: ^4.0.0
screenshot: ^1.2.3

when saving the file, VS Code should automatically install new libraries but if not, perform the command in terminal:

$ pub get

Implement QR code generator

Let’s start with importing the code_viewer.dart, at the beginning of the file type.

import ‘package:qr_code_generator/pages/code_viewer.dart’;

Then update our method to navigate to another page.

void _showCode() {
Navigator.of(context)
.pushNamed("viewer", arguments: {"message": _controller.text});
}

As you can see, we pass the Map object with a typed message to a new page.

Switch to code_viewer.dart file, import these libraries:

import ‘dart:typed_data’;
import ‘package:flutter/material.dart’;
import ‘package:flutter/widgets.dart’;
import ‘package:qr_flutter/qr_flutter.dart’;
import ‘package:pdf/pdf.dart’;
import ‘package:pdf/widgets.dart’ as pw;
import ‘dart:convert’;
import ‘dart:html’ as html;

Please, update the build method of the _CodeViewerPageState.

Widget build(BuildContext context) {
Map<String, String> args = ModalRoute.of(context).settings.arguments as Map;
_buildQrCode(args["code"]);

return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
"This is your qr code",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24),
),
Container(child: _qrImage, width: 400, height: 400),
TextButton(
style: TextButton.styleFrom(primary: Colors.blue),
onPressed: _downloadPdf,
child: const Text("Download as PDF"),
)
],
),
),
);
}

We need some explanation here. First, we obtain the message which we passed on the previous page. In method _buildQrCode(String message) we build an object with type QrImage using String message. After that, we can replace the placeholder inside the Container, where _qrImage will be shown.

As a result, the web application is almost ready, restart it.

Home page form
Home page form
Generated QR code
Generated QR code

Implementing PDF generation

Generating a PDF file from Widget is not trivial in Flutter, but we can simply use a library screenshot to take a snapshot of the displayed QrImage. Then, we will convert the encoded screenshot into an Image object. On the web, we do not have a directory structure, so we cannot rely on a temporary directory to let users fetch a file. What we can do is to prepare the generated PDF in memory and use the dart HTML library to build an anchor element.

Let’s dive into coding and replace empty method _downloadPdf() with the code below:

void _downloadPdf() async {
final pdf = pw.Document();

ScreenshotController screenshotController = ScreenshotController();

Uint8List pngBytes = await screenshotController.captureFromWidget(_qrImage);

pw.MemoryImage imageImage = pw.MemoryImage(pngBytes);
pw.Image pdfImage = pw.Image(imageImage);

pdf.addPage(pw.Page(
pageFormat: PdfPageFormat.a4,
build: (pw.Context context) {
return pw.Center(child: pdfImage); // Center
})); // Page

final rawData = await pdf.save();
final content = base64Encode(rawData);
html.AnchorElement(
href: "data:application/octet-stream;charset=utf-16le;base64,$content")
..setAttribute("download", "qr_code.pdf")
..click();
}
Downloaded PDF file
Downloaded PDF file

Is Flutter for web universal?

We have seen that this framework can help you bring a robust application to your business, but it will not be the best solution to all problems. Remember that Flutter SDK is used to create app-centric services. It is not a good tool to develop blog articles with rich-text documents. Of course, you can always bring interactive features to your website.

Congratulations, you’ve created your QR generator!

This is the end, we have successfully implemented a Flutter for web application that generates QR codes and lets you download the PDF file. We have done it without HTML and CSS. Furthermore, we can publish the result to the web server. Simply follow the steps from this official documentation website.

Deviniti is your guide to the universe of digital transformation and enterprise software. Check out who we are and what we can do on our website.

If you want to learn more Flutter tips and tricks, make sure to check out other articles available on Deviniti Technology-Driven Blog:

--

--

Sebastian Kotarski
Deviniti Technology-Driven Blog

iOS Dev, Flutter enthusiast. In the meantime, gamer and body building amateur