# QR and barcode scanner - JavaScript bridge API

> Google’s scanner screen from one promise, AppMint.scanCode() - no camera permission, and the parsed URL, Wi-Fi, phone or contact for common QR codes.

- **Applies to:** AppMint
- **Source:** extracted from the app runtime and its per-method example files; this page is generated from them.
- **HTML:** https://freewebtoapk.com/docs/api/scanner

### `AppMint.scanCode`

```js
AppMint.scanCode(options)
```

**Example**

Opens Google's QR code and barcode scanner screen and gives you what was scanned. One call - no camera permission, no `<video>`, no UI of your own.

**Returns:** a Promise that always resolves: `{ok: true, value, displayValue, format, type, …}` or `{ok: false, code, message}`. **Needs:** nothing to switch on. The phone needs Google Play services.

**Any code:**

```js
async function scan() {
  if (!(window.AppMint && AppMint.scanCode)) { alert('Open this page in the app to scan'); return; }
  var r = await AppMint.scanCode();
  if (!r.ok) {
    if (r.code === 'cancelled') return;                          // the user closed the scanner
    if (r.code === 'unavailable') alert('The scanner is not available on this phone');
    else if (r.code === 'busy') alert('A scan is already open');
    else alert('Scan failed: ' + r.message);                     // 'failed'
    return;
  }
  console.log(r.value, r.format, r.type);   // "TICKET-4821", "qr_code", "text"
}
```

**Only some formats**, and a "type it in" option for damaged labels:

```js
var r = await AppMint.scanCode({
  formats: ['ean_13', 'ean_8', 'upc_a', 'upc_e'],   // shop barcodes
  manualInput: true,                                // lets the user type the code
  autoZoom: true                                    // default true
});
if (r.ok) lookUpProduct(r.value);
```

**Ready-made parts** - only the part that matches `r.type` is present:

```js
var r = await AppMint.scanCode({ formats: ['qr_code'] });
if (r.ok) {
  if (r.type === 'url')     openLink(r.url.url);                      // url: { url, title }
  if (r.type === 'wifi')    showWifi(r.wifi.ssid, r.wifi.password, r.wifi.encryption); // 'wpa'|'wep'|'open'
  if (r.type === 'phone')   callNumber(r.phone);                      // a string
  if (r.type === 'email')   writeMail(r.email.address, r.email.subject, r.email.body);
  if (r.type === 'sms')     writeSms(r.sms.phoneNumber, r.sms.message);
  if (r.type === 'geo')     showMap(r.geo.lat, r.geo.lng);
  if (r.type === 'contact') addContact(r.contact.name, r.contact.organization, r.contact.phones, r.contact.emails);
}
```

**Notes:** Format names: `qr_code`, `aztec`, `codabar`, `code_39`, `code_93`, `code_128`, `data_matrix`, `ean_8`, `ean_13`, `itf`, `pdf417`, `upc_a`, `upc_e` (unknown names are ignored; none = all formats). `type` is one of `url`, `wifi`, `text`, `phone`, `email`, `sms`, `geo`, `contact`, `calendar`, `isbn`, `product`, `driver_license`, `unknown`. Error codes: `cancelled` (closed, including with Back), `unavailable` (no Play services, or the scanner could not be downloaded), `busy` (a scan is already open), `failed`. The first scan on a phone can take a few seconds while Play services downloads the scanner. AI-built apps use `scanCode()` from `@/lib/appmintNative`, which also scans on the web.

### `__ocrAvailable`

```js
window.WebToApk.__ocrAvailable(): Boolean
```

TextDetector / recognizeText(): Google Play services is here (the OCR module's home).

**Example**

Internal transport behind `TextDetector`: whether Google Play services (where the recognizer comes from) is on this phone. Pages use the standard API; never call this directly - the `__` methods may change without notice.

**Returns:** `true` or `false`. When `false`, `TextDetector` is not installed at all. **Needs:** nothing.

**Use the public API:**

```js
if ('TextDetector' in window) scanButton.hidden = false;
```

**Notes:** Implemented in the app shell (TextRecognitionBridge.kt).

### `__ocrRecognize`

```js
window.WebToApk.__ocrRecognize(requestId: String, base64: String)
```

Recognises the text in [base64] (PNG/JPEG); the answer arrives as `appmint:ocr {requestId, blocks|error}`.

**Example**

Internal transport behind `TextDetector.detect()`: recognises the text in a PNG/JPEG. Pages use the standard API; never call this directly - the `__` methods may change without notice.

**Returns:** nothing; the answer arrives as the `appmint:ocr` event `{requestId, blocks:[{text, box, corners, lines}]}` or `{requestId, error}` (`unavailable`, `bad-image`, `failed: …`). **Needs:** nothing.

**Use the public API:**

```js
const lines = await new TextDetector().detect(document.getElementById('receipt'));
console.log(lines.map((l) => l.rawValue));
```

**Notes:** Implemented in the app shell (TextRecognitionBridge.kt).

### `scanCode`

```js
window.WebToApk.scanCode(optionsJson: String, callbackId: String)
```

Opens Google's code scanner; [optionsJson] `{formats?, autoZoom?, manualInput?}`. Resolves the AppMint.scanCode promise [callbackId].

**Example**

Internal plumbing behind `AppMint.scanCode()` - pages use that Promise helper, which opens Google's QR/barcode scanner and resolves with the result.

**Returns:** nothing directly; the result resolves the `AppMint.scanCode()` promise. **Needs:** nothing to switch on (no camera permission). The phone needs Google Play services.

The public API:

```js
async function scanTicket() {
  if (!(window.AppMint && AppMint.scanCode)) { alert('Open this page in the app to scan'); return; }
  var r = await AppMint.scanCode({ formats: ['qr_code'] });
  if (r.ok) checkTicket(r.value);                  // r.format, r.type, r.displayValue…
  else if (r.code !== 'cancelled') alert('Scan failed (' + r.code + ')');
}
```

**Notes:** The raw method takes `optionsJson` (`{formats?, autoZoom?, manualInput?}` as a JSON string) and a `callbackId`; the answer is delivered to the helper's internal reply table, so a page calling it directly gets no answer. Only one scan runs at a time - a second call answers `code: 'busy'`. See `AppMint.scanCode` for every result field and error code.

