Apache Cordova (formerly PhoneGap) is a mobile application development framework that enables developers to build mobile apps using CSS, JavaScript, and HTML. Different from Xamarin that converting C# code to native apps, Cordova composes apps with hybrid code – all UI layouts are rendered with web technologies via web views and native device APIs are invoked via plugins. In this article, I will demonstrate how to use Cordova plugin to build iOS app with third-party iOS framework.
Cordova Project
A Cordova project includes:
- Plugin Code
- Platform Code
- Configuration
- HTML, CSS, JS and assets
Cordova Plugin with Third Party iOS Framework
Let’s create a Cordova plugin with Dynamsoft iOS barcode SDK. Since there is an existing Cordova plugin BarcodeScanner, I can make some changes based on the source code:
git clone https://github.com/phonegap/phonegap-plugin-barcodescanner.git
Download and install Dynamsoft iOS Barcode SDK.
Copy the DynamsoftBarcodeReader.framework to src/ios/.
Edit plugin.xml:
<!-- ios --> <platform name="ios"> <!-- Cordova >= 2.8 --> <config-file target="config.xml" parent="/*"> <feature name="BarcodeScanner"> <param name="ios-package" value="CDVBarcodeScanner" /> </feature> </config-file> <resource-file src="src/ios/scannerOverlay.xib" /> <resource-file src="src/ios/CDVBarcodeScanner.bundle" /> <source-file src="src/ios/CDVBarcodeScanner.mm" compiler-flags="-fno-objc-arc" /> <framework src="libiconv.dylib" /> <framework src="AVFoundation.framework" /> <framework src="AssetsLibrary.framework" /> <framework src="CoreVideo.framework" /> <framework src="QuartzCore.framework" /> <framework src="CoreGraphics.framework" /> <framework src="CoreImage.framework" /> <framework src="AudioToolbox.framework" /> <framework src="src/ios/DynamsoftBarcodeReader.framework" custom="true"/> </platform>
I replaced ZXing APIs with Dynamsoft Barcode Reader APIs.
Open CDVBarcodeScanner.mm and find:
- (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection
This is where we receive the video frame and detect barcode:
- (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection { if (!self.capturing) return; #if USE_SHUTTER if (!self.viewController.shutterPressed) return; self.viewController.shutterPressed = NO; UIView* flashView = [[UIView alloc] initWithFrame:self.viewController.view.frame]; [flashView setBackgroundColor:[UIColor whiteColor]]; [self.viewController.view.window addSubview:flashView]; [UIView animateWithDuration:.4f animations:^{ [flashView setAlpha:0.f]; } completion:^(BOOL finished){ [flashView removeFromSuperview]; } ]; // [self dumpImage: [[self getImageFromSample:sampleBuffer] autorelease]]; #endif // Dynamsoft Barcode Reader SDK @autoreleasepool { void *imageData = NULL; uint8_t *copyToAddress; CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); OSType pixelFormat = CVPixelBufferGetPixelFormatType(imageBuffer); if (!(pixelFormat == '420v' || pixelFormat == '420f')) { return; } CVPixelBufferLockBaseAddress(imageBuffer, 0); int numPlanes = (int)CVPixelBufferGetPlaneCount(imageBuffer); int bufferSize = (int)CVPixelBufferGetDataSize(imageBuffer); int imgWidth = (int)CVPixelBufferGetWidthOfPlane(imageBuffer, 0); int imgHeight = (int)CVPixelBufferGetHeightOfPlane(imageBuffer, 0); if(numPlanes < 1) { return; } uint8_t *baseAddress = (uint8_t *) CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0); size_t bytesToCopy = CVPixelBufferGetHeightOfPlane(imageBuffer, 0) * CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0); imageData = malloc(bytesToCopy); copyToAddress = (uint8_t *) imageData; memcpy(copyToAddress, baseAddress, bytesToCopy); CVPixelBufferUnlockBaseAddress(imageBuffer, 0); NSData *buffer = [NSData dataWithBytesNoCopy:imageData length:bufferSize freeWhenDone:YES]; // read frame using Dynamsoft Barcode Reader in async manner ReadResult *result = [self.barcodeReader readSingle:buffer width:imgWidth height:imgHeight barcodeFormat: self.barcodeFormat]; if (result.barcodes != nil) { Barcode *barcode = (Barcode *)result.barcodes[0]; [self barcodeScanSucceeded:barcode.displayValue format:barcode.formatString]; } } }
The preview data format needs to be initialized with NV21:
[output setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];
Define and initialize Dynamsoft Barcode Reader:
#import <DynamsoftBarcodeReader/DynamsoftBarcodeReader.h> #import <DynamsoftBarcodeReader/Barcode.h> @property (nonatomic, retain) BarcodeReader* barcodeReader; @property (nonatomic) long barcodeFormat; @synthesize barcodeReader = _barcodeReader; @synthesize barcodeFormat = _barcodeFormat; - (id)initWithPlugin:(CDVBarcodeScanner*)plugin callback:(NSString*)callback parentViewController:(UIViewController*)parentViewController alterateOverlayXib:(NSString *)alternateXib { self = [super init]; if (!self) return self; self.plugin = plugin; self.callback = callback; self.parentViewController = parentViewController; self.alternateXib = alternateXib; self.is1D = YES; self.is2D = YES; self.capturing = NO; self.results = [NSMutableArray new]; CFURLRef soundFileURLRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("CDVBarcodeScanner.bundle/beep"), CFSTR ("caf"), NULL); AudioServicesCreateSystemSoundID(soundFileURLRef, &_soundFileObject); self.barcodeReader = [[BarcodeReader alloc] initWithLicense:@"license"]; self.barcodeFormat = Barcode.OneD | Barcode.PDF417 | Barcode.QR_CODE; return self; }
Building iOS Barcode Scanner with Cordova Plugin
Initialize a new project:
cordova create barcode com.dynamsoft.barcode Barcode
Add iOS platform:
cd barcode cordova platform add ios --save
Install the plugin made above:
cordova plugin add <local-path>/<plugin-name>
Import the project from platforms/ios to Xcode.
Create a button in index.html:
<div class="app"> <div id="deviceready"> <button id="scan">scan barcode</button> </div> </div>
Trigger barcode scanning event in index.js:
onDeviceReady: function() { document.getElementById("scan").onclick = function() { cordova.plugins.barcodeScanner.scan( function (result) { alert("We got a barcode\n" + "Result: " + result.text + "\n" + "Format: " + result.format + "\n" + "Cancelled: " + result.cancelled); }, function (error) { alert("Scanning failed: " + error); }, { "preferFrontCamera" : false, // iOS and Android "showFlipCameraButton" : true, // iOS and Android } ); } app.receivedEvent('deviceready'); },
Build and run the iOS project:
Source Code
https://github.com/dynamsoft-dbr/phonegap-plugin-dbr
The post How to Make Cordova Plugin with Custom iOS framework appeared first on Code Pool.