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
- Free trial license for Dynamsoft Barcode Reader.
- Ready-to-Use Barcode Scanner API documentation for iOS
Setting Up the iOS Project
- Create a new iOS project in Xcode and select SwiftUI as the user interface.
-
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
.
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))
}
}
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)
{}
}
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
)
}
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
- Clone the project from the GitHub repository.
-
Click "File" -> "Add Files" to add the cloned project as a sub-project.
-
Replace the dependent framework with the local project:
- Select the project target.
- Navigate to "General" -> "Frameworks, Libraries, and Embedded Content".
- Remove the
DynamsoftBarcodeReaderBundle
and addDynamsoftBarcodeReaderBundle.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.
-
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 // } // } }
-
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.") } }
-
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]) ... }
-
Re-run the project to see the changes:
Top comments (0)