iOS device management toolkit using libimobiledevice command-line tools
npm install @mcesystems/apple-kitbash
npm install @mcesystems/apple-kit
`
Requirements
- Node.js 18+
- iOS device connected via USB
- Device must be trusted/paired with the computer
- libimobiledevice tools (idevice\*)
- go-ios ios CLI binary
$3
#### Windows
- libimobiledevice binaries - use the export script (see below)
- go-ios ios.exe (see Resources section below)
- iTunes installed OR Apple Mobile Device Support
#### macOS
Option 1: Use bundled binaries (recommended for distribution)
Use the export script to bundle libimobiledevice for your application:
`bash
Using npx (after installing the package)
npx export-apple-resources /path/to/your-app/resources/apple-kit
Or run the script directly
npx tsx node_modules/@mcesystems/apple-kit/scripts/export-resources.ts /path/to/your-app/resources
`
See scripts/README.md for detailed prerequisites and instructions.
Option 2: Use Homebrew installation (for development)
- Install via Homebrew: brew install libimobiledevice ideviceinstaller
- Tools are auto-detected from /opt/homebrew/bin (Apple Silicon) or /usr/local/bin (Intel)
#### Linux
- libimobiledevice-utils: sudo apt install libimobiledevice-utils
- Tools are auto-detected from /usr/bin or /usr/local/bin
$3
Set a resources directory once so both toolchains can be located:
`typescript
import path from "node:path";
import { AppleDeviceKit } from "@mcesystems/apple-kit";
AppleDeviceKit.setResourcesDir(path.join(process.cwd(), "resources"));
`
If you do not set a resources directory, make sure both toolchains are on your PATH.
The package looks for tools in this order:
1. resourcesDir/ios/bin/{platform}/ (go-ios ios and libimobiledevice tools)
2. Homebrew paths on macOS (/opt/homebrew/bin, /usr/local/bin)
3. System PATH (for global installations)
Usage
$3
`typescript
import { createIosCli } from "@mcesystems/apple-kit";
// Example: /ios/bin/{platform}/ios(.exe)
const cli = createIosCli("path/to/ios");
const list = await cli.listDevices();
console.log(list.udids);
`
$3
`typescript
import { AppleDeviceKit } from '@mcesystems/apple-kit';
const device = new AppleDeviceKit('device-udid', 1);
// Install app locally, then (if MDM is configured) take over management
await device.installApp('/path/to/agent.ipa', {
appId: 'com.example.agent',
url: 'https://example.com/agent.ipa',
waitForInstalled: true
});
// Check if installed
const isInstalled = await device.isAppInstalled('com.example.agent');
// List all installed apps
const apps = await device.listApps();
// Uninstall an agent/app
await device.uninstallApp('com.example.agent');
`
$3
`typescript
const device = new AppleDeviceKit('device-udid', 1);
const info = await device.info();
console.log(Device: ${info.DeviceName});
console.log(Model: ${info.ProductType});
console.log(iOS: ${info.ProductVersion} (${info.BuildVersion}));
console.log(Serial: ${info.SerialNumber});
console.log(UDID: ${info.UniqueDeviceID});
`
$3
`typescript
const device = new AppleDeviceKit('device-udid', 1);
// Check if device is trusted
const isPaired = await device.isPaired();
// Trust the device (initiates pairing and waits for user acceptance)
await device.trustDevice(60000);
// Unpair device
await device.unpair();
`
$3
`typescript
const device = new AppleDeviceKit('device-udid', 1);
// Forward device port 8080 to a local port (auto-allocated)
const forward = await device.startPortForwardAsync(8080);
console.log(Local port: ${forward.localPort});
// Use the forwarded connection...
// connect to localhost:8080 to reach device:8080
// Stop forwarding when done
device.closePortForward();
`
$3
`typescript
const device = new AppleDeviceKit('device-udid', 1);
// Get activation state
const state = await device.getActivationState();
console.log(Activated: ${state.isActivated});
console.log(State: ${state.activationState});
// Activate device (uses go-ios and MDM client)
const cleanup = await device.activate();
if (cleanup) {
await cleanup(); // removes WiFi profile when done
}
`
The activation flow can install a WiFi profile based on environment variables:
WIFI_SSID, WIFI_PASSWORD, WIFI_ENCRYPTION, WIFI_HIDDEN, WIFI_ENTERPRISE,
WIFI_USERNAME, and WIFI_EAP_TYPE.
$3
`typescript
const device = new AppleDeviceKit('device-udid', 1);
// List profiles
const profiles = await device.listProfiles();
console.log(profiles.profiles);
// Remove a profile by identifier
await device.removeProfile("com.example.profile");
`
$3
`typescript
const device = new AppleDeviceKit('device-udid', 1);
// WARNING: this erases all data
await device.wipe();
`
API Reference
$3
Static methods:
- setResourcesDir(dir): Configure resources location
Device Info:
- info(): Get device properties
- getDeviceId(): Get the device UDID
- getLogicalPort(): Get the logical port number
- getDevicePort(): Get current local forwarded port (or null)
App Management:
- installApp(ipaPath, options): Install IPA and take over via MDM if configured
- uninstallApp(bundleId): Uninstall an app by bundle ID
- isAppInstalled(bundleId): Check if app is installed
- listApps(): List all installed user apps
Trust/Pairing:
- isPaired(): Check if device is paired/trusted
- pair(): Initiate pairing (user must accept on device)
- trustDevice(timeout?, onWaiting?): Pair and wait for user acceptance
- unpair(): Remove pairing/trust
- waitForPairing(timeout?, pollInterval?): Wait for device to be paired
Port Forwarding:
- startPortForwardAsync(devicePort, startupTimeout?): Start and wait for ready
- closePortForward(): Stop forwarding
Profiles:
- listProfiles(): List installed profiles
- removeProfile(identifier): Remove profile by identifier
Activation:
- getActivationState(): Get activation state
- activate(): Activate the device (returns cleanup function)
Device Wipe:
- wipe(): Erase device data
Lifecycle:
- dispose(): Clean up resources and port forwards
$3
`typescript
interface ActivationState {
isActivated: boolean;
activationState: string;
}
``