Build a React Native Vision Camera Frame Processor Plugin to Scan Barcodes for iOS

In the previous article, we’ve created a React Native Vision Camera frame processor plugin for Dynamsoft Barcode Reader (DBR). Let’s continue to create the frame processor plugin for iOS.

PS: If you don’t need to use Vision Camera, you can use the Dynamsoft Capture Vision package instead to scan barcodes.

Other React Native Vision Camera Frame Processor Plugins

Getting started with Dynamsoft Barcode Reader

DOWNLOAD THE SDK WITH A 30-DAY LICENSE
REQUEST A 30-DAY LICENSE

Building the React Native Vision Camera Frame Processor Plugin of Barcode Reader for iOS

Let’s do this in steps.

Implement the iOS Part of the Plugin

  1. Add Dynamsoft Barcode Reader to vision-camera-dynamsoft-barcode-reader.podspec

    s.libraries = 'c++'
    s.dependency 'DynamsoftBarcodeReader', '= 9.0.0'
    
  2. Go to ios, remove VisionCameraDynamsoftBarcodeReader.swift and VisionCameraDynamsoftBarcodeReader.m

  3. Create a new file named VisionCameraDBRPlugin.swift with the following content:

     import Foundation
    
     @objc(VisionCameraDBRPlugin)
     public class VisionCameraDBRPlugin: NSObject, FrameProcessorPluginBase {
         @objc
         public static func callback(_ frame: Frame!, withArgs args: [Any]!) -> Any! {
             // code goes here
             return []
         }
     }
    
  4. Add the following content to VisionCameraDynamsoftBarcodeReader-Bridging-Header.h

     #import <VisionCamera/FrameProcessorPlugin.h>
     #import <VisionCamera/Frame.h>
    
  5. Create a new Objective-C file with the same name as the Swift file with the following content:

     #import <Foundation/Foundation.h>
     #import <VisionCamera/FrameProcessorPlugin.h>
    
     @interface VISION_EXPORT_SWIFT_FRAME_PROCESSOR(decode, VisionCameraDBRPlugin)
    
     @end
    
  6. Create a new BarcodeReaderInitializer.swift to initialize Dynamsoft Barcode Reader:

     public class BarcodeReaderInitializer: NSObject, DBRLicenseVerificationListener {
            
         func configurationDBR(license:String) -> DynamsoftBarcodeReader {
             var dbr:DynamsoftBarcodeReader
             DynamsoftBarcodeReader.initLicense(license, verificationDelegate: self)
             dbr = DynamsoftBarcodeReader.init()
             return dbr
         }
            
         public func dbrLicenseVerificationCallback(_ isSuccess: Bool, error: Error?) {
             let err = error as NSError?
             if(err != nil){
                 print("Server DBR license verify failed")
             }
         }
     }
    
  7. Use the Initializer to create an instance of Dynamsoft Barcode Reader if the plugin is called:

     private static var barcodeReader:DynamsoftBarcodeReader! = nil
     public static func callback(_ frame: Frame!, withArgs args: [Any]!) -> Any! {
         let config = getConfig(withArgs: args)
         if barcodeReader == nil {
             initDBR(config: config)
         }
         return []
     }
    
     static func initDBR(config: [String:String]!) {
         var license = "";
         license = config?["license"] ?? "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ=="
         let initializer = BarcodeReaderInitializer();
         barcodeReader = initializer.configurationDBR(license: license)
     }
        
     static func getConfig(withArgs args: [Any]!) -> [String:String]!{
         if args.count>0 {
             let config = args[0] as? [String: String]
             return config
         }
         return nil
     }
    
  8. Decode the image using Dynamsoft Barcode Reader and return the result

     private static let context = CIContext(options: nil)
     @objc
     public static func callback(_ frame: Frame!, withArgs args: [Any]!) -> Any! {
         let config = getConfig(withArgs: args)
         if barcodeReader == nil {
             initDBR(config: config)
         }
         guard let imageBuffer = CMSampleBufferGetImageBuffer(frame.buffer) else {
           print("Failed to get CVPixelBuffer!")
           return nil
         }
         let ciImage = CIImage(cvPixelBuffer: imageBuffer)
    
         guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else {
           print("Failed to create CGImage!")
           return nil
         }
         var returned_results: [Any] = []
         let image = UIImage(cgImage: cgImage)
         // code goes here
         let results = try? barcodeReader.decodeImage(image)
         let count = results?.count ?? 0
         if count > 0 {
             for index in 0..<count {
                 let tr = results![index]
                 returned_results.append(wrapResult(result: tr))
             }
             print("Found barcodes")
         }
         return returned_results
     }
    
     static func wrapResult(result: iTextResult) -> Any {
         var map: [String: Any] = [:]
            
         map["barcodeText"] = result.barcodeText
         map["barcodeFormat"] = result.barcodeFormatString
            
         let points = result.localizationResult?.resultPoints as! [CGPoint]
         map["x1"] = points[0].x
         map["x2"] = points[1].x
         map["x3"] = points[2].x
         map["x4"] = points[3].x
         map["y1"] = points[0].y
         map["y2"] = points[1].y
         map["y3"] = points[2].y
         map["y4"] = points[3].y
            
         return map
     }
    

The iOS implementation of the React Native Vision Camera plugin is now completed.

We can do the following to test the example project.

  1. Add camera permission to the example project by adding the following to Info.plist.

    <key>NSCameraUsageDescription</key>
    <string>For barcode scanning</string>
    
  2. Run the following to install pods.

     cd example/ios
     pod install
    
  3. Run the project for iOS.

    npx react-native run-ios
    

Source Code

You can check out the source code for more details.

https://github.com/tony-xlh/vision-camera-dynamsoft-barcode-reader