Skip to content

Commit

Permalink
feat(ios): support older iPods (without a back camera)
Browse files Browse the repository at this point in the history
also implements the 'canChangeCamera' status property
  • Loading branch information
bitjson committed May 10, 2016
1 parent 30fc953 commit f211f90
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 28 deletions.
19 changes: 10 additions & 9 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
# cordova-plugin-qrscanner
A fast, energy efficient, highly-configurable QR code scanner for Cordova apps. Currently iOS and browser only.

QRScanner's live video preview is rendered behind the Cordova app's native webview, and the native webview's background is made transparent. This allows for an interface to be built inside the webview to control the scanner.
QRScanner's live video preview is rendered behind the Cordova app's native webview, and the native webview's background is made transparent. This allows for an HTML/CSS/JS interface to be built inside the webview to control the scanner.

## Get Started

```bash
cordova plugin add cordova-plugin-qrscanner
```

The iOS component of the plugin is written in Swift 2. To enable it, add the following hook to the iOS platform in your Cordova app's `config.xml`:
The iOS component of the plugin is written in Swift 2. To enable it, be sure you're running the lastest version of Xcode, then add the following hook to the iOS platform in your Cordova app's `config.xml`:

```xml
<platform name="ios">
Expand All @@ -25,14 +25,8 @@ This script requires the `xcode` npm module:
```bash
npm install --save xcode
```
Once installed, remove and re-add the ios platform to trigger the hook:

```bash
cordova platform remove ios
cordova platform add ios
```

The `QRScanner` plugin is now available in your app:
Swift will now be enabled during your build, and the `QRScanner` plugin will be available in your app:

```js
// Make sure the user will give your app camera access when prompted, then:
Expand Down Expand Up @@ -305,6 +299,13 @@ Code | Name | Description

This plugin attempts to properly abstract all the necessary functions of a well-designed, native QR code scanner. Here are some platform specific details it may be helpful to know.

## iOS

This plugin is always tested with the latest version of Xcode. Please be sure you have updated Xcode before installing.

If you run into issues in your own project, try the test project in this repo to confirm your environment is set up properly: `npm run gen-tests && npm run test:ios`.


## Browser

While the browser implementation matches the native mobile implementations very closely, the platform itself does not. Notably:
Expand Down
59 changes: 40 additions & 19 deletions src/ios/QRScanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ class QRScanner : CDVPlugin, AVCaptureMetadataOutputObjectsDelegate {
frontCamera = device
}
}
// older iPods have no back camera
if(backCamera == nil){
currentCamera = 1
}
let input: AVCaptureDeviceInput
input = try self.createCaptureDeviceInput()
captureSession = AVCaptureSession()
Expand Down Expand Up @@ -167,7 +171,8 @@ class QRScanner : CDVPlugin, AVCaptureMetadataOutputObjectsDelegate {
useMode = AVCaptureTorchMode.Off
}
do {
if(backCamera!.hasTorch == false || backCamera!.torchAvailable == false || backCamera!.isTorchModeSupported(useMode) == false){
// torch is only available for back camera
if(backCamera == nil || backCamera!.hasTorch == false || backCamera!.torchAvailable == false || backCamera!.isTorchModeSupported(useMode) == false){
throw LightError.torchUnavailable
}
try backCamera!.lockForConfiguration()
Expand Down Expand Up @@ -267,26 +272,36 @@ class QRScanner : CDVPlugin, AVCaptureMetadataOutputObjectsDelegate {
func useCamera(command: CDVInvokedUrlCommand){
let index = command.arguments[0] as! Int
if(currentCamera != index){
// switch camera
currentCamera = index
if(self.prepScanner(command)){
do {
captureSession!.beginConfiguration()
let currentInput = captureSession?.inputs[0] as! AVCaptureDeviceInput
captureSession!.removeInput(currentInput)
let input = try self.createCaptureDeviceInput()
captureSession!.addInput(input)
captureSession!.commitConfiguration()
self.getStatus(command)
} catch CaptureError.backCameraUnavailable {
// camera change only available if both backCamera and frontCamera exist
if(backCamera != nil && frontCamera != nil){
// switch camera
currentCamera = index
if(self.prepScanner(command)){
do {
captureSession!.beginConfiguration()
let currentInput = captureSession?.inputs[0] as! AVCaptureDeviceInput
captureSession!.removeInput(currentInput)
let input = try self.createCaptureDeviceInput()
captureSession!.addInput(input)
captureSession!.commitConfiguration()
self.getStatus(command)
} catch CaptureError.backCameraUnavailable {
self.sendErrorCode(command, error: QRScannerError.BACK_CAMERA_UNAVAILABLE)
} catch CaptureError.frontCameraUnavailable {
self.sendErrorCode(command, error: QRScannerError.FRONT_CAMERA_UNAVAILABLE)
} catch CaptureError.couldNotCaptureInput(let error){
print(error.localizedDescription)
self.sendErrorCode(command, error: QRScannerError.CAMERA_UNAVAILABLE)
} catch {
self.sendErrorCode(command, error: QRScannerError.UNEXPECTED_ERROR)
}

}
} else {
if(backCamera == nil){
self.sendErrorCode(command, error: QRScannerError.BACK_CAMERA_UNAVAILABLE)
} catch CaptureError.frontCameraUnavailable {
} else {
self.sendErrorCode(command, error: QRScannerError.FRONT_CAMERA_UNAVAILABLE)
} catch CaptureError.couldNotCaptureInput(let error){
print(error.localizedDescription)
self.sendErrorCode(command, error: QRScannerError.CAMERA_UNAVAILABLE)
} catch {
self.sendErrorCode(command, error: QRScannerError.UNEXPECTED_ERROR)
}
}
} else {
Expand Down Expand Up @@ -376,6 +391,11 @@ class QRScanner : CDVPlugin, AVCaptureMetadataOutputObjectsDelegate {
canEnableLight = true
}

var canChangeCamera = false;
if(backCamera != nil && frontCamera != nil){
canChangeCamera = true
}

let status = [
"authorized": boolToNumberString(authorized),
"denied": boolToNumberString(denied),
Expand All @@ -387,6 +407,7 @@ class QRScanner : CDVPlugin, AVCaptureMetadataOutputObjectsDelegate {
"lightEnabled": boolToNumberString(lightEnabled),
"canOpenSettings": boolToNumberString(canOpenSettings),
"canEnableLight": boolToNumberString(canEnableLight),
"canChangeCamera": boolToNumberString(canChangeCamera),
"currentCamera": String(currentCamera)
]

Expand Down
1 change: 1 addition & 0 deletions tests/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ exports.defineAutoTests = function() {
expect(typeof status.lightEnabled).toBe('boolean');
expect(typeof status.canOpenSettings).toBe('boolean');
expect(typeof status.canEnableLight).toBe('boolean');
expect(typeof status.canChangeCamera).toBe('boolean');
expect(typeof status.currentCamera).toBe('number');
done();
});
Expand Down
1 change: 1 addition & 0 deletions www/QRScanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ function convertStatus(statusDictionary) {
lightEnabled: stringToBool(statusDictionary.lightEnabled),
canOpenSettings: stringToBool(statusDictionary.canOpenSettings),
canEnableLight: stringToBool(statusDictionary.canEnableLight),
canChangeCamera: stringToBool(statusDictionary.canChangeCamera),
currentCamera: parseInt(statusDictionary.currentCamera)
};
}
Expand Down

0 comments on commit f211f90

Please sign in to comment.