tauri-plugin-barcode-scanner-continuous 0.1.0

Fork of tauri-plugin-barcode-scanner with on-device fixes enabling a stable continuous scan loop on iOS and Android.
# tauri-plugin-barcode-scanner-continuous

Fork of [`@tauri-apps/plugin-barcode-scanner`](https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins/barcode-scanner) with on-device fixes that enable a **stable continuous scan loop** on iOS and Android.

The API surface is the same as the upstream plugin (`scan`, `cancel`, `checkPermissions`, `requestPermissions`, `openAppSettings`), so it is a near drop-in replacement when the consumer wants to keep a scanner overlay open across many detections — a common pattern in Point-of-Sale checkout flows.

| Platform | Supported |
| --- | --- |
| iOS ||
| Android ||
| macOS / Windows / Linux ||

## Why this fork

`tauri-plugin-barcode-scanner 2.4.4` (the latest release on crates.io at the time of this fork) had two unresolved on-device bugs that prevented a reliable continuous scanning UX:

1. **iOS app crash when `cancel()` is called while a scan is live.** Upstream's `cancel()` runs on the IPC thread, so tearing the capture session down from JS races `destroy()` on the main thread. See [tauri-apps/plugins-workspace#3081]https://github.com/tauri-apps/plugins-workspace/issues/3081.
2. **iOS taps stop working after a scan.** `dismantleCamera()` removed the preview layer but left the `UIView` in the superview hierarchy, intercepting touches. See [PR #3107]https://github.com/tauri-apps/plugins-workspace/pull/3107 / [PR #2440]https://github.com/tauri-apps/plugins-workspace/pull/2440.

Both are fixed in unreleased upstream work, but as of `2.4.4` they were not in any published crate.

This fork carries those patches plus a small additive feature so it can live alongside the upstream plugin in a project without conflicting with its ACL / Tauri plugin namespace.

## What is different from upstream

### iOS (Swift)

- `cancel()` wraps its body in `DispatchQueue.main.async { … }`. Fixes the crash when the close button is pressed while `scan()` is still running.
- `dismantleCamera()` now calls `self.cameraView.removeFromSuperview()`. Fixes the unresponsive-after-scan bug.
- `scan()` accepts an optional `overlayInsetBottom` argument (points). When running in non-windowed mode on iOS, this leaves a transparent strip at the bottom of the camera preview so apps can keep their own UI (e.g. a cart bottom-sheet) visible.

### Renamed identifiers (to avoid collision with upstream)

| Thing | Upstream | This fork |
| --- | --- | --- |
| Crate name | `tauri-plugin-barcode-scanner` | `tauri-plugin-barcode-scanner-continuous` |
| Rust lib | `tauri_plugin_barcode_scanner` | `tauri_plugin_barcode_scanner_continuous` |
| Tauri plugin name | `barcode-scanner` | `barcode-scanner-continuous` |
| ACL prefix | `barcode-scanner:*` | `barcode-scanner-continuous:*` |
| iOS `@_cdecl` init | `init_plugin_barcode_scanner` | `init_plugin_barcode_scanner_continuous` |
| Android Java package | `app.tauri.barcodescanner` | `app.tauri.barcodescannercontinuous` |

Installing both this fork and the upstream plugin in the same app is supported.

## Install

### Rust (`src-tauri/Cargo.toml`)

```toml
[target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies]
tauri-plugin-barcode-scanner-continuous = "0.1"
```

### JavaScript

```bash
npm install @riczescaran/tauri-plugin-barcode-scanner-continuous
```

### Register the plugin (`src-tauri/src/lib.rs`)

```rust
#[cfg(any(target_os = "android", target_os = "ios"))]
let builder = builder.plugin(tauri_plugin_barcode_scanner_continuous::init());
```

### Allow the commands (`src-tauri/capabilities/mobile.json`)

```json
{
  "permissions": ["barcode-scanner-continuous:default"]
}
```

## Usage

```ts
import {
  scan,
  cancel,
  Format,
} from '@riczescaran/tauri-plugin-barcode-scanner-continuous'

// Continuous loop — the caller drives the loop; the plugin resolves one
// scan() call per detection and internally tears down the capture session
// in a way that is safe to re-arm on the next iteration.
async function runScanLoop() {
  while (shouldKeepScanning()) {
    try {
      const { content } = await scan({
        windowed: true,
        formats: [Format.EAN13, Format.EAN8, Format.QRCode],
      })
      addToCart(content)
    } catch (e) {
      // cancel() rejects the in-flight scan() with "cancelled" — this is
      // the normal exit from the loop.
      if (String(e).match(/cancel/i)) break
      throw e
    }
  }
}

// Close the overlay:
await cancel()
```

## License

Apache-2.0 OR MIT. Derivative work of the upstream `@tauri-apps/plugin-barcode-scanner`, Copyright © 2019-Present — The Tauri Programme within The Commons Conservancy.

See `LICENSE_APACHE-2.0` and `LICENSE_MIT`.