iOS General Example
Creating Barkoder Configuration #
The createBarkoderConfig method is responsible for setting up the configuration required to initiate barcode scanning. This configuration includes the license key necessary for validating and activating the SDK.
If the license key is invalid or missing, the scan results will contain an "UNLICENSED" prefix and random asterisks.
private func createBarkoderConfig() {
// In order to perform scanning, config property need to be set before
// If license key is not valid you will receive results with asterisks inside
barkoderView.config = BarkoderConfig(licenseKey: "LICENSE_KEY") { licenseResult in
print("Licensing SDK: \(licenseResult)")
}
}
Enabling Symbologies #
Here’s a detailed and refined explanation of how you can enable individual symbologies for barcode scanning using both direct configuration and JSON configuration in Swift
Enabling Symbologies Directly #
You can enable individual symbologies directly by setting the enabled property of each symbology in the decoderConfig object. Here’s a method that demonstrates how to do this:
private func setActiveBarcodeTypes() {
guard let decoderConfig = barkoderView.config?.decoderConfig else { return }
decoderConfig.ean13.enabled = true
decoderConfig.upcA.enabled = true
decoderConfig.qr.enabled = true
}
Enabling Symbologies via JSON Configuration #
Alternatively, you can enable symbologies using a JSON configuration. This approach allows you to define the symbology settings in a more structured and flexible manner. Here’s how you can do it:
private func setActiveBarcodeTypes() {
guard let config = barkoderView.config else { return }
let json: [String: Any] = [
“decoder”: [
“QR”: [
“enabled”: true
],
“Aztec”: [
“enabled”: true
],
“Aztec Compact”: [
“enabled”: true
],
“QR Micro”: [
“enabled”: true
]
]
]
do {
let jsonData = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
BarkoderHelper.applyConfigSettingsFromJson(config, jsonData: jsonData) { updatedConfig, error in
if let error {
print(“\(error.localizedDescription)“)
}
}
} catch {
print(“Error converting dictionary to JSON data: \(error)“)
}
}
Starting scan
func startScanning() {
do {
try barkoderView.startScanning(self)
} catch {
print(error.localizedDescription)
}
}
Available Barcode Types #
guard let decoderConfig = barkoderView.config?.decoderConfig else { return } //get decoder config
decoderConfig.aztec.enabled = true
decoderConfig.aztecCompact.enabled = true
decoderConfig.qr.enabled = true
decoderConfig.qrMicro.enabled = true
decoderConfig.code128.enabled = true
decoderConfig.code93.enabled = true
decoderConfig.code39.enabled = true
decoderConfig.codabar.enabled = true
decoderConfig.code11.enabled = true
decoderConfig.msi.enabled = true
decoderConfig.upcA.enabled = true
decoderConfig.upcE.enabled = true
decoderConfig.upcE1.enabled = true
decoderConfig.ean13.enabled = true
decoderConfig.ean8.enabled = true
decoderConfig.pdf417.enabled = true
decoderConfig.pdf417Micro.enabled = true
decoderConfig.datamatrix.enabled = true
decoderConfig.code25.enabled = true
decoderConfig.interleaved25.enabled = true
decoderConfig.itf14.enabled = true
decoderConfig.iata25.enabled = true
decoderConfig.matrix25.enabled = true
decoderConfig.datalogic25.enabled = true
decoderConfig.coop25.enabled = true
decoderConfig.code32.enabled = true
decoderConfig.telepen.enabled = true
decoderConfig.dotcode.enabled = true
decoderConfig.idDocument.enabled = true
decoderConfig.databar14.enabled = true
decoderConfig.databarLimited.enabled = true
decoderConfig.databarExpanded.enabled = true
decoderConfig.postalIMB.enabled = true
decoderConfig.postnet.enabled = true
decoderConfig.planet.enabled = true
decoderConfig.australianPost.enabled = true
decoderConfig.royalMail.enabled = true
decoderConfig.kix.enabled = true
decoderConfig.japanesePost.enabled = true
decoderConfig.maxiCode.enabled = true
Setting barkoder settings #
The setBarkoderSettings method
Next define a function setBarkoderSettings where we will update our settings for the barcode scanner view (bkdView).
In our case we will enable image results and include barcode location within the image, also make the region of interest visible and enable pinch-to-zoom functionality.
Finally, configure the ROI to cover the central 90% of the scanner view.
These configurations enhance the user experience by providing more detailed scan results, interactive zooming, and visual feedback about the scan area.
private func setBarkoderSettings() {
guard let config = barkoderView.config else { return }
// These are optional settings, otherwise default values will be used
config.imageResultEnabled = true
config.locationInImageResultEnabled = true
config.regionOfInterestVisible = true
config.pinchToZoomEnabled = true
try? config.setRegionOfInterest(CGRect(x: 5, y: 5, width: 90, height: 90))
}
Starting Scan #
The startScanning method initiates the scanning process. If there is an error during the start process, the error message is printed for debugging.
func startScanning() {
if !scanningInProcess {
try? barkoderView.startScanning(self)
} else {
barkoderView.stopScanning()
}
resetResult()
scanningInProcess.toggle()
}
Handling Results #
Implementing the BarkoderResultDelegate allows your view controller to receive scanning results. The scanningFinished method is called when scanning is complete, providing the results, optional thumbnails, and the captured image.
func scanningFinished(_ decoderResults: [DecoderResult], thumbnails: [UIImage]?, image: UIImage?) {
if let decoderResult = decoderResults.first, let thumbnail = thumbnails?.first {
showResult(decoderResult, thumbnail: thumbnail, image: image)
}
scanningInProcess = false
}
showResult #
The showResult function updates the UI based on the state of the scanning process and the results obtained
private func showResult(_ decoderResult: DecoderResult, thumbnail: UIImage?, image: UIImage?) {
resultImageView.image = image
thumbnailImageView.image = thumbnail
typeResultLabel.text = decoderResult.barcodeTypeName
resultValueLabel.text = decoderResult.textualData
resultFromScanning = decoderResult.textualData
let extras: [String] = decoderResult.extra.map {
return "\($0): \($1)"
}
extrasResultLabel.text = extras.joined(separator: "\n")
}
Complete solution #
In the end, let's merge all of these functions and implement them within our main view controller.
This code would go in your view controller, and of course it will be different for your project, but generally it's a good starting point to have.
//
// BKDSample.swift
// Barkoder
//
// Created by Goran Chakarevski on 26.11.25.
//
import UIKit
import BarkoderSDK
final class ViewController: UIViewController {
// MARK: - UI
private let barkoderView = BarkoderView()
private let resultImageView = UIImageView()
private let scrollView = UIScrollView()
private let contentView = UIView()
private let introLabel = UILabel()
private let resultHolderView = UIView()
private let typeHolderView = UIView()
private let extrasHolderView = UIView()
private let resultTitleLabel = UILabel()
private let typeTitleLabel = UILabel()
private let extrasTitleLabel = UILabel()
private let resultValueLabel = UILabel()
private let typeResultLabel = UILabel()
private let extrasResultLabel = UILabel()
private let thumbnailCardView = UIView()
private let thumbnailImageView = UIImageView()
private let scanButton = ScanButton(type: .system)
// MARK: - Constants
private let holderViewBackgroundColor: UIColor = .white
private let barkoderBackgroundColor: UIColor = UIColor(
red: 242/255.0,
green: 242/255.0,
blue: 242/255.0,
alpha: 1
)
private let resultsMaximumLines = 2
private let holderViewCornerRadius = 16.0
private var resultFromScanning: String?
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
setupBaseView()
setupSubviews()
setupLayout()
createBarkoderConfig()
setActiveBarcodeTypes()
setBarkoderSettings()
}
// MARK: - Setup
private func setupBaseView() {
title = "Barkoder Sample (v\(iBarkoder.GetVersion()))"
view.backgroundColor = .white
}
private func setupSubviews() {
// Turn off autoresizing mask constraints
[
barkoderView,
resultImageView,
scrollView,
contentView,
introLabel,
resultHolderView,
typeHolderView,
extrasHolderView,
resultTitleLabel,
typeTitleLabel,
extrasTitleLabel,
resultValueLabel,
typeResultLabel,
extrasResultLabel,
thumbnailCardView,
thumbnailImageView,
scanButton
].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
}
// Barkoder view
barkoderView.backgroundColor = barkoderBackgroundColor
// Result image overlay (on top of barkoderView)
resultImageView.contentMode = .scaleAspectFit
resultImageView.backgroundColor = .black
resultImageView.isHidden = true
resultImageView.clipsToBounds = true
// Scroll view
scrollView.backgroundColor = .clear
contentView.backgroundColor = .clear
// Intro label
introLabel.text = "Click the scan button to start scanning."
introLabel.textAlignment = .center
introLabel.numberOfLines = 0
introLabel.font = .systemFont(ofSize: 14, weight: .regular)
introLabel.textColor = .black
// Holder views styling
[resultHolderView, typeHolderView, extrasHolderView].forEach { holder in
holder.backgroundColor = holderViewBackgroundColor
holder.layer.cornerRadius = holderViewCornerRadius
holder.layer.borderWidth = 1
holder.layer.borderColor = UIColor(white: 0.9, alpha: 1).cgColor
holder.layer.shadowColor = UIColor.black.cgColor
holder.layer.shadowOpacity = 0.05
holder.layer.shadowRadius = 8
holder.layer.shadowOffset = CGSize(width: 0, height: 4)
holder.layer.masksToBounds = false
}
// Title labels for holders
func configureTitleLabel(_ label: UILabel, text: String) {
label.text = text.uppercased()
label.font = .systemFont(ofSize: 12, weight: .semibold)
label.textColor = UIColor(white: 0.4, alpha: 1)
}
configureTitleLabel(resultTitleLabel, text: "Result")
configureTitleLabel(typeTitleLabel, text: "Type")
configureTitleLabel(extrasTitleLabel, text: "Extras")
// Result labels
[resultValueLabel, typeResultLabel, extrasResultLabel].forEach { label in
label.textColor = .black
label.font = .systemFont(ofSize: 15, weight: .regular)
label.numberOfLines = resultsMaximumLines
}
typeResultLabel.font = .systemFont(ofSize: 16, weight: .semibold)
// Tap on resultHolderView to see full result
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapViewAllResult))
resultHolderView.addGestureRecognizer(tapGesture)
resultHolderView.isUserInteractionEnabled = true
// Thumbnail card design
thumbnailCardView.backgroundColor = .white
thumbnailCardView.layer.cornerRadius = holderViewCornerRadius
thumbnailCardView.layer.borderWidth = 1
thumbnailCardView.layer.borderColor = UIColor(white: 0.9, alpha: 1).cgColor
thumbnailCardView.layer.shadowColor = UIColor.black.cgColor
thumbnailCardView.layer.shadowOpacity = 0.06
thumbnailCardView.layer.shadowRadius = 10
thumbnailCardView.layer.shadowOffset = CGSize(width: 0, height: 6)
thumbnailCardView.layer.masksToBounds = false
thumbnailImageView.contentMode = .scaleAspectFit
thumbnailImageView.backgroundColor = UIColor(white: 0.97, alpha: 1)
thumbnailImageView.layer.cornerRadius = 12
thumbnailImageView.layer.borderWidth = 1
thumbnailImageView.layer.borderColor = UIColor(white: 0.9, alpha: 1).cgColor
thumbnailImageView.clipsToBounds = true
// Scan button styling
var configuration = UIButton.Configuration.filled()
configuration.image = UIImage(named: "btn_ffa")
configuration.baseBackgroundColor = UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1.00)
configuration.baseForegroundColor = .white
configuration.cornerStyle = .capsule
configuration.contentInsets = NSDirectionalEdgeInsets(top: 16, leading: 28, bottom: 16, trailing: 28)
configuration.title = "Scan"
configuration.imagePadding = 8
scanButton.configuration = configuration
scanButton.titleLabel?.font = .systemFont(ofSize: 18, weight: .semibold)
scanButton.layer.shadowColor = UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1.00).cgColor
scanButton.layer.shadowOpacity = 0.2
scanButton.layer.shadowOffset = CGSize(width: 0, height: 6)
scanButton.layer.shadowRadius = 12
scanButton.addTarget(self, action: #selector(didTapScanButton), for: .touchUpInside)
updateScanButtonAppearance()
// Add subviews (order so resultImageView overlays barkoderView)
view.addSubview(barkoderView)
view.addSubview(resultImageView)
view.addSubview(scrollView)
view.addSubview(scanButton)
scrollView.addSubview(contentView)
// Content inside scroll view
contentView.addSubview(introLabel)
contentView.addSubview(resultHolderView)
contentView.addSubview(typeHolderView)
contentView.addSubview(extrasHolderView)
contentView.addSubview(thumbnailCardView)
// Holder content
resultHolderView.addSubview(resultTitleLabel)
resultHolderView.addSubview(resultValueLabel)
typeHolderView.addSubview(typeTitleLabel)
typeHolderView.addSubview(typeResultLabel)
extrasHolderView.addSubview(extrasTitleLabel)
extrasHolderView.addSubview(extrasResultLabel)
// Thumbnail card content
thumbnailCardView.addSubview(thumbnailImageView)
}
private func setupLayout() {
let safe = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// Barkoder view pinned to safe area top
barkoderView.topAnchor.constraint(equalTo: safe.topAnchor),
barkoderView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
barkoderView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
barkoderView.heightAnchor.constraint(equalToConstant: 320),
// Result image overlay (same frame as barkoderView)
resultImageView.topAnchor.constraint(equalTo: barkoderView.topAnchor),
resultImageView.leadingAnchor.constraint(equalTo: barkoderView.leadingAnchor),
resultImageView.trailingAnchor.constraint(equalTo: barkoderView.trailingAnchor),
resultImageView.bottomAnchor.constraint(equalTo: barkoderView.bottomAnchor),
// Scan button at bottom
scanButton.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: -4),
scanButton.centerXAnchor.constraint(equalTo: safe.centerXAnchor),
scanButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 56),
scanButton.widthAnchor.constraint(greaterThanOrEqualToConstant: 220),
// Scroll view between scanner and button
scrollView.topAnchor.constraint(equalTo: barkoderView.bottomAnchor, constant: 8),
scrollView.leadingAnchor.constraint(equalTo: safe.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: safe.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: scanButton.topAnchor, constant: -16),
// Content view inside scroll view
contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
contentView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor),
// Intro label at top of content
introLabel.topAnchor.constraint(equalTo: contentView.topAnchor),
introLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
introLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
// RESULT holder
resultHolderView.topAnchor.constraint(equalTo: introLabel.bottomAnchor, constant: 4),
resultHolderView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
resultHolderView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
resultTitleLabel.topAnchor.constraint(equalTo: resultHolderView.topAnchor, constant: 10),
resultTitleLabel.leadingAnchor.constraint(equalTo: resultHolderView.leadingAnchor, constant: 12),
resultTitleLabel.trailingAnchor.constraint(equalTo: resultHolderView.trailingAnchor, constant: -12),
resultValueLabel.topAnchor.constraint(equalTo: resultTitleLabel.bottomAnchor, constant: 4),
resultValueLabel.leadingAnchor.constraint(equalTo: resultHolderView.leadingAnchor, constant: 12),
resultValueLabel.trailingAnchor.constraint(equalTo: resultHolderView.trailingAnchor, constant: -12),
resultValueLabel.bottomAnchor.constraint(equalTo: resultHolderView.bottomAnchor, constant: -12),
// TYPE holder
typeHolderView.topAnchor.constraint(equalTo: resultHolderView.bottomAnchor, constant: 12),
typeHolderView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
typeHolderView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
typeTitleLabel.topAnchor.constraint(equalTo: typeHolderView.topAnchor, constant: 10),
typeTitleLabel.leadingAnchor.constraint(equalTo: typeHolderView.leadingAnchor, constant: 12),
typeTitleLabel.trailingAnchor.constraint(equalTo: typeHolderView.trailingAnchor, constant: -12),
typeResultLabel.topAnchor.constraint(equalTo: typeTitleLabel.bottomAnchor, constant: 4),
typeResultLabel.leadingAnchor.constraint(equalTo: typeHolderView.leadingAnchor, constant: 12),
typeResultLabel.trailingAnchor.constraint(equalTo: typeHolderView.trailingAnchor, constant: -12),
typeResultLabel.bottomAnchor.constraint(equalTo: typeHolderView.bottomAnchor, constant: -12),
// EXTRAS holder
extrasHolderView.topAnchor.constraint(equalTo: typeHolderView.bottomAnchor, constant: 12),
extrasHolderView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
extrasHolderView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
extrasTitleLabel.topAnchor.constraint(equalTo: extrasHolderView.topAnchor, constant: 10),
extrasTitleLabel.leadingAnchor.constraint(equalTo: extrasHolderView.leadingAnchor, constant: 12),
extrasTitleLabel.trailingAnchor.constraint(equalTo: extrasHolderView.trailingAnchor, constant: -12),
extrasResultLabel.topAnchor.constraint(equalTo: extrasTitleLabel.bottomAnchor, constant: 4),
extrasResultLabel.leadingAnchor.constraint(equalTo: extrasHolderView.leadingAnchor, constant: 12),
extrasResultLabel.trailingAnchor.constraint(equalTo: extrasHolderView.trailingAnchor, constant: -12),
extrasResultLabel.bottomAnchor.constraint(equalTo: extrasHolderView.bottomAnchor, constant: -12),
// Thumbnail card
thumbnailCardView.topAnchor.constraint(equalTo: extrasHolderView.bottomAnchor, constant: 16),
thumbnailCardView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
thumbnailCardView.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.6),
thumbnailImageView.topAnchor.constraint(equalTo: thumbnailCardView.topAnchor, constant: 12),
thumbnailImageView.leadingAnchor.constraint(equalTo: thumbnailCardView.leadingAnchor, constant: 12),
thumbnailImageView.trailingAnchor.constraint(equalTo: thumbnailCardView.trailingAnchor, constant: -12),
thumbnailImageView.heightAnchor.constraint(equalToConstant: 120),
thumbnailImageView.bottomAnchor.constraint(equalTo: thumbnailCardView.bottomAnchor, constant: -12),
// Content bottom
contentView.bottomAnchor.constraint(equalTo: thumbnailCardView.bottomAnchor, constant: 16)
])
}
// MARK: - Barkoder
private func createBarkoderConfig() {
barkoderView.config = BarkoderConfig(licenseKey: "LICENSE_KEY") { licenseResult in
print("Licensing SDK: \(licenseResult)")
}
}
private func setActiveBarcodeTypes() {
guard let decoderConfig = barkoderView.config?.decoderConfig else { return }
decoderConfig.ean13.enabled = true
decoderConfig.upcA.enabled = true
decoderConfig.qr.enabled = true
}
private func setBarkoderSettings() {
guard let config = barkoderView.config else { return }
// These are optional settings, otherwise default values will be used
config.imageResultEnabled = true
config.locationInImageResultEnabled = true
config.regionOfInterestVisible = true
config.pinchToZoomEnabled = true
try? config.setRegionOfInterest(CGRect(x: 5, y: 5, width: 90, height: 90))
}
private func showResult(_ decoderResult: DecoderResult, thumbnail: UIImage?, image: UIImage?) {
// Overlay image on scanner
if let image = image {
resultImageView.image = image
resultImageView.isHidden = false
} else {
resultImageView.image = nil
resultImageView.isHidden = true
}
thumbnailImageView.image = thumbnail
typeResultLabel.text = decoderResult.barcodeTypeName
resultValueLabel.text = decoderResult.textualData
resultFromScanning = decoderResult.textualData
let extras: [String] = decoderResult.extra.map { "\($0): \($1)" }
extrasResultLabel.text = extras.isEmpty
? "No extra data"
: extras.joined(separator: "\n")
}
// MARK: - Actions
@objc private func didTapScanButton() {
introLabel.isHidden = true
resultImageView.isHidden = true
startScanning()
}
@objc private func didTapViewAllResult() {
guard let resultFromScanning else { return }
let alert = UIAlertController(
title: "Full result",
message: resultFromScanning,
preferredStyle: .alert
)
let continueAction = UIAlertAction(title: "Continue", style: .default)
alert.addAction(continueAction)
present(alert, animated: true)
}
private func updateScanButtonAppearance() {
guard var config = scanButton.configuration else { return }
if scanButton.isScanning {
config.baseBackgroundColor = .red
} else {
config.baseBackgroundColor = .black
}
scanButton.configuration = config
}
}
// MARK: - ScanButton
class ScanButton: UIButton {
var isScanning: Bool {
get { isSelected }
set { isSelected = newValue }
}
}
// MARK: - BarkoderResultDelegate
extension ViewController: BarkoderResultDelegate {
func scanningFinished(_ decoderResults: [DecoderResult], thumbnails: [UIImage]?, image: UIImage?) {
if let decoderResult = decoderResults.first {
let thumbnail = thumbnails?.first
showResult(decoderResult, thumbnail: thumbnail, image: image)
}
scanButton.isScanning = false
updateScanButtonAppearance()
}
func startScanning() {
let isScanning = scanButton.isScanning
if !isScanning {
try? barkoderView.startScanning(self)
} else {
barkoderView.stopScanning()
}
scanButton.isScanning.toggle()
updateScanButtonAppearance()
}
}
To try this example you can get our SDK directly from our github repository.
However, as mentioned, the SDK will work without a license but the results will be filled with "UNLINCESED". To get full results one would need a license key, which can be obtained from our Developer Portal.