Home About

Published

- 4 min read

QR Private Code

img of QR Private Code

QR Private Code

Is a lightweight mobile application designed to read and store QR codes in a secure, offline environment. This article provides an overview of how the app is developed using Angular and Capacitor, along with the specific plugin used to access the device camera.

Technology Stack

The app is developed using the following technologies:

  • Angular: A popular framework for building mobile and desktop web applications.
  • Capacitor: A cross-platform app runtime that makes it easy to build web apps that run natively on iOS, Android, and the web.
  • Camera Plugin: Used to access the device camera for scanning QR codes.

Development Process

Setting Up the Angular Project

First, we set up an Angular project. If you don’t have Angular CLI installed, you can install it using:

   npm install -g @angular/cli

Create a new Angular project:

   ng new qr-private-code
cd qr-private-code

Adding Capacitor

Next, we add Capacitor to the Angular project. Capacitor is used to wrap the Angular application and enable it to run as a native mobile app.

Install Capacitor:

   npm install @capacitor/core @capacitor/cli
npx cap init

Adding the Camera Plugin

To enable the app to access the device camera, we use a Capacitor plugin. The plugin opens the device camera and detects QR codes.

Install the Capacitor camera plugin:

   npm install @capacitor-mlkit/barcode-scanning
npx cap sync

Integrating Camera Functionality

With the plugin installed, we can now integrate the camera functionality into our Angular app. Below is a simplified example of how this can be achieved:

   import { Component } from '@angular/core';
import {
  BarcodeScanner,
  BarcodeFormat,
  LensFacing,
} from '@capacitor-mlkit/barcode-scanning';
import { contactRegex, getContactData, getWifiAndPass, wifiConfigRegex } from './regex';
import { ModalController, ToastController } from '@ionic/angular';
import { SaveQrCodeComponent } from '../save-qr-code/save-qr-code.component';
import { SavedCodesComponent } from '../saved-code/saved-codes.component';
import { QrCode, QrCodeType } from '../models/qr-code';

const { Camera } = Plugins;

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
  public currentQRCode: string;
	public streamOn: boolean = false;
  constructor(
		private mymodal: ModalController,
    private toast: ToastController,
    private ref: ChangeDetectorRef
	) {}

  public async scanCode() {
    try {
      this.streamOn = true;
      document.querySelector('body')?.classList.add('barcode-scanner-active');
      const listener = await BarcodeScanner.addListener(
        'barcodeScanned',
        async result => {
          await listener.remove();
          console.log('Barcode data', result?.barcode);
          const qr = this.getQrCodeFromResult(result?.barcode?.rawValue)
          await this.closeStream(qr);
        },
      );
      await BarcodeScanner.startScan({
        lensFacing: LensFacing.Back,
        formats: [BarcodeFormat.QrCode],
      });
    } catch (e) {
      console.error('', e);
    } finally {
      this.streamOn = false;
    }
  }

	public async closeStream(qr: QrCode | null = null) {
    if (qr) {
      this.currentQRCode = qr;
    }
    await BarcodeScanner.removeAllListeners();
    await BarcodeScanner.stopScan();
    setTimeout(() => {
      this.streamOn = false;
      this.importedImg = '';
      this.file = null;
      document.querySelector('body')?.classList.remove('barcode-scanner-active');
      this.ref.detectChanges();
    }, 500);
  }

  private getQrCodeFromResult(result: string): QrCode {
    let qr: QrCode = {
      n: '', // name
      d: [], // data : One line per data type
      v: result, // raw value can be used to recreate an image of the qr code
      date: (new Date()).toISOString(), // date of the scan
      t: QrCodeType.Unknown // type of the qr code
    }
		// properties have short names to reduce the size of the qr code object we store.
    if (!result) {
      return  qr;
    }
    if (wifiConfigRegex.test(result)) {
      qr = getWifiAndPass(result);
    } else if (result.indexOf('http') === 0) {
      qr.t = QrCodeType.Url;
      qr.v = result;
      qr.n = new URL(result).hostname;
      qr.d = [result];
    } else if (
      contactRegex.test(result)
    ) {
      return getContactData(result);
    }
    return qr;
  }
}

QR Code Detection and Processing

Once the QR code is detected, it is returned to the Angular app for further processing. The app tries to understand the type of QR code scanned and processes it accordingly. This involves:

  • Detecting the QR Code Value: This is taken care of by the plugin we use here (see their github page here).
  • Processing the QR Code: Determining the type of QR code (e.g., URL, WiFi code) and handling it appropriately.
  • Displaying the QR Code: Once read, the Qr code can be displayed in a raw format alongside a prettier format when the type is recognized.

Storing Data Locally

All scanned QR codes and their associated data are stored locally on the user’s device. This ensures that sensitive information is kept private and secure. Users can add or delete entries as needed, and all data is permanently deleted if the app is uninstalled.

Conclusion

QR Private Code is a secure and private QR code reader application built using Angular and Capacitor. By leveraging the capabilities of Capacitor and integrating the camera plugin, we have created an app that ensures user data privacy while providing essential QR code functionality.