How to Implement a Flutter QR Code Scanner Plugin for iOS in Swift

Flutter QR Code Scanner Plugin

Dev Environment

  • M1 Mac
  • Xcode 13.2.1

Step-by-step Guide: Implement Flutter QR Code Scanner Plugin for iOS

Step 1: Get the Existing Flutter Plugin Project:

git clone https://github.com/yushulx/flutter_qrcode_scanner

Step 2: Add Support for iOS

cd flutter_qrcode_scanner
flutter create --template=plugin --platforms=ios .

Step 3: Install Dynamsoft Camera Enhancer and Dynamsoft Barcode Reader

s.dependency 'DynamsoftBarcodeReader', '8.9.1'
s.dependency 'DynamsoftCameraEnhancer', '2.1.1'

Activating Mobile QR Code SDK

Step 4: Implement the Factory and the Platform View Using Swift Code

  1. Based on the structure of the Android QRCodeScanner class, we create a FLQRCodeScanner class in iOS/Classes/FLQRCodeScanner.swift:
import Flutter
import UIKit
import DynamsoftBarcodeReader
import DynamsoftCameraEnhancer

public protocol DetectionHandler {
func onDetected(data: NSArray)
}

class FLQRCodeScanner: NSObject, DBRTextResultDelegate {

private var cameraView: DCECameraView
private var dce: DynamsoftCameraEnhancer
private var barcodeReader: DynamsoftBarcodeReader! = nil
private var handler: DetectionHandler?

init(cameraView: DCECameraView, dce: DynamsoftCameraEnhancer) {
self.cameraView = cameraView
self.cameraView.overlayVisible = true
self.dce = dce
super.init()

createBarcodeReader(dce: dce)
}

func setDetectionHandler(handler: DetectionHandler) {
self.handler = handler;
}

func createBarcodeReader(dce: DynamsoftCameraEnhancer) {
// To activate the sdk, apply for a license key: https://www.dynamsoft.com/customer/license/trialLicense?product=dbr
barcodeReader = DynamsoftBarcodeReader.init(license: "license-key")
barcodeReader.setCameraEnhancer(dce)

// Set text result call back to get barcode results.
barcodeReader.setDBRTextResultDelegate(self, userData: nil)

// Start the barcode decoding thread.
barcodeReader.startScanning()
}

func textResultCallback(_ frameId: Int, results: [iTextResult]?, userData: NSObject?) {
if results!.count > 0 {
let outResults = NSMutableArray()
for item in results! {
let subDic = NSMutableDictionary()
if item.barcodeFormat_2 != EnumBarcodeFormat2.Null {
subDic.setObject(item.barcodeFormatString_2 ?? "", forKey: "format" as NSCopying)
}else{
subDic.setObject(item.barcodeFormatString ?? "", forKey: "format" as NSCopying)
}
subDic.setObject(item.barcodeText ?? "", forKey: "text" as NSCopying)
let points = item.localizationResult?.resultPoints as! [CGPoint]
subDic.setObject(Int(points[0].x), forKey: "x1" as NSCopying)
subDic.setObject(Int(points[0].y), forKey: "y1" as NSCopying)
subDic.setObject(Int(points[1].x), forKey: "x2" as NSCopying)
subDic.setObject(Int(points[1].y), forKey: "y2" as NSCopying)
subDic.setObject(Int(points[2].x), forKey: "x3" as NSCopying)
subDic.setObject(Int(points[2].y), forKey: "y3" as NSCopying)
subDic.setObject(Int(points[3].x), forKey: "x4" as NSCopying)
subDic.setObject(Int(points[3].y), forKey: "y4" as NSCopying)
subDic.setObject(item.localizationResult?.angle ?? 0, forKey: "angle" as NSCopying)
outResults.add(subDic)
}

if handler != nil {
handler!.onDetected(data: outResults)
}
}
}

func startScan() {
cameraView.overlayVisible = true
barcodeReader.startScanning()
}
import Flutter
import UIKit
import DynamsoftCameraEnhancer

class FLNativeView: NSObject, FlutterPlatformView, DetectionHandler {
private var _view: UIView
private var messenger: FlutterBinaryMessenger
private var channel: FlutterMethodChannel
private var qrCodeScanner: FLQRCodeScanner
init(
frame: CGRect,
viewIdentifier viewId: Int64,
arguments args: Any?,
binaryMessenger: FlutterBinaryMessenger
) {
self.messenger = binaryMessenger
let cameraView = DCECameraView.init(frame: frame)
let dce = DynamsoftCameraEnhancer.init(view: cameraView)
dce.open()
dce.setFrameRate(30)
_view = cameraView

qrCodeScanner = FLQRCodeScanner.init(cameraView: cameraView, dce: dce)

channel = FlutterMethodChannel(name: "com.dynamsoft.flutter_camera_qrcode_scanner/nativeview_" + String(viewId), binaryMessenger: messenger)

super.init()

qrCodeScanner.setDetectionHandler(handler: self)
channel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
switch call.method {
case "startScanning":
self.qrCodeScanner.startScan()
result(.none)
case "stopScanning":
self.qrCodeScanner.stopScan()
result(.none)
case "setLicense":
self.qrCodeScanner.setLicense(license: (call.arguments as! NSDictionary).value(forKey: "license") as! String)
result(.none)
case "setBarcodeFormats":
self.qrCodeScanner.setBarcodeFormats(arg: call.arguments as! NSDictionary)
result(.none)
default:
result(.none)
}
})
}

func view() -> UIView {
return _view
}

func onDetected(data: NSArray) {
DispatchQueue.main.async {
self.channel.invokeMethod("onDetected", arguments: data)
}
}
}
import Flutter
import UIKit

class FLNativeViewFactory: NSObject, FlutterPlatformViewFactory {
private var messenger: FlutterBinaryMessenger

init(messenger: FlutterBinaryMessenger) {
self.messenger = messenger
super.init()
}

func create(
withFrame frame: CGRect,
viewIdentifier viewId: Int64,
arguments args: Any?
) -> FlutterPlatformView {
return FLNativeView(
frame: frame,
viewIdentifier: viewId,
arguments: args,
binaryMessenger: messenger
)
}
}
import Flutter
import UIKit

public class SwiftFlutterCameraQrcodeScannerPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let factory = FLNativeViewFactory(messenger: registrar.messenger())
registrar.register(factory, withId: "com.dynamsoft.flutter_camera_qrcode_scanner/nativeview")
}
}

Step 5: Test the QR code scanner in Flutter

  1. Go to the example folder and add the camera access permission to ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Can I use the camera please?</string>
<key>NSMicrophoneUsageDescription</key>
<string>Can I use the mic please?</string>
flutter run

Source Code

--

--

--

Manager of Dynamsoft Open Source Projects | Tech Lover

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Xiao Ling

Xiao Ling

Manager of Dynamsoft Open Source Projects | Tech Lover

More from Medium

Let’s Flutter

Using Realm Flexible Sync in Your App

Displaying FCM notifications on iOS Simulators

What is the Relation Between Stateful and Stateless Widgets In Flutter?