-
Notifications
You must be signed in to change notification settings - Fork 506
Description
Describe the bug
When using the barcode scanner plugin on iOS with windowed: true, the JavaScript promise returned by scan() never resolves — even though the native side successfully detects the barcode and sends the IPC response.
With windowed: false, the same code works perfectly.
Reproduction
import { scan, Format } from '@tauri-apps/plugin-barcode-scanner';
// This never resolves on iOS:
const result = await scan({ windowed: true, formats: [Format.QRCode] });
console.log(result); // Never reachedEvidence
- The IPC response IS visible in Safari's network inspector — the native side returns
{"content": "D56UPN", "format": "QR_CODE"}correctly - But the JavaScript
await scan()never continues — no code afterawaitexecutes windowed: falseworks correctly with identical JavaScript codecancel()works correctly (the reject path is unaffected)
Analysis
Looking at BarcodeScannerPlugin.swift, the metadataOutput delegate calls:
invoke?.resolve(jsObject)
destroy()destroy() runs synchronously right after resolve() on the same main queue and does:
dismantleCamera() // stops AVCaptureSession (can block main thread)
invoke = nil
if windowed {
webView.isOpaque = true // restores webview
webView.backgroundColor = backgroundColor
webView.scrollView.backgroundColor = backgroundColor
}In non-windowed mode, the if windowed block is skipped and resolve() works fine. In windowed mode, the webview property restoration (isOpaque, backgroundColor) appears to interfere with the pending IPC callback delivery before it reaches the JavaScript layer.
Potential fix
Reorder the operations in metadataOutput so that resolve() is called after all cleanup and webview restoration, not before:
self.isScanning = false
dismantleCamera()
if windowed {
let backgroundColor = previousBackgroundColor ?? UIColor.white
webView.isOpaque = true
webView.backgroundColor = backgroundColor
webView.scrollView.backgroundColor = backgroundColor
}
invoke?.resolve(jsObject)
invoke = nilThis way the webview is fully restored to its normal (opaque) state before the IPC response is sent — matching the state where resolve() is known to work (non-windowed mode).
I've tested this fix locally and it resolves the issue. Happy to submit a PR if this approach looks correct.
Expected behavior
scan({ windowed: true }) should resolve with the scanned barcode content, same as windowed: false.
Platform and versions
- iOS 18.7 (iPhone)
- Tauri v2
@tauri-apps/plugin-barcode-scannerv2.4.4tauri-plugin-barcode-scannerfromv2branch
Stack trace
No crash — the promise simply never settles.