Navaron Bracke
Committed by GitHub

Merge pull request #826 from navaronbracke/fix_platform_messages_threading

fix: Fix platform messages threading
@@ -15,6 +15,7 @@ Bugs fixed: @@ -15,6 +15,7 @@ Bugs fixed:
15 * Fixed the default values for the `format` and `type` arguments of the Barcode constructor. 15 * Fixed the default values for the `format` and `type` arguments of the Barcode constructor.
16 These now use `BarcodeFormat.unknown` and `BarcodeType.unknown`, rather than `BarcodeFormat.ean13` and `BarcodeType.text`. 16 These now use `BarcodeFormat.unknown` and `BarcodeType.unknown`, rather than `BarcodeFormat.ean13` and `BarcodeType.text`.
17 (thanks @navaronbracke !) 17 (thanks @navaronbracke !)
  18 +* Fixed messages not being sent on the main thread for Android, iOS and MacOS. (thanks @navaronbracke !)
18 19
19 ## 3.5.0 20 ## 3.5.0
20 New Features: 21 New Features:
@@ -2,6 +2,8 @@ package dev.steenbakker.mobile_scanner @@ -2,6 +2,8 @@ package dev.steenbakker.mobile_scanner
2 2
3 import android.app.Activity 3 import android.app.Activity
4 import android.net.Uri 4 import android.net.Uri
  5 +import android.os.Handler
  6 +import android.os.Looper
5 import android.util.Size 7 import android.util.Size
6 import androidx.camera.core.CameraSelector 8 import androidx.camera.core.CameraSelector
7 import androidx.camera.core.ExperimentalGetImage 9 import androidx.camera.core.ExperimentalGetImage
@@ -30,12 +32,13 @@ class MobileScannerHandler( @@ -30,12 +32,13 @@ class MobileScannerHandler(
30 "name" to "barcode", 32 "name" to "barcode",
31 "data" to barcodes 33 "data" to barcodes
32 )) 34 ))
33 - analyzerResult?.success(true)  
34 - } else {  
35 - analyzerResult?.success(false)  
36 } 35 }
  36 +
  37 + Handler(Looper.getMainLooper()).post {
  38 + analyzerResult?.success(barcodes != null)
37 analyzerResult = null 39 analyzerResult = null
38 } 40 }
  41 + }
39 42
40 private var analyzerResult: MethodChannel.Result? = null 43 private var analyzerResult: MethodChannel.Result? = null
41 44
@@ -92,7 +95,6 @@ class MobileScannerHandler( @@ -92,7 +95,6 @@ class MobileScannerHandler(
92 if(listener != null) { 95 if(listener != null) {
93 activityPluginBinding.removeRequestPermissionsResultListener(listener) 96 activityPluginBinding.removeRequestPermissionsResultListener(listener)
94 } 97 }
95 -  
96 } 98 }
97 99
98 @ExperimentalGetImage 100 @ExperimentalGetImage
@@ -173,11 +175,13 @@ class MobileScannerHandler( @@ -173,11 +175,13 @@ class MobileScannerHandler(
173 torchStateCallback, 175 torchStateCallback,
174 zoomScaleStateCallback, 176 zoomScaleStateCallback,
175 mobileScannerStartedCallback = { 177 mobileScannerStartedCallback = {
  178 + Handler(Looper.getMainLooper()).post {
176 result.success(mapOf( 179 result.success(mapOf(
177 "textureId" to it.id, 180 "textureId" to it.id,
178 "size" to mapOf("width" to it.width, "height" to it.height), 181 "size" to mapOf("width" to it.width, "height" to it.height),
179 "torchable" to it.hasFlashUnit 182 "torchable" to it.hasFlashUnit
180 )) 183 ))
  184 + }
181 }, 185 },
182 timeout.toLong(), 186 timeout.toLong(),
183 cameraResolution, 187 cameraResolution,
@@ -9,9 +9,6 @@ import Flutter @@ -9,9 +9,6 @@ import Flutter
9 import Foundation 9 import Foundation
10 10
11 public class BarcodeHandler: NSObject, FlutterStreamHandler { 11 public class BarcodeHandler: NSObject, FlutterStreamHandler {
12 -  
13 - var event: [String: Any?] = [:]  
14 -  
15 private var eventSink: FlutterEventSink? 12 private var eventSink: FlutterEventSink?
16 private let eventChannel: FlutterEventChannel 13 private let eventChannel: FlutterEventChannel
17 14
@@ -23,8 +20,9 @@ public class BarcodeHandler: NSObject, FlutterStreamHandler { @@ -23,8 +20,9 @@ public class BarcodeHandler: NSObject, FlutterStreamHandler {
23 } 20 }
24 21
25 func publishEvent(_ event: [String: Any?]) { 22 func publishEvent(_ event: [String: Any?]) {
26 - self.event = event  
27 - eventSink?(event) 23 + DispatchQueue.main.async {
  24 + self.eventSink?(event)
  25 + }
28 } 26 }
29 27
30 public func onListen(withArguments arguments: Any?, 28 public func onListen(withArguments arguments: Any?,
@@ -232,7 +232,6 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega @@ -232,7 +232,6 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
232 device.activeFormat.formatDescription) 232 device.activeFormat.formatDescription)
233 let hasTorch = device.hasTorch 233 let hasTorch = device.hasTorch
234 234
235 - DispatchQueue.main.async {  
236 completion( 235 completion(
237 MobileScannerStartParameters( 236 MobileScannerStartParameters(
238 width: Double(dimensions.height), 237 width: Double(dimensions.height),
@@ -241,16 +240,13 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega @@ -241,16 +240,13 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
241 textureId: self.textureId ?? 0 240 textureId: self.textureId ?? 0
242 ) 241 )
243 ) 242 )
244 - }  
245 243
246 return 244 return
247 } 245 }
248 246
249 - DispatchQueue.main.async {  
250 completion(MobileScannerStartParameters()) 247 completion(MobileScannerStartParameters())
251 } 248 }
252 } 249 }
253 - }  
254 250
255 /// Stop scanning for barcodes 251 /// Stop scanning for barcodes
256 func stop() throws { 252 func stop() throws {
@@ -121,7 +121,12 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin { @@ -121,7 +121,12 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin {
121 121
122 do { 122 do {
123 try mobileScanner.start(barcodeScannerOptions: barcodeOptions, returnImage: returnImage, cameraPosition: position, torch: torch ? .on : .off, detectionSpeed: detectionSpeed) { parameters in 123 try mobileScanner.start(barcodeScannerOptions: barcodeOptions, returnImage: returnImage, cameraPosition: position, torch: torch ? .on : .off, detectionSpeed: detectionSpeed) { parameters in
124 - result(["textureId": parameters.textureId, "size": ["width": parameters.width, "height": parameters.height], "torchable": parameters.hasTorch]) 124 + DispatchQueue.main.async {
  125 + result([
  126 + "textureId": parameters.textureId,
  127 + "size": ["width": parameters.width, "height": parameters.height],
  128 + "torchable": parameters.hasTorch])
  129 + }
125 } 130 }
126 } catch MobileScannerError.alreadyStarted { 131 } catch MobileScannerError.alreadyStarted {
127 result(FlutterError(code: "MobileScanner", 132 result(FlutterError(code: "MobileScanner",
@@ -158,12 +163,12 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin { @@ -158,12 +163,12 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin {
158 private func toggleTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { 163 private func toggleTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
159 do { 164 do {
160 try mobileScanner.toggleTorch(call.arguments as? Int == 1 ? .on : .off) 165 try mobileScanner.toggleTorch(call.arguments as? Int == 1 ? .on : .off)
  166 + result(nil)
161 } catch { 167 } catch {
162 result(FlutterError(code: "MobileScanner", 168 result(FlutterError(code: "MobileScanner",
163 message: "Called toggleTorch() while stopped!", 169 message: "Called toggleTorch() while stopped!",
164 details: nil)) 170 details: nil))
165 } 171 }
166 - result(nil)  
167 } 172 }
168 173
169 /// Toggles the zoomScale 174 /// Toggles the zoomScale
@@ -177,6 +182,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin { @@ -177,6 +182,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin {
177 } 182 }
178 do { 183 do {
179 try mobileScanner.setScale(scale!) 184 try mobileScanner.setScale(scale!)
  185 + result(nil)
180 } catch MobileScannerError.zoomWhenStopped { 186 } catch MobileScannerError.zoomWhenStopped {
181 result(FlutterError(code: "MobileScanner", 187 result(FlutterError(code: "MobileScanner",
182 message: "Called setScale() while stopped!", 188 message: "Called setScale() while stopped!",
@@ -190,13 +196,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin { @@ -190,13 +196,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin {
190 message: "Error while zooming.", 196 message: "Error while zooming.",
191 details: nil)) 197 details: nil))
192 } 198 }
193 - result(nil)  
194 } 199 }
195 200
196 /// Reset the zoomScale 201 /// Reset the zoomScale
197 private func resetScale(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { 202 private func resetScale(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
198 do { 203 do {
199 try mobileScanner.resetScale() 204 try mobileScanner.resetScale()
  205 + result(nil)
200 } catch MobileScannerError.zoomWhenStopped { 206 } catch MobileScannerError.zoomWhenStopped {
201 result(FlutterError(code: "MobileScanner", 207 result(FlutterError(code: "MobileScanner",
202 message: "Called resetScale() while stopped!", 208 message: "Called resetScale() while stopped!",
@@ -210,7 +216,6 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin { @@ -210,7 +216,6 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin {
210 message: "Error while zooming.", 216 message: "Error while zooming.",
211 details: nil)) 217 details: nil))
212 } 218 }
213 - result(nil)  
214 } 219 }
215 220
216 /// Toggles the torch 221 /// Toggles the torch
@@ -247,16 +252,28 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin { @@ -247,16 +252,28 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin {
247 } 252 }
248 253
249 mobileScanner.analyzeImage(image: uiImage!, position: AVCaptureDevice.Position.back, callback: { [self] barcodes, error in 254 mobileScanner.analyzeImage(image: uiImage!, position: AVCaptureDevice.Position.back, callback: { [self] barcodes, error in
250 - if error == nil && barcodes != nil && !barcodes!.isEmpty { 255 + if error != nil {
  256 + barcodeHandler.publishEvent(["name": "error", "message": error?.localizedDescription])
  257 +
  258 + DispatchQueue.main.async {
  259 + result(false)
  260 + }
  261 +
  262 + return
  263 + }
  264 +
  265 + if (barcodes == nil || barcodes!.isEmpty) {
  266 + DispatchQueue.main.async {
  267 + result(false)
  268 + }
  269 + } else {
251 let barcodesMap: [Any?] = barcodes!.compactMap { barcode in barcode.data } 270 let barcodesMap: [Any?] = barcodes!.compactMap { barcode in barcode.data }
252 let event: [String: Any?] = ["name": "barcode", "data": barcodesMap] 271 let event: [String: Any?] = ["name": "barcode", "data": barcodesMap]
253 barcodeHandler.publishEvent(event) 272 barcodeHandler.publishEvent(event)
  273 +
  274 + DispatchQueue.main.async {
254 result(true) 275 result(true)
255 - } else {  
256 - if error != nil {  
257 - barcodeHandler.publishEvent(["name": "error", "message": error?.localizedDescription])  
258 } 276 }
259 - result(false)  
260 } 277 }
261 }) 278 })
262 } 279 }
1 import AVFoundation 1 import AVFoundation
2 -import Flutter  
3 import Foundation 2 import Foundation
4 import MLKitBarcodeScanning 3 import MLKitBarcodeScanning
5 4
6 -extension Error {  
7 - func throwNative(_ result: FlutterResult) {  
8 - let error = FlutterError(code: localizedDescription, message: nil, details: nil)  
9 - result(error)  
10 - }  
11 -}  
12 -  
13 extension CVBuffer { 5 extension CVBuffer {
14 var image: UIImage { 6 var image: UIImage {
15 let ciImage = CIImage(cvPixelBuffer: self) 7 let ciImage = CIImage(cvPixelBuffer: self)
@@ -144,8 +144,10 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, @@ -144,8 +144,10 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
144 } 144 }
145 } 145 }
146 } else { 146 } else {
  147 + DispatchQueue.main.async {
147 self?.sink?(FlutterError(code: "MobileScanner", message: error?.localizedDescription, details: nil)) 148 self?.sink?(FlutterError(code: "MobileScanner", message: error?.localizedDescription, details: nil))
148 } 149 }
  150 + }
149 }) 151 })
150 if(self?.symbologies.isEmpty == false){ 152 if(self?.symbologies.isEmpty == false){
151 // add the symbologies the user wishes to support 153 // add the symbologies the user wishes to support
@@ -153,11 +155,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, @@ -153,11 +155,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
153 } 155 }
154 try imageRequestHandler.perform([barcodeRequest]) 156 try imageRequestHandler.perform([barcodeRequest])
155 } catch let e { 157 } catch let e {
  158 + DispatchQueue.main.async {
156 self?.sink?(FlutterError(code: "MobileScanner", message: e.localizedDescription, details: nil)) 159 self?.sink?(FlutterError(code: "MobileScanner", message: e.localizedDescription, details: nil))
157 } 160 }
158 } 161 }
159 } 162 }
160 } 163 }
  164 + }
161 165
162 func checkPermission(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { 166 func checkPermission(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
163 if #available(macOS 10.14, *) { 167 if #available(macOS 10.14, *) {
@@ -276,6 +280,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, @@ -276,6 +280,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
276 device.unlockForConfiguration() 280 device.unlockForConfiguration()
277 } catch { 281 } catch {
278 result(FlutterError(code: error.localizedDescription, message: nil, details: nil)) 282 result(FlutterError(code: error.localizedDescription, message: nil, details: nil))
  283 + return
279 } 284 }
280 } 285 }
281 286
@@ -288,6 +293,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, @@ -288,6 +293,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
288 captureSession.addInput(input) 293 captureSession.addInput(input)
289 } catch { 294 } catch {
290 result(FlutterError(code: error.localizedDescription, message: nil, details: nil)) 295 result(FlutterError(code: error.localizedDescription, message: nil, details: nil))
  296 + return
291 } 297 }
292 captureSession.sessionPreset = AVCaptureSession.Preset.photo 298 captureSession.sessionPreset = AVCaptureSession.Preset.photo
293 // Add video output. 299 // Add video output.