DEV Community

Xiao Ling
Xiao Ling

Posted on • Originally published at dynamsoft.com

How to Integrate a Barcode Scanner Component into iOS Apps in Minutes

In this article, we will explore Dynamsoft's Ready-to-Use Barcode Scanner API for iOS. We will cover how to integrate the barcode scanner framework, distributed via the Swift Package Manager, into an iOS SwiftUI project, as well as how to customize its functionalities by modifying the source code.

iOS Barcode Scanner Demo

Prerequisites

Setting Up the iOS Project

  1. Create a new iOS project in Xcode and select SwiftUI as the user interface.
  2. Click "File" -> "Add Package Dependencies..." to add all required frameworks via Swift Package Manager. The package URL is https://github.com/Dynamsoft/barcode-reader-spm.

    Swift Package Manager for barcode reader bundle

Implementing an iOS Barcode Scanner in Minutes

Create a Text view to display the barcode result and two buttons to launch the single barcode scanner and multi-barcode scanner.

import DynamsoftBarcodeReaderBundle
import DynamsoftLicense
import SwiftUI

struct ContentView: View {
    @State private var scanResult: String = "Scan results will appear here"

    var body: some View {
        VStack(spacing: 16) {
            ScrollView {
                Text(scanResult)
                    .font(.system(size: 20))
                    .padding(16)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(Color.white)
                    .foregroundColor(.black)
                    .lineSpacing(4)
            }
            .background(Color.white)
            .cornerRadius(8)
            .shadow(radius: 2)

            Spacer()

            HStack(spacing: 8) {
                Button(action: {
                    presentBarcodeScanner(mode: .single)
                }) {
                    Text("Single Scan")
                        .font(.headline)
                        .foregroundColor(.white)
                        .padding()
                        .frame(maxWidth: .infinity)
                        .background(Color.blue)
                        .cornerRadius(8)
                }

                Button(action: {
                    presentBarcodeScanner(mode: .multiple)

                }) {
                    Text("Multi Scan")
                        .font(.headline)
                        .foregroundColor(.white)
                        .padding()
                        .frame(maxWidth: .infinity)
                        .background(Color.blue)
                        .cornerRadius(8)
                }
            }
        }
        .padding(16)
        .background(Color(UIColor.systemGroupedBackground))
    }
}
Enter fullscreen mode Exit fullscreen mode

The SDK provides a UIKit-based view controller, BarcodeScannerViewController, which allows real-time barcode scanning with a camera preview. To integrate this view controller into a SwiftUI project, we need to create a UIViewControllerRepresentable wrapper:

struct BarcodeScannerView: UIViewControllerRepresentable {
    let config: BarcodeScannerConfig
    var onScannedResult: ((BarcodeScanResult) -> Void)?

    func makeUIViewController(context: Context) -> BarcodeScannerViewController {
        let vc = BarcodeScannerViewController()
        vc.config = config
        vc.onScannedResult = onScannedResult
        return vc
    }

    func updateUIViewController(_ uiViewController: BarcodeScannerViewController, context: Context)
    {}
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • BarcodeScannerConfig is a struct that defines the barcode scanner settings.
  • BarcodeScanResult is a struct that stores the scanned barcode data.
  • onScannedResult is a callback function that handles the scanned barcode result.

Now, we can launch the barcode scanner by clicking one of the buttons. Be sure to replace LICENSE-KEY with your own.

func presentBarcodeScanner(mode: ScanningMode) {
        let config = BarcodeScannerConfig()
        config.license = "LICENSE-KEY"
        config.scanningMode = mode

        var scannerView = BarcodeScannerView(config: config)
        scannerView.onScannedResult = { result in
            DispatchQueue.main.async {
                switch result.resultStatus {
                case .finished:
                    let items = result.barcodes

                    if items != nil && items!.count > 0 {
                        var index = 0
                        self.scanResult = ""
                        for item in items! {
                            if item.type == .barcode {
                                self.scanResult +=
                                    "Result \(index): \nFormat: \(item.formatString)\nText: \(item.text)\n\n"
                                index += 1
                            }
                        }
                    }

                case .canceled:
                    self.scanResult = "Scan canceled"
                case .exception:
                    self.scanResult = result.errorString ?? "Unknown error"
                @unknown default:
                    break
                }

                UIApplication.shared.windows.first?.rootViewController?.dismiss(
                    animated: true, completion: nil)
            }
        }

        UIApplication.shared.windows.first?.rootViewController?.present(
            UIHostingController(rootView: scannerView),
            animated: true,
            completion: nil
        )
    }
Enter fullscreen mode Exit fullscreen mode

iOS single barcode scanner

Customizing the Barcode Scanner

The barcode scanner component is open-source. You can access the source code in the GitHub repository.

The following steps demonstrate how to integrate the source code project into an iOS project and apply some customizations.

Step 1: Integrate the Source Code Project into Your iOS Project

  1. Clone the project from the GitHub repository.
  2. Click "File" -> "Add Files" to add the cloned project as a sub-project.

    Add local project as sub-project

  3. Replace the dependent framework with the local project:

    • Select the project target.
    • Navigate to "General" -> "Frameworks, Libraries, and Embedded Content".
    • Remove the DynamsoftBarcodeReaderBundle and add DynamsoftBarcodeReaderBundle.framework.

    Replace the dependent framework

Step 2: Add a Capture Button to Manually Return Multiple Barcode Results

By default, the prebuilt multi-barcode scanner automatically returns results. To modify this behavior, we will change the logic in BarcodeScannerViewController.swift to allow manual result capture.

  1. Modify handleMultipleResult() to store the scanned results instead of returning them immediately:

    var temporaryResult: DecodedBarcodesResult?
    
    private func handleMultipleResult(_ result: DecodedBarcodesResult) {
        guard let items = result.items, items.count > 0 else {
            stableFrameCount = 1
            return
        }
    
        temporaryResult = result
    //        if items.count >= config.expectedBarcodesCount {
    //            stop()
    //            if config.isBeepEnabled {
    //                Feedback.beep()
    //            }
    //            onScannedResult?(.init(resultStatus: .finished, barcodes: result.items))
    //        } else {
    //            guard let resultitems = referenceItems else {
    //                stableFrameCount = 1
    //                referenceItems = items
    //                return
    //            }
    //            if isStable(items: items, resultitems: resultitems) {
    //                stableFrameCount += 1
    //                if stableFrameCount >= config.maxConsecutiveStableFramesToExit {
    //                    stop()
    //                    if config.isBeepEnabled {
    //                        Feedback.beep()
    //                    }
    //                    onScannedResult?(.init(resultStatus: .finished, barcodes: result.items))
    //                }
    //            } else {
    //                stableFrameCount = 1
    //                referenceItems = items
    //            }
    //        }
        }
    
  2. Add a Capture button to trigger the result return manually:

    lazy var captureButton: UIButton = {
        let bundle = Bundle(for: type(of: self))
        let button = UIButton()
        let captureImage = UIImage(systemName: "camera.circle.fill")
        button.setImage(captureImage?.withRenderingMode(.alwaysOriginal), for: .normal)
        button.tintColor = .systemBlue 
    
        button.setPreferredSymbolConfiguration(
            UIImage.SymbolConfiguration(pointSize: 40, weight: .regular, scale: .large),
            forImageIn: .normal
        )
        button.addTarget(self, action: #selector(onCaptureButtonTouchUp), for: .touchUpInside)
        return button
    }()
    
    @objc func onCaptureButtonTouchUp() {
        if temporaryResult != nil {
            onScannedResult?(.init(resultStatus: .finished, barcodes: temporaryResult?.items))
        } else {
            print("No results to capture.")
        }
    }
    
  3. Integrate the Capture button into the UI:

    private func setupUI() {
        ...
    
        captureButton.isHidden = config.scanningMode == .single
        captureButton.translatesAutoresizingMaskIntoConstraints = false
    
        let stackView = UIStackView(arrangedSubviews: [torchButton, captureButton, cameraButton])
        ...
    }
    
  4. Re-run the project to see the changes:

    iOS multiple barcode scanner

Source Code

https://github.com/yushulx/ios-swiftui-barcode-mrz-document-scanner/tree/main/examples/BarcodeScanner

Top comments (0)