npm package: @opuu/capacitor-hardware-transport
Description: Universal Capacitor plugin for raw data hardware transport over USB, Bluetooth (BLE), and Network (TCP) interfaces.
Author: Obaydur Rahman
Latest version: 0.0.3

# @opuu/capacitor-hardware-transport

Universal Capacitor plugin for raw data hardware transport over USB, Bluetooth (BLE), and Network (TCP) interfaces.

This plugin provides a unified API to discover, connect, and communicate with hardware peripherals across Android, iOS, and the Web. It is designed for "raw" transport, meaning you can send any byte sequence (EscPos, ZPL, custom protocols) to the connected hardware.

## Features

- **Multi-Interface Support**: Connect via USB, Bluetooth Low Energy (BLE), or TCP/IP (Network).
- **Device Discovery**: Unified scanning API for all supported interfaces.
- **Raw Data Transport**: Send `Uint8Array`, `number[]`, or Base64 strings directly.
- **Internal Queuing**: Optional internal command queuing for thread-safe operations.
- **Cross-Platform**: Consistent API across Android, iOS, and Web.

## Platform Support

| Interface           | Android | iOS |          Web           |
| :------------------ | :-----: | :-: | :--------------------: |
| **USB**             |   ✅    | ❌  |      ✅ (WebUSB)       |
| **Bluetooth (BLE)** |   ✅    | ✅  |   ✅ (Web Bluetooth)   |
| **Network (TCP)**   |   ✅    | ✅  | ✅ (WebSocket Proxy\*) |

_\*Web support for Network (TCP) requires a WebSocket-to-TCP proxy running on the target address (Default Port: 9100)._

## Installation

```bash
npm install @opuu/capacitor-hardware-transport
npx cap sync
```

## Configuration

### Android

Add the following permissions to your `AndroidManifest.xml`:

```xml
<!-- Bluetooth Permissions -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- USB Permissions -->
<uses-feature android:name="android.hardware.usb.host" />

<!-- Network Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
```

### iOS

Add the following keys to your `Info.plist`:

```xml
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs Bluetooth access to connect to hardware peripherals.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app needs Bluetooth access to connect to hardware peripherals.</string>
```

## Usage

```typescript
import { HardwareTransport } from '@opuu/capacitor-hardware-transport';

// 1. Request Permissions
await HardwareTransport.requestPermissions();

// 2. Discover Devices (e.g., Bluetooth)
const { devices } = await HardwareTransport.discoverDevices({
  type: 'BLUETOOTH',
});

const device = devices[0];

// 3. Connect
await HardwareTransport.connect({
  type: 'BLUETOOTH',
  address: device.address,
});

// 4. Write Raw Data (e.g., ESC/POS)
const data = new Uint8Array([0x1b, 0x40, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x0a]);
await HardwareTransport.write({ data });

// 5. Disconnect
await HardwareTransport.disconnect();
```

### Auto-Reconnect

You can automatically re-establish a connection to the last successfully connected hardware device (useful on app startup). On Android and iOS, this works natively. On Web, USB requires the device to be in the browser's previously granted list. 

> **Note on Web Bluetooth:** Auto-reconnecting to Web Bluetooth devices requires the experimental `navigator.bluetooth.getDevices()` API. In most browsers (including many versions of Chrome), this feature is completely unsupported or hidden behind flags (e.g. `chrome://flags/#enable-web-bluetooth-new-permissions-backend`). If unsupported, `autoReconnect()` will safely return `false` or throw, allowing you to gracefully prompt the user to select the device again.

```typescript
// On app startup:
try {
  const reconnected = await HardwareTransport.autoReconnect({ maxRetries: 3 });
  if (reconnected) {
    console.log("Reconnected to last device!");
  } else {
    console.log("No previous device found — need to scan.");
  }
} catch (err) {
  console.error("Auto-reconnect failed (device off/out of range):", err);
}

// To inspect the last connected device:
const lastDevice = await HardwareTransport.getLastDevice();
console.log(lastDevice); // { type: 'BLUETOOTH', address: '...', ... }

// To forget the last device (prevents autoReconnect):
await HardwareTransport.clearLastDevice();
```

## API

<docgen-index>

* [`checkPermissions()`](#checkpermissions)
* [`requestPermissions()`](#requestpermissions)
* [`discoverDevices(...)`](#discoverdevices)
* [`connect(...)`](#connect)
* [`disconnect()`](#disconnect)
* [`write(...)`](#write)
* [`getLastDevice()`](#getlastdevice)
* [`clearLastDevice()`](#clearlastdevice)
* [`autoReconnect(...)`](#autoreconnect)
* [Interfaces](#interfaces)
* [Type Aliases](#type-aliases)

</docgen-index>

<docgen-api>
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->

### checkPermissions()

```typescript
checkPermissions() => Promise<PermissionStatus>
```

Checks the status of specific hardware connection permissions natively.

**Returns:** <code>Promise&lt;<a href="#permissionstatus">PermissionStatus</a>&gt;</code>

**Since:** 0.0.1

--------------------


### requestPermissions()

```typescript
requestPermissions() => Promise<PermissionStatus>
```

Requests necessary hardware discovery/connection permissions from the user.
Prompts platform-specific system dialogs.

**Returns:** <code>Promise&lt;<a href="#permissionstatus">PermissionStatus</a>&gt;</code>

**Since:** 0.0.1

--------------------


### discoverDevices(...)

```typescript
discoverDevices(options: DiscoverOptions) => Promise<{ devices: DeviceInfo[]; }>
```

Triggers a hardware scan for the specified connection type.
Yields a list of devices available for connection.

| Param         | Type                                                        | Description                               |
| ------------- | ----------------------------------------------------------- | ----------------------------------------- |
| **`options`** | <code><a href="#discoveroptions">DiscoverOptions</a></code> | Strategy and filters for the device scan. |

**Returns:** <code>Promise&lt;{ devices: DeviceInfo[]; }&gt;</code>

**Since:** 0.0.1

--------------------


### connect(...)

```typescript
connect(options: ConnectOptions) => Promise<void>
```

Attempts to establish an Input/Output stream with the specified hardware peripheral.

| Param         | Type                                                      | Description                                       |
| ------------- | --------------------------------------------------------- | ------------------------------------------------- |
| **`options`** | <code><a href="#connectoptions">ConnectOptions</a></code> | Information identifying the device to connect to. |

**Since:** 0.0.1

--------------------


### disconnect()

```typescript
disconnect() => Promise<void>
```

Severs all active streams and closes hardware sockets.
Retains the "Last Device" record in memory for `autoReconnect()`.

**Since:** 0.0.1

--------------------


### write(...)

```typescript
write(options: WriteOptions) => Promise<void>
```

Enqueues a payload into the active hardware stream buffer.
The underlying native plugins expect a Base64 encoded string payload. If using `HardwareTransportClient`, bytes are encoded automatically.

| Param         | Type                                                  | Description                             |
| ------------- | ----------------------------------------------------- | --------------------------------------- |
| **`options`** | <code><a href="#writeoptions">WriteOptions</a></code> | Payload and transmission configuration. |

**Since:** 0.0.1

--------------------


### getLastDevice()

```typescript
getLastDevice() => Promise<ConnectOptions | null>
```

Returns the last successfully connected device options, or null if no device has been connected.
Useful for UI state restoration (e.g. displaying "Last Connected Printer").

**Returns:** <code>Promise&lt;<a href="#connectoptions">ConnectOptions</a> | null&gt;</code>

**Since:** 0.0.2

--------------------


### clearLastDevice()

```typescript
clearLastDevice() => Promise<void>
```

Removes the persisted last device, preventing future auto-reconnect calls from using it.
Call this explicitly when the user requests to "Forget Device" or disconnects intentionally.

**Since:** 0.0.2

--------------------


### autoReconnect(...)

```typescript
autoReconnect(options?: AutoReconnectOptions | undefined) => Promise<boolean>
```

Attempts to automatically reconnect to the last successfully connected device.
Uses localStorage persistence under the hood. Fails safely if no previous device exists.

| Param         | Type                                                                  | Description                    |
| ------------- | --------------------------------------------------------------------- | ------------------------------ |
| **`options`** | <code><a href="#autoreconnectoptions">AutoReconnectOptions</a></code> | Tuning for connection retries. |

**Returns:** <code>Promise&lt;boolean&gt;</code>

**Since:** 0.0.2

--------------------


### Interfaces


#### PermissionStatus

| Prop            | Type                                                        | Description                                    | Since |
| --------------- | ----------------------------------------------------------- | ---------------------------------------------- | ----- |
| **`bluetooth`** | <code><a href="#permissionstate">PermissionState</a></code> | Permission state for Bluetooth devices.        | 0.0.1 |
| **`usb`**       | <code><a href="#permissionstate">PermissionState</a></code> | Permission state for USB devices.              | 0.0.1 |
| **`network`**   | <code><a href="#permissionstate">PermissionState</a></code> | Permission state for Network traffic (TCP/IP). | 0.0.1 |


#### DeviceInfo

| Prop            | Type                | Description                                                                                                                                                                                                                                                    | Since |
| --------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
| **`name`**      | <code>string</code> | Human-readable name of the device.                                                                                                                                                                                                                             | 0.0.1 |
| **`address`**   | <code>string</code> | Connection address of the device. - IP Address (`192.168.1.100`) for Network connections - MAC address (`00:11:22:33:44:55`) for Bluetooth on Android/System - Unique ID (`id`) for Web Bluetooth / BLE on iOS - Serial Number or `vendorId:productId` for USB | 0.0.1 |
| **`vendorId`**  | <code>string</code> | USB Vendor ID (for USB connection types).                                                                                                                                                                                                                      | 0.0.1 |
| **`productId`** | <code>string</code> | USB Product ID (for USB connection types).                                                                                                                                                                                                                     | 0.0.1 |


#### DiscoverOptions

| Prop            | Type                                           | Description                                                                                | Since |
| --------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------ | ----- |
| **`type`**      | <code>'USB' \| 'BLUETOOTH' \| 'NETWORK'</code> | The type of peripheral hardware to scan for.                                               | 0.0.1 |
| **`services`**  | <code>string[]</code>                          | [Bluetooth] Optional array of Service UUIDs to filter discovered BLE peripherals natively. | 0.0.1 |
| **`vendorId`**  | <code>number</code>                            | [USB] Optional Vendor ID to filter discovered USB devices.                                 | 0.0.1 |
| **`productId`** | <code>number</code>                            | [USB] Optional Product ID to filter discovered USB devices.                                | 0.0.1 |


#### ConnectOptions

| Prop          | Type                                           | Description                                                                                                                                                      | Default           | Since |
| ------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | ----- |
| **`type`**    | <code>'USB' \| 'BLUETOOTH' \| 'NETWORK'</code> | The type of peripheral hardware to connect to.                                                                                                                   |                   | 0.0.1 |
| **`address`** | <code>string</code>                            | The connection address mapped to the queried hardware device. Obtain this address via `discoverDevices()`.                                                       |                   | 0.0.1 |
| **`port`**    | <code>number</code>                            | Override port for Network (TCP/WebSocket) connections.                                                                                                           | <code>9100</code> | 0.0.1 |
| **`timeout`** | <code>number</code>                            | Timeout in milliseconds for hardware connection attempts.                                                                                                        | <code>5000</code> | 0.0.1 |
| **`mtu`**     | <code>number</code>                            | Request specific MTU (Maximum Transmission Unit) size for Bluetooth LE connections. Android/iOS only. Use this if your peripheral expects larger payload chunks. |                   | 0.0.1 |


#### WriteOptions

| Prop          | Type                                                                    | Description                                                                                                                                                                                                             | Default           | Since |
| ------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | ----- |
| **`data`**    | <code>string \| number[] \| <a href="#uint8array">Uint8Array</a></code> | Raw byte payload to write. The wrapper client handles Base64 encoding natively for Capacitor. For sending ESC/POS or ZPL strings directly, convert them to <a href="#uint8array">Uint8Array</a> using an encoder first. |                   | 0.0.1 |
| **`timeout`** | <code>number</code>                                                     | Timeout in milliseconds for the write operation.                                                                                                                                                                        | <code>5000</code> | 0.0.1 |


#### Uint8Array

A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the
requested number of bytes could not be allocated an exception is raised.

| Prop                    | Type                                                        | Description                                                                  |
| ----------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------- |
| **`BYTES_PER_ELEMENT`** | <code>number</code>                                         | The size in bytes of each element in the array.                              |
| **`buffer`**            | <code><a href="#arraybufferlike">ArrayBufferLike</a></code> | The <a href="#arraybuffer">ArrayBuffer</a> instance referenced by the array. |
| **`byteLength`**        | <code>number</code>                                         | The length in bytes of the array.                                            |
| **`byteOffset`**        | <code>number</code>                                         | The offset in bytes of the array.                                            |
| **`length`**            | <code>number</code>                                         | The length of the array.                                                     |

| Method             | Signature                                                                                                                                                                      | Description                                                                                                                                                                                                                                 |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **copyWithin**     | (target: number, start: number, end?: number \| undefined) =&gt; this                                                                                                          | Returns the this object after copying a section of the array identified by start and end to the same array starting at position target                                                                                                      |
| **every**          | (predicate: (value: number, index: number, array: <a href="#uint8array">Uint8Array</a>) =&gt; unknown, thisArg?: any) =&gt; boolean                                            | Determines whether all the members of an array satisfy the specified test.                                                                                                                                                                  |
| **fill**           | (value: number, start?: number \| undefined, end?: number \| undefined) =&gt; this                                                                                             | Returns the this object after filling the section identified by start and end with value                                                                                                                                                    |
| **filter**         | (predicate: (value: number, index: number, array: <a href="#uint8array">Uint8Array</a>) =&gt; any, thisArg?: any) =&gt; <a href="#uint8array">Uint8Array</a>                   | Returns the elements of an array that meet the condition specified in a callback function.                                                                                                                                                  |
| **find**           | (predicate: (value: number, index: number, obj: <a href="#uint8array">Uint8Array</a>) =&gt; boolean, thisArg?: any) =&gt; number \| undefined                                  | Returns the value of the first element in the array where predicate is true, and undefined otherwise.                                                                                                                                       |
| **findIndex**      | (predicate: (value: number, index: number, obj: <a href="#uint8array">Uint8Array</a>) =&gt; boolean, thisArg?: any) =&gt; number                                               | Returns the index of the first element in the array where predicate is true, and -1 otherwise.                                                                                                                                              |
| **forEach**        | (callbackfn: (value: number, index: number, array: <a href="#uint8array">Uint8Array</a>) =&gt; void, thisArg?: any) =&gt; void                                                 | Performs the specified action for each element in an array.                                                                                                                                                                                 |
| **indexOf**        | (searchElement: number, fromIndex?: number \| undefined) =&gt; number                                                                                                          | Returns the index of the first occurrence of a value in an array.                                                                                                                                                                           |
| **join**           | (separator?: string \| undefined) =&gt; string                                                                                                                                 | Adds all the elements of an array separated by the specified separator string.                                                                                                                                                              |
| **lastIndexOf**    | (searchElement: number, fromIndex?: number \| undefined) =&gt; number                                                                                                          | Returns the index of the last occurrence of a value in an array.                                                                                                                                                                            |
| **map**            | (callbackfn: (value: number, index: number, array: <a href="#uint8array">Uint8Array</a>) =&gt; number, thisArg?: any) =&gt; <a href="#uint8array">Uint8Array</a>               | Calls a defined callback function on each element of an array, and returns an array that contains the results.                                                                                                                              |
| **reduce**         | (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: <a href="#uint8array">Uint8Array</a>) =&gt; number) =&gt; number                       | Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.                      |
| **reduce**         | (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: <a href="#uint8array">Uint8Array</a>) =&gt; number, initialValue: number) =&gt; number |                                                                                                                                                                                                                                             |
| **reduce**         | &lt;U&gt;(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: <a href="#uint8array">Uint8Array</a>) =&gt; U, initialValue: U) =&gt; U            | Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.                      |
| **reduceRight**    | (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: <a href="#uint8array">Uint8Array</a>) =&gt; number) =&gt; number                       | Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
| **reduceRight**    | (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: <a href="#uint8array">Uint8Array</a>) =&gt; number, initialValue: number) =&gt; number |                                                                                                                                                                                                                                             |
| **reduceRight**    | &lt;U&gt;(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: <a href="#uint8array">Uint8Array</a>) =&gt; U, initialValue: U) =&gt; U            | Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
| **reverse**        | () =&gt; <a href="#uint8array">Uint8Array</a>                                                                                                                                  | Reverses the elements in an Array.                                                                                                                                                                                                          |
| **set**            | (array: <a href="#arraylike">ArrayLike</a>&lt;number&gt;, offset?: number \| undefined) =&gt; void                                                                             | Sets a value or an array of values.                                                                                                                                                                                                         |
| **slice**          | (start?: number \| undefined, end?: number \| undefined) =&gt; <a href="#uint8array">Uint8Array</a>                                                                            | Returns a section of an array.                                                                                                                                                                                                              |
| **some**           | (predicate: (value: number, index: number, array: <a href="#uint8array">Uint8Array</a>) =&gt; unknown, thisArg?: any) =&gt; boolean                                            | Determines whether the specified callback function returns true for any element of an array.                                                                                                                                                |
| **sort**           | (compareFn?: ((a: number, b: number) =&gt; number) \| undefined) =&gt; this                                                                                                    | Sorts an array.                                                                                                                                                                                                                             |
| **subarray**       | (begin?: number \| undefined, end?: number \| undefined) =&gt; <a href="#uint8array">Uint8Array</a>                                                                            | Gets a new <a href="#uint8array">Uint8Array</a> view of the <a href="#arraybuffer">ArrayBuffer</a> store for this array, referencing the elements at begin, inclusive, up to end, exclusive.                                                |
| **toLocaleString** | () =&gt; string                                                                                                                                                                | Converts a number to a string by using the current locale.                                                                                                                                                                                  |
| **toString**       | () =&gt; string                                                                                                                                                                | Returns a string representation of an array.                                                                                                                                                                                                |
| **valueOf**        | () =&gt; <a href="#uint8array">Uint8Array</a>                                                                                                                                  | Returns the primitive value of the specified object.                                                                                                                                                                                        |


#### ArrayLike

| Prop         | Type                |
| ------------ | ------------------- |
| **`length`** | <code>number</code> |


#### ArrayBufferTypes

Allowed <a href="#arraybuffer">ArrayBuffer</a> types for the buffer of an ArrayBufferView and related Typed Arrays.

| Prop              | Type                                                |
| ----------------- | --------------------------------------------------- |
| **`ArrayBuffer`** | <code><a href="#arraybuffer">ArrayBuffer</a></code> |


#### ArrayBuffer

Represents a raw buffer of binary data, which is used to store data for the
different typed arrays. ArrayBuffers cannot be read from or written to directly,
but can be passed to a typed array or DataView Object to interpret the raw
buffer as needed.

| Prop             | Type                | Description                                                                     |
| ---------------- | ------------------- | ------------------------------------------------------------------------------- |
| **`byteLength`** | <code>number</code> | Read-only. The length of the <a href="#arraybuffer">ArrayBuffer</a> (in bytes). |

| Method    | Signature                                                                               | Description                                                     |
| --------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| **slice** | (begin: number, end?: number \| undefined) =&gt; <a href="#arraybuffer">ArrayBuffer</a> | Returns a section of an <a href="#arraybuffer">ArrayBuffer</a>. |


#### AutoReconnectOptions

| Prop             | Type                | Description                                             | Default           | Since |
| ---------------- | ------------------- | ------------------------------------------------------- | ----------------- | ----- |
| **`timeout`**    | <code>number</code> | Timeout in milliseconds for the reconnection attempt.   | <code>5000</code> | 0.0.2 |
| **`maxRetries`** | <code>number</code> | Maximum number of reconnection attempts before failing. | <code>1</code>    | 0.0.2 |


### Type Aliases


#### PermissionState

<code>'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'</code>


#### ArrayBufferLike

<code>ArrayBufferTypes[keyof ArrayBufferTypes]</code>

</docgen-api>