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,11 +32,12 @@ class MobileScannerHandler( @@ -30,11 +32,12 @@ 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 }
37 - analyzerResult = null 36 +
  37 + Handler(Looper.getMainLooper()).post {
  38 + analyzerResult?.success(barcodes != null)
  39 + analyzerResult = null
  40 + }
38 } 41 }
39 42
40 private var analyzerResult: MethodChannel.Result? = null 43 private var analyzerResult: MethodChannel.Result? = null
@@ -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 = {
176 - result.success(mapOf(  
177 - "textureId" to it.id,  
178 - "size" to mapOf("width" to it.width, "height" to it.height),  
179 - "torchable" to it.hasFlashUnit  
180 - )) 178 + Handler(Looper.getMainLooper()).post {
  179 + result.success(mapOf(
  180 + "textureId" to it.id,
  181 + "size" to mapOf("width" to it.width, "height" to it.height),
  182 + "torchable" to it.hasFlashUnit
  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,23 +232,19 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega @@ -232,23 +232,19 @@ 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(  
237 - MobileScannerStartParameters(  
238 - width: Double(dimensions.height),  
239 - height: Double(dimensions.width),  
240 - hasTorch: hasTorch,  
241 - textureId: self.textureId ?? 0  
242 - ) 235 + completion(
  236 + MobileScannerStartParameters(
  237 + width: Double(dimensions.height),
  238 + height: Double(dimensions.width),
  239 + hasTorch: hasTorch,
  240 + textureId: self.textureId ?? 0
243 ) 241 )
244 - } 242 + )
245 243
246 return 244 return
247 } 245 }
248 246
249 - DispatchQueue.main.async {  
250 - completion(MobileScannerStartParameters())  
251 - } 247 + completion(MobileScannerStartParameters())
252 } 248 }
253 } 249 }
254 250
@@ -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)
254 - result(true)  
255 - } else {  
256 - if error != nil {  
257 - barcodeHandler.publishEvent(["name": "error", "message": error?.localizedDescription]) 273 +
  274 + DispatchQueue.main.async {
  275 + result(true)
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,7 +144,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, @@ -144,7 +144,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
144 } 144 }
145 } 145 }
146 } else { 146 } else {
147 - self?.sink?(FlutterError(code: "MobileScanner", message: error?.localizedDescription, details: nil)) 147 + DispatchQueue.main.async {
  148 + self?.sink?(FlutterError(code: "MobileScanner", message: error?.localizedDescription, details: nil))
  149 + }
148 } 150 }
149 }) 151 })
150 if(self?.symbologies.isEmpty == false){ 152 if(self?.symbologies.isEmpty == false){
@@ -153,7 +155,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, @@ -153,7 +155,9 @@ 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 {
156 - self?.sink?(FlutterError(code: "MobileScanner", message: e.localizedDescription, details: nil)) 158 + DispatchQueue.main.async {
  159 + self?.sink?(FlutterError(code: "MobileScanner", message: e.localizedDescription, details: nil))
  160 + }
157 } 161 }
158 } 162 }
159 } 163 }
@@ -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.