Julian Steenbakker
Committed by GitHub

Merge branch 'master' into feature/zoom

@@ -22,10 +22,10 @@ Features: @@ -22,10 +22,10 @@ Features:
22 * Added a new `placeholderBuilder` function to the `MobileScanner` widget to customize the preview placeholder. 22 * Added a new `placeholderBuilder` function to the `MobileScanner` widget to customize the preview placeholder.
23 * Added `autoStart` parameter to MobileScannerController(). If set to false, controller won't start automatically. 23 * Added `autoStart` parameter to MobileScannerController(). If set to false, controller won't start automatically.
24 * Added `hasTorch` function on MobileScannerController(). After starting the controller, you can check if the device has a torch. 24 * Added `hasTorch` function on MobileScannerController(). After starting the controller, you can check if the device has a torch.
  25 +* [iOS] Support `torchEnabled` parameter from MobileScannerController() on iOS
25 * [Web] Added ability to use custom barcode scanning js libraries 26 * [Web] Added ability to use custom barcode scanning js libraries
26 by extending `WebBarcodeReaderBase` class and changing `barCodeReader` property in `MobileScannerWebPlugin` 27 by extending `WebBarcodeReaderBase` class and changing `barCodeReader` property in `MobileScannerWebPlugin`
27 28
28 -  
29 Fixes: 29 Fixes:
30 * Fixes the missing gradle setup for the Android project, which prevented gradle sync from working. 30 * Fixes the missing gradle setup for the Android project, which prevented gradle sync from working.
31 * Fixes `MobileScannerController.stop()` throwing when already stopped. 31 * Fixes `MobileScannerController.stop()` throwing when already stopped.
@@ -35,6 +35,7 @@ Fixes: @@ -35,6 +35,7 @@ Fixes:
35 * Fixes the `MobileScanner` preview depending on all attributes of `MediaQueryData`. 35 * Fixes the `MobileScanner` preview depending on all attributes of `MediaQueryData`.
36 Now it only depends on its layout constraints. 36 Now it only depends on its layout constraints.
37 * Fixed a potential crash when the scanner is restarted due to the app being resumed. 37 * Fixed a potential crash when the scanner is restarted due to the app being resumed.
  38 +* [iOS] Fix crash when changing torch state
38 39
39 ## 3.0.0-beta.2 40 ## 3.0.0-beta.2
40 Breaking changes: 41 Breaking changes:
@@ -12,6 +12,7 @@ import MLKitVision @@ -12,6 +12,7 @@ import MLKitVision
12 import MLKitBarcodeScanning 12 import MLKitBarcodeScanning
13 13
14 typealias MobileScannerCallback = ((Array<Barcode>?, Error?, UIImage) -> ()) 14 typealias MobileScannerCallback = ((Array<Barcode>?, Error?, UIImage) -> ())
  15 +typealias TorchModeChangeCallback = ((Int?) -> ())
15 16
16 public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, FlutterTexture { 17 public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, FlutterTexture {
17 /// Capture session of the camera 18 /// Capture session of the camera
@@ -32,6 +33,9 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega @@ -32,6 +33,9 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
32 /// When results are found, this callback will be called 33 /// When results are found, this callback will be called
33 let mobileScannerCallback: MobileScannerCallback 34 let mobileScannerCallback: MobileScannerCallback
34 35
  36 + /// When torch mode is changes, this callback will be called
  37 + let torchModeChangeCallback: TorchModeChangeCallback
  38 +
35 /// If provided, the Flutter registry will be used to send the output of the CaptureOutput to a Flutter texture. 39 /// If provided, the Flutter registry will be used to send the output of the CaptureOutput to a Flutter texture.
36 private let registry: FlutterTextureRegistry? 40 private let registry: FlutterTextureRegistry?
37 41
@@ -43,9 +47,10 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega @@ -43,9 +47,10 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
43 47
44 var detectionSpeed: DetectionSpeed = DetectionSpeed.noDuplicates 48 var detectionSpeed: DetectionSpeed = DetectionSpeed.noDuplicates
45 49
46 - init(registry: FlutterTextureRegistry?, mobileScannerCallback: @escaping MobileScannerCallback) { 50 + init(registry: FlutterTextureRegistry?, mobileScannerCallback: @escaping MobileScannerCallback, torchModeChangeCallback: @escaping TorchModeChangeCallback) {
47 self.registry = registry 51 self.registry = registry
48 self.mobileScannerCallback = mobileScannerCallback 52 self.mobileScannerCallback = mobileScannerCallback
  53 + self.torchModeChangeCallback = torchModeChangeCallback
49 super.init() 54 super.init()
50 } 55 }
51 56
@@ -127,17 +132,6 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega @@ -127,17 +132,6 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
127 throw MobileScannerError.noCamera 132 throw MobileScannerError.noCamera
128 } 133 }
129 134
130 - // Enable the torch if parameter is set and torch is available  
131 - if (device.hasTorch && device.isTorchAvailable) {  
132 - do {  
133 - try device.lockForConfiguration()  
134 - device.torchMode = torch  
135 - device.unlockForConfiguration()  
136 - } catch {  
137 - throw MobileScannerError.torchError(error)  
138 - }  
139 - }  
140 -  
141 device.addObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode), options: .new, context: nil) 135 device.addObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode), options: .new, context: nil)
142 captureSession.beginConfiguration() 136 captureSession.beginConfiguration()
143 137
@@ -169,6 +163,13 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega @@ -169,6 +163,13 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
169 } 163 }
170 captureSession.commitConfiguration() 164 captureSession.commitConfiguration()
171 captureSession.startRunning() 165 captureSession.startRunning()
  166 + // Enable the torch if parameter is set and torch is available
  167 + // torch should be set after 'startRunning' is called
  168 + do {
  169 + try toggleTorch(torch)
  170 + } catch {
  171 + print("Failed to set initial torch state.")
  172 + }
172 let dimensions = CMVideoFormatDescriptionGetDimensions(device.activeFormat.formatDescription) 173 let dimensions = CMVideoFormatDescriptionGetDimensions(device.activeFormat.formatDescription)
173 174
174 return MobileScannerStartParameters(width: Double(dimensions.height), height: Double(dimensions.width), hasTorch: device.hasTorch, textureId: textureId) 175 return MobileScannerStartParameters(width: Double(dimensions.height), height: Double(dimensions.width), hasTorch: device.hasTorch, textureId: textureId)
@@ -198,6 +199,7 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega @@ -198,6 +199,7 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
198 if (device == nil) { 199 if (device == nil) {
199 throw MobileScannerError.torchWhenStopped 200 throw MobileScannerError.torchWhenStopped
200 } 201 }
  202 + if (device.hasTorch && device.isTorchAvailable) {
201 do { 203 do {
202 try device.lockForConfiguration() 204 try device.lockForConfiguration()
203 device.torchMode = torch 205 device.torchMode = torch
@@ -206,6 +208,19 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega @@ -206,6 +208,19 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
206 throw MobileScannerError.torchError(error) 208 throw MobileScannerError.torchError(error)
207 } 209 }
208 } 210 }
  211 + }
  212 +
  213 + // Observer for torch state
  214 + public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
  215 + switch keyPath {
  216 + case "torchMode":
  217 + // off = 0; on = 1; auto = 2;
  218 + let state = change?[.newKey] as? Int
  219 + torchModeChangeCallback(state)
  220 + default:
  221 + break
  222 + }
  223 + }
209 224
210 /// Set the zoom factor of the camera 225 /// Set the zoom factor of the camera
211 func setScale(_ scale: CGFloat) throws { 226 func setScale(_ scale: CGFloat) throws {
@@ -55,6 +55,8 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin { @@ -55,6 +55,8 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin {
55 } else if (error != nil){ 55 } else if (error != nil){
56 barcodeHandler.publishEvent(["name": "error", "data": error!.localizedDescription]) 56 barcodeHandler.publishEvent(["name": "error", "data": error!.localizedDescription])
57 } 57 }
  58 + }, torchModeChangeCallback: { torchState in
  59 + barcodeHandler.publishEvent(["name": "torchState", "data": torchState])
58 }) 60 })
59 self.barcodeHandler = barcodeHandler 61 self.barcodeHandler = barcodeHandler
60 super.init() 62 super.init()
@@ -230,16 +232,4 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin { @@ -230,16 +232,4 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin {
230 }) 232 })
231 result(nil) 233 result(nil)
232 } 234 }
233 -  
234 - /// Observer for torch state  
235 - public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {  
236 - switch keyPath {  
237 - case "torchMode":  
238 - // off = 0; on = 1; auto = 2;  
239 - let state = change?[.newKey] as? Int  
240 - barcodeHandler.publishEvent(["name": "torchState", "data": state])  
241 - default:  
242 - break  
243 - }  
244 - }  
245 } 235 }