Skip to content

opuu/capacitor-hardware-transport

Repository files navigation

@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

npm install @opuu/capacitor-hardware-transport
npx cap sync

Configuration

Android

Add the following permissions to your AndroidManifest.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:

<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

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.

// 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

checkPermissions()

checkPermissions() => Promise<PermissionStatus>

Checks the status of specific hardware connection permissions natively.

Returns: Promise<PermissionStatus>

Since: 0.0.1


requestPermissions()

requestPermissions() => Promise<PermissionStatus>

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

Returns: Promise<PermissionStatus>

Since: 0.0.1


discoverDevices(...)

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 DiscoverOptions Strategy and filters for the device scan.

Returns: Promise<{ devices: DeviceInfo[]; }>

Since: 0.0.1


connect(...)

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

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

Param Type Description
options ConnectOptions Information identifying the device to connect to.

Since: 0.0.1


disconnect()

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(...)

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 WriteOptions Payload and transmission configuration.

Since: 0.0.1


getLastDevice()

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: Promise<ConnectOptions | null>

Since: 0.0.2


clearLastDevice()

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(...)

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 AutoReconnectOptions Tuning for connection retries.

Returns: Promise<boolean>

Since: 0.0.2


Interfaces

PermissionStatus

Prop Type Description Since
bluetooth PermissionState Permission state for Bluetooth devices. 0.0.1
usb PermissionState Permission state for USB devices. 0.0.1
network PermissionState Permission state for Network traffic (TCP/IP). 0.0.1

DeviceInfo

Prop Type Description Since
name string Human-readable name of the device. 0.0.1
address string 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 string USB Vendor ID (for USB connection types). 0.0.1
productId string USB Product ID (for USB connection types). 0.0.1

DiscoverOptions

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

ConnectOptions

Prop Type Description Default Since
type 'USB' | 'BLUETOOTH' | 'NETWORK' The type of peripheral hardware to connect to. 0.0.1
address string The connection address mapped to the queried hardware device. Obtain this address via discoverDevices(). 0.0.1
port number Override port for Network (TCP/WebSocket) connections. 9100 0.0.1
timeout number Timeout in milliseconds for hardware connection attempts. 5000 0.0.1
mtu number 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 string | number[] | Uint8Array 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 Uint8Array using an encoder first. 0.0.1
timeout number Timeout in milliseconds for the write operation. 5000 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 number The size in bytes of each element in the array.
buffer ArrayBufferLike The ArrayBuffer instance referenced by the array.
byteLength number The length in bytes of the array.
byteOffset number The offset in bytes of the array.
length number The length of the array.
Method Signature Description
copyWithin (target: number, start: number, end?: number | undefined) => 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: Uint8Array) => unknown, thisArg?: any) => boolean Determines whether all the members of an array satisfy the specified test.
fill (value: number, start?: number | undefined, end?: number | undefined) => this Returns the this object after filling the section identified by start and end with value
filter (predicate: (value: number, index: number, array: Uint8Array) => any, thisArg?: any) => Uint8Array Returns the elements of an array that meet the condition specified in a callback function.
find (predicate: (value: number, index: number, obj: Uint8Array) => boolean, thisArg?: any) => 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: Uint8Array) => boolean, thisArg?: any) => 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: Uint8Array) => void, thisArg?: any) => void Performs the specified action for each element in an array.
indexOf (searchElement: number, fromIndex?: number | undefined) => number Returns the index of the first occurrence of a value in an array.
join (separator?: string | undefined) => string Adds all the elements of an array separated by the specified separator string.
lastIndexOf (searchElement: number, fromIndex?: number | undefined) => number Returns the index of the last occurrence of a value in an array.
map (callbackfn: (value: number, index: number, array: Uint8Array) => number, thisArg?: any) => Uint8Array 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: Uint8Array) => number) => 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: Uint8Array) => number, initialValue: number) => number
reduce <U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, initialValue: U) => 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: Uint8Array) => number) => 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: Uint8Array) => number, initialValue: number) => number
reduceRight <U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, initialValue: U) => 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 () => Uint8Array Reverses the elements in an Array.
set (array: ArrayLike<number>, offset?: number | undefined) => void Sets a value or an array of values.
slice (start?: number | undefined, end?: number | undefined) => Uint8Array Returns a section of an array.
some (predicate: (value: number, index: number, array: Uint8Array) => unknown, thisArg?: any) => boolean Determines whether the specified callback function returns true for any element of an array.
sort (compareFn?: ((a: number, b: number) => number) | undefined) => this Sorts an array.
subarray (begin?: number | undefined, end?: number | undefined) => Uint8Array Gets a new Uint8Array view of the ArrayBuffer store for this array, referencing the elements at begin, inclusive, up to end, exclusive.
toLocaleString () => string Converts a number to a string by using the current locale.
toString () => string Returns a string representation of an array.
valueOf () => Uint8Array Returns the primitive value of the specified object.

ArrayLike

Prop Type
length number

ArrayBufferTypes

Allowed ArrayBuffer types for the buffer of an ArrayBufferView and related Typed Arrays.

Prop Type
ArrayBuffer ArrayBuffer

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 number Read-only. The length of the ArrayBuffer (in bytes).
Method Signature Description
slice (begin: number, end?: number | undefined) => ArrayBuffer Returns a section of an ArrayBuffer.

AutoReconnectOptions

Prop Type Description Default Since
timeout number Timeout in milliseconds for the reconnection attempt. 5000 0.0.2
maxRetries number Maximum number of reconnection attempts before failing. 1 0.0.2

Type Aliases

PermissionState

'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'

ArrayBufferLike

ArrayBufferTypes[keyof ArrayBufferTypes]

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors