@devioarts/capacitor-tcpclient
v0.2.1
Published
TCP Client for Capacitor working on Android, iOS and Electron
Maintainers
Readme
@devioarts/capacitor-tcpclient
TCP client plugin for Capacitor apps with native Android, iOS and Electron support.
Use it when your app needs to talk to a TCP device or service directly, for example printers, scanners, controllers, gateways or local network hardware.
Features
- Native TCP sockets on Android, iOS and Electron
- Multi-connection API with isolated listeners per connection
- Raw writes, continuous stream reads and request/response reads
- Byte payloads as
number[]orUint8Array - Optional
expectpattern matching for protocol replies - Web stub for browser development builds
Install
npm install @devioarts/capacitor-tcpclient
npx cap syncAndroid network permissions are merged automatically from the plugin manifest. See Getting started for manual Android fallback notes and the required iOS setup.
Quick Start
import { TCPClient } from '@devioarts/capacitor-tcpclient';
const conn = TCPClient.createConnection({
host: '192.168.1.100',
port: 9100,
timeout: 3000,
});
await conn.connect();
const reply = await conn.writeAndRead({
data: [0x1b, 0x40],
timeout: 1000,
maxBytes: 4096,
});
if (reply.error) {
console.error(reply.errorMessage);
} else {
console.log('Received bytes:', reply.data);
}
await conn.destroy();Capacitor App Example
import { TCPClient, type TCPConnection } from '@devioarts/capacitor-tcpclient';
let connection: TCPConnection | undefined;
export async function connectToDevice(host: string) {
connection = TCPClient.createConnection({ connectionId: 'main-device', host, port: 9100 });
await connection.addListener('tcpDisconnect', ({ reason, error }) => {
console.log('TCP disconnected:', reason, error ?? '');
});
return connection.connect();
}
export async function sendCommand(command: Uint8Array) {
if (!connection) throw new Error('TCP connection is not ready');
return connection.writeAndRead({
data: command,
expect: '0d0a',
timeout: 1500,
maxBytes: 8192,
});
}
export async function disconnectFromDevice() {
await connection?.destroy();
connection = undefined;
}Documentation
- Getting started: installation, Android/iOS setup and playground notes
- Usage guide: Capacitor examples, streaming, request/response and lifecycle patterns
- Electron integration: Capacitor Electron and manual Electron bridge setup
- Behavior and FAQ: timeouts, buffering, platform notes and troubleshooting
- API reference: generated TypeScript API reference in this README
Platform Support
| Platform | Status | Notes | | --- | --- | --- | | Android | Native TCP | Internet/network permissions are merged automatically | | iOS | Native TCP | Requires local network usage description for local devices | | Electron | Native TCP | Use Capacitor Electron or the manual bridge | | Web | Development stub | Keeps the same API shape, but does not open real TCP sockets |
Common Commands
npm run build
npm test
npm run verify:webAPI
The generated API below documents the root
@devioarts/capacitor-tcpclient entry point used by Capacitor apps. The manual
Electron bridge exposes the native methods directly over IPC, so it uses
connectionId on every call instead of createConnection().
createConnection(...)
createConnection(options?: TcpCreateConnectionOptions | undefined) => TCPConnectionCreate (or retrieve) a TCP connection instance.
- Without connectionId: always creates a new instance with a generated UUID.
- With connectionId: returns the existing instance if one was already created, otherwise creates a new one.
- host/port/timeout/noDelay/keepAlive supplied here become defaults for connect().
| Param | Type |
| ------------- | --------------------------------------------------------------------------------- |
| options | TcpCreateConnectionOptions |
Returns: TCPConnection
getPluginPlatform()
getPluginPlatform() => Promise<TcpGetPlatformResult>Returns the platform identifier for this plugin's native implementation ('ios' | 'android' | 'electron' | 'web').
Distinct from the Capacitor core Capacitor.getPlatform() — use this when
you need to know whether the TCP layer is backed by iOS, Android, Electron,
or the browser development stub.
Returns: Promise<TcpGetPlatformResult>
Interfaces
TCPConnection
A single TCP connection instance returned by TCPClient.createConnection(). Each instance has its own socket, event listeners, and lifecycle.
| Prop | Type |
| ------------------ | ------------------- |
| connectionId | string |
| Method | Signature | Description |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| connect | (options?: Partial<TcpConnectOptions> | undefined) => Promise<TcpConnectResult> | Open the socket. Options are merged with the defaults supplied in createConnection(). host must be present either in createConnection() or here. |
| disconnect | () => Promise<TcpDisconnectResult> | Close the socket. Idempotent. Resolves after native teardown completes. Emits tcpDisconnect(reason: manual). |
| isConnected | () => Promise<TcpIsConnectedResult> | |
| isReading | () => Promise<TcpIsReadingResult> | |
| write | (options: TcpWriteOptions) => Promise<TcpWriteResult> | |
| writeAndRead | (options: TcpWriteAndReadOptions) => Promise<TcpWriteAndReadResult> | |
| startRead | (options?: TcpStartReadOptions | undefined) => Promise<TcpStartStopResult> | |
| stopRead | () => Promise<TcpStartStopResult> | |
| setReadTimeout | (options: { readTimeout: number; }) => Promise<{ error: boolean; errorMessage?: string | null; }> | Configure stream read timeout. - Android: sets SO_TIMEOUT on the continuous reader socket (applies during startRead). - iOS: no-op (evented I/O, no blocking timeout). - Electron: sets the default timeout value used by writeAndRead when no explicit timeout is passed; if called before connect, the default is stored without creating a socket state entry. |
| addListener | (eventName: 'tcpData', listenerFunc: (event: TcpDataEvent) => void) => Promise<PluginListenerHandle> | Subscribe to stream data. Only events for this connectionId are delivered. |
| addListener | (eventName: 'tcpDisconnect', listenerFunc: (event: TcpDisconnectEvent) => void) => Promise<PluginListenerHandle> | Subscribe to disconnect notifications for this connection. |
| removeAllListeners | () => Promise<void> | Remove all listeners registered through this instance. |
| destroy | () => Promise<void> | Disconnect, remove all listeners, and release this instance from the registry even if listener cleanup fails. |
TcpConnectResult
| Prop | Type |
| ------------------ | --------------------------- |
| error | boolean |
| errorMessage | string | null |
| connected | boolean |
TcpConnectOptions
| Prop | Type | Description |
| --------------- | -------------------- | -------------------------------------------------------------------------------------- |
| host | string | Hostname or IP address. Required (either here or in createConnection). |
| port | number | TCP port, default 9100. Valid range 1..65535. |
| timeout | number | Connect timeout in milliseconds, default 3000. Includes DNS and socket connect budget. |
| noDelay | boolean | Enable TCP_NODELAY (Nagle off). Default true. |
| keepAlive | boolean | Enable SO_KEEPALIVE. Default true. |
TcpDisconnectResult
| Prop | Type |
| ------------------ | --------------------------- |
| error | boolean |
| errorMessage | string | null |
| disconnected | boolean |
| reading | boolean |
TcpIsConnectedResult
| Prop | Type |
| ------------------ | --------------------------- |
| error | boolean |
| errorMessage | string | null |
| connected | boolean |
TcpIsReadingResult
| Prop | Type |
| ------------------ | --------------------------- |
| error | boolean |
| errorMessage | string | null |
| reading | boolean |
TcpWriteResult
| Prop | Type |
| ------------------ | --------------------------- |
| error | boolean |
| errorMessage | string | null |
| bytesSent | number |
TcpWriteOptions
| Prop | Type |
| ---------- | --------------------------------------------------------- |
| data | TcpBytePayload |
TcpByteArrayLike
Byte-like array accepted by write APIs. Uint8Array is supported because it has numeric indexes and a length.
| Prop | Type |
| ------------ | ------------------- |
| length | number |
TcpWriteAndReadResult
| Prop | Type |
| ------------------- | --------------------------- |
| error | boolean |
| errorMessage | string | null |
| bytesSent | number |
| bytesReceived | number |
| data | number[] |
| matched | boolean |
TcpWriteAndReadOptions
| Prop | Type | Description |
| --------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| data | TcpBytePayload | |
| timeout | number | RR timeout in ms. Default 1000. Values <= 0 fall back to the default. |
| maxBytes | number | Maximum bytes to accumulate. Default 4096, capped at 16 MiB. |
| expect | string | TcpBytePayload | Optional pattern — reading stops when found. Accepts number[] / Uint8Array or hex string (e.g. "1B40", "0x1b 0x40"). Empty values are treated as no expect pattern. |
| suspendStreamDuringRR | boolean | Suspend stream reader during RR to avoid consuming reply. Default true. |
TcpStartStopResult
| Prop | Type |
| ------------------ | --------------------------- |
| error | boolean |
| errorMessage | string | null |
| reading | boolean |
TcpStartReadOptions
| Prop | Type | Description |
| ----------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| chunkSize | number | Stream read chunk size in bytes. Default 4096, capped at 16 MiB. - Android/iOS: size of each native socket read before bridge micro-batching. - Electron: maximum bytes per emitted tcpData event after micro-batching. |
| readTimeout | number | Stream read timeout in ms. - Android: sets SO_TIMEOUT for the continuous reader. - iOS: no-op. - Electron: updates the per-connection default writeAndRead timeout; the stream reader itself remains event-driven. |
PluginListenerHandle
| Prop | Type |
| ------------ | ----------------------------------------- |
| remove | () => Promise<void> |
TcpDataEvent
Emitted by the stream reader. connectionId identifies which connection sent the data.
| Prop | Type |
| ------------------ | --------------------- |
| connectionId | string |
| data | number[] |
TcpDisconnectEvent
Emitted when a connection closes.
| Prop | Type |
| ------------------ | -------------------------------------------- |
| connectionId | string |
| disconnected | true |
| reading | boolean |
| reason | 'error' | 'manual' | 'remote' |
| error | string |
TcpCreateConnectionOptions
Options for TCPClient.createConnection(). All fields are optional. host/port and other connect options set here become defaults for every connect() call on the returned instance.
| Prop | Type | Description |
| ------------------ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| connectionId | string | Optional stable identifier for this connection. If an instance with this id already exists in the registry, it is returned as-is. Omit to get a new instance with a generated UUID each time. |
TcpGetPlatformResult
| Prop | Type |
| ------------------ | --------------------------------------------------- |
| error | boolean |
| errorMessage | string | null |
| platform | TcpPlatform |
Type Aliases
Partial
Make all properties in T optional
{ [P in keyof T]?: T[P]; }
TcpBytePayload
Byte payload accepted by write APIs. Values must be integer bytes in the 0..255 range.
number[] | TcpByteArrayLike
TcpPlatform
'ios' | 'android' | 'web' | 'electron'
License
MIT
