Optional
options: Partial<DeviceClientOptions>Private
Optional
#extraReadonly
clientPrivate
optionsReadonly
serialprepare a STFService and STFagent this server must be started with the start() method
Optional
options: Partial<STFServiceOptions>exec a service call command and return Parcel responce Data as a Buffer
a PsEntry array
Rest
...args: ServiceCallArg[]Private
connectionreturn a new connection to ADB.
execute a single shell command and get stdout responce as a buffer of a string.
the command to execute
Forwards socket connections from the ADB server host (local) to the device (remote). This is analogous to adb forward <local> <remote>
. It's important to note that if you are connected to a remote ADB server, the forward will be created on that host.
true
A string representing the local endpoint on the ADB host. At time of writing, can be one of:
tcp:<port>
localabstract:<unix domain socket name>
localreserved:<unix domain socket name>
localfilesystem:<unix domain socket name>
dev:<character device name>
A string representing the remote endpoint on the device. At time of writing, can be one of:
Any value accepted by the local
argument
jdwp:<process pid>
Fetches the current raw framebuffer (i.e. what is visible on the screen) from the device, and optionally converts it into something more usable by using [GraphicsMagick][graphicsmagick]'s gm
command, which must be available in $PATH
if conversion is desired. Note that we don't bother supporting really old framebuffer formats such as RGB_565. If for some mysterious reason you happen to run into a >=2.3
device that uses RGB_565, let us know.
Note that high-resolution devices can have quite massive framebuffers. For example, a device with a resolution of 1920x1080 and 32 bit colors would have a roughly 8MB (1920*1080*4
byte) RGBA framebuffer. Empirical tests point to about 5MB/s bandwidth limit for the ADB USB connection, which means that it can take ~1.6 seconds for the raw data to arrive, or even more if the USB connection is already congested. Using a conversion will further slow down completion.
The possibly converted framebuffer stream. The stream also has a meta
.:
The desired output format. Any output format supported by [GraphicsMagick][graphicsmagick] (such as 'png'
) is supported. Defaults to 'raw'
for raw framebuffer data.
Gets the device path of the device identified by the given serial number.
The device path. This corresponds to the device path in client.listDevicesWithPaths()
.
List devices withPath
import Adb from '@u4/adbkit';
const client = Adb.createClient();
const devices = client.listDevicesWithPaths();
devices.then((devices) => {
devices.forEach(function (d) {
console.log('id: ' + d.id);
console.log('type: ' + d.type);
console.log('model ' + d.model);
console.log('path: ' + d.path);
console.log('product: ' + d.product);
console.log('transportId: ' + d.transportId + '\n');
});
});
Retrieves the features of the device identified by the given serial number. This is analogous to adb shell pm list features
. Useful for checking whether hardware features such as NFC are available (you'd check for 'android.hardware.nfc'
).
An object of device features. Each key corresponds to a device feature, with the value being either true
for a boolean feature, or the feature value as a string (e.g. '0x20000'
for reqGlEsVersion
).
Checking for NFC support
import Adb from '@u4/adbkit';
const client = Adb.createClient();
const test = async () => {
try {
const devices = await client.listDevices();
const supportedDevices: string[] = [];
for (const device of devices) {
const client = device.client();
const features = await client.getFeatures(device.id);
if (features['android.hardware.nfc'])
supportedDevices.push(device.serial);
}
console.log('The following devices support NFC:', supportedDevices);
} catch (err) {
console.error('Something went wrong:', err.stack);
}
};
Attemps to retrieve the IP addresses of the device. using ip addr show
command.
The IP addresses as string[] starting with IPv4 then IPv6.
Optional
iface: string = 'wlan0'The network interface. Defaults to 'wlan0'
.
Retrieves the list of packages present on the device. This is analogous to adb shell pm list packages
. If you just want to see if something's installed, consider using client.isInstalled()
instead.
An object of device features. Each key corresponds to a device feature, with the value being either true
for a boolean feature, or the feature value as a string (e.g. '0x20000'
for reqGlEsVersion
)
Optional
flags: stringFlags to pass to the pm list packages
command to filter the list
-d: filter to only show disabled packages
-e: filter to only show enabled packages
-s: filter to only show system packages
-3: filter to only show third party packages
Retrieves the properties of the device identified by the given serial number. This is analogous to adb shell getprop
.
An object of device properties. Each key corresponds to a device property. Convenient for accessing things like 'ro.product.model'
.
Gets the serial number of the device identified by the given serial number. With our API this doesn't really make much sense, but it has been implemented for completeness. FYI: in the raw ADB protocol you can specify a device in other ways, too.
The serial number of the device.
Retrieves the list of available services
a PsEntry array
Gets the state of the device identified by the given serial number.
The device state. This corresponds to the device type in client.listDevices()
.
Installs the APK on the device, replacing any previously installed version. This is roughly analogous to adb install -r <apk>
.
Note that if the call seems to stall, you may have to accept a dialog on the phone first.
true
This example requires the request module. It also doesn't do any error handling (404 responses, timeouts, invalid URLs etc).
import Adb from '@u4/adbkit';
import request from 'request';
import { Readable } from 'stream';
const client = Adb.createClient();
const test = async () => {
// The request module implements old-style streams, so we have to wrap it.
try {
// request is deprecated
const device = client.getClient('<serial>');
await device.install(new Readable().wrap(request('http://example.org/app.apk') as any) as any)
console.log('Installed')
} catch (err) {
console.error('Something went wrong:', err.stack)
}
}
Install an apk to all connected devices
import Adb from '@u4/adbkit';
const client = Adb.createClient();
const apk = 'vendor/app.apk';
const test = async () => {
try {
const devices = await client.listDevices();
for (const device of devices) {
await device.getClient().install(apk);
console.log(`Installed ${apk} on all connected devices`);
}
} catch (err) {
console.error('Something went wrong:', err.stack);
}
};
When String
, interpreted as a path to an APK file. When [Stream
][node-stream], installs directly from the stream, which must be a valid APK.
Installs an APK file which must already be located on the device file system, and replaces any previously installed version. Useful if you've previously pushed the file to the device for some reason (perhaps to have direct access to client.push()
's transfer stats). This is roughly analogous to adb shell pm install -r <apk>
followed by adb shell rm -f <apk>
.
Note that if the call seems to stall, you may have to accept a dialog on the phone first.
true
The path to the APK file on the device. The file will be removed when the command completes.
call ip route command
a IpRouteEntry array
Rest
...args: string[]call ip rule command
a IpRuleEntry array
Rest
...args: string[]Tells you if the specific package is installed or not. This is analogous to adb shell pm path <pkg>
and some output parsing.
true
if the package is installed, false
otherwise.
The package name. This is NOT the APK.
Lists forwarded connections on the device. This is analogous to adb forward --list
.
An array of forward objects with the following properties:
client.forward()
's local
argument.client.forward()
's remote
argument.List package installed into the devices,
an array of DevicePackage
Optional
options: { list all or only third party apps
Optional
thirdparty?: booleanLists forwarded connections on the device. This is analogous to adb reverse --list
.
An array of Reverse objects with the following properties:
client.reverse()
's remote
argument.client.reverse()
's local
argument.prepare a minicap server this server must be started with the start() method
Optional
options: Partial<MinicapOptions>Opens a direct connection to a unix domain socket in the given path.
The connection (i.e. [net.Socket
][node-net]). Read and write as you please. Call conn.end()
to end the connection.
The path to the socket. Prefixed with 'localfilesystem:'
by default, include another prefix (e.g. 'localabstract:'
) in the path to override.
Opens a direct connection to a binary log file, providing access to the raw log data. Note that it is usually much more convenient to use the client.openLogcat()
method, described separately.
The binary log stream. Call log.end()
when you wish to stop receiving data.
The name of the log. Available logs include 'main'
, 'system'
, 'radio'
and 'events'
.
Calls the logcat
utility on the device and hands off the connection to [adbkit-logcat][adbkit-logcat], a pure Node.js Logcat client. This is analogous to adb logcat -B
, but the event stream will be parsed for you and a separate event will be emitted for every log entry, allowing for easy processing.
For more information, check out the [adbkit-logcat][adbkit-logcat] documentation.
The Logcat client. Please see the [adbkit-logcat][adbkit-logcat] documentation for details.
Optional. The following options are supported:
true
, clears logcat before opening the reader. Not set by default.Optional
clear?: booleanStarts the built-in monkey
utility on the device, connects to it using client.openTcp()
and hands the connection to [adbkit-monkey][adbkit-monkey], a pure Node.js Monkey client. This allows you to create touch and key events, among other things.
For more information, check out the [adbkit-monkey][adbkit-monkey] documentation.
The Monkey client. Please see the [adbkit-monkey][adbkit-monkey] documentation for details.
Optional. The device port where you'd like Monkey to run at. Defaults to 1080
.
Tracks /proc/stat
and emits useful information, such as CPU load.
A single sync service instance is used to download the /proc/stat
file for processing.
While doing this does consume some resources, it is very light and should not be a problem.
/proc/stat is pulled once per sec, and emit a 'load' event.
The /proc/stat
tracker, which is an [EventEmitter
][node-events]. Call stat.end()
to stop tracking. The following events are available:
'cpu0'
, 'cpu1'
) and the value an object with the following properties:
- user Percentage (0-100) of ticks spent on user programs.
- nice Percentage (0-100) of ticks spent on nice
d user programs.
- system Percentage (0-100) of ticks spent on system programs.
- idle Percentage (0-100) of ticks spent idling.
- iowait Percentage (0-100) of ticks spent waiting for IO.
- irq Percentage (0-100) of ticks spent on hardware interrupts.
- softirq Percentage (0-100) of ticks spent on software interrupts.
- steal Percentage (0-100) of ticks stolen by others.
- guest Percentage (0-100) of ticks spent by a guest.
- guestnice Percentage (0-100) of ticks spent by a nice
d guest.
- total Total. Always 100.Opens a direct TCP connection to a port on the device, without any port forwarding required.
The TCP connection (i.e. [net.Socket
][node-net]). Read and write as you please. Call conn.end()
to end the connection.
The port number to connect to.
Optional
host: stringOptional. The host to connect to. Allegedly this is supposed to establish a connection to the given host from the device, but we have not been able to get it to work at all. Skip the host and everything works great.
A convenience shortcut for sync.pull()
, mainly for one-off use cases. The connection cannot be reused, resulting in poorer performance over multiple calls. However, the Sync client will be closed automatically for you, so that's one less thing to worry about.
A PullTransfer
instance.
Pulling a file from all cofnnected devices
import Bluebird from 'bluebird';
import fs from 'fs';
import Adb from '@u4/adbkit';
const client = Adb.createClient();
const test = async () => {
try {
const devices = await client.listDevices();
await Bluebird.map(devices, async (device) => {
const transfer = await client.pull(device.id, '/system/build.prop');
const fn = `/tmp/${device.id}.build.prop`;
await new Bluebird((resolve, reject) => {
transfer.on('progress', (stats) =>
console.log(`[${device.id}] Pulled ${stats.bytesTransferred} bytes so far`),
);
transfer.on('end', () => {
console.log(`[${device.id}] Pull complete`);
resolve(device.id);
});
transfer.on('error', reject);
transfer.pipe(fs.createWriteStream(fn));
});
});
console.log('Done pulling /system/build.prop from all connected devices');
} catch (err) {
console.error('Something went wrong:', err.stack);
}
};
See sync.pull()
for details.
A convenience shortcut for sync.push()
, mainly for one-off use cases. The connection cannot be reused, resulting in poorer performance over multiple calls. However, the Sync client will be closed automatically for you, so that's one less thing to worry about.
Pushing a file to all connected devices
import Bluebird from 'bluebird';
import Adb from '@u4/adbkit';
const client = Adb.createClient();
const test = async () => {
try {
const devices = await client.listDevices();
await Bluebird.map(devices, async (device) => {
const transfer = await client.push(device.id, 'temp/foo.txt', '/data/local/tmp/foo.txt');
await new Bluebird(function (resolve, reject) {
transfer.on('progress', (stats) =>
console.log(`[${device.id}] Pushed ${stats.bytesTransferred} bytes so far`),
);
transfer.on('end', () => {
console.log('[${device.id}] Push complete');
resolve();
});
transfer.on('error', reject);
});
});
console.log('Done pushing foo.txt to all connected devices');
} catch (err) {
console.error('Something went wrong:', err.stack);
}
};
See sync.push()
for details.
See sync.push()
for details.
Optional
mode: numberSee sync.push()
for details.
A convenience shortcut for sync.readdir()
, mainly for one-off use cases. The connection cannot be reused, resulting in poorer performance over multiple calls. However, the Sync client will be closed automatically for you, so that's one less thing to worry about.
Files Lists
List files in a folder
import Bluebird from 'bluebird';
import Adb from '@u4/adbkit';
const client = Adb.createClient();
const test = async () => {
try {
const devices = await client.listDevices();
await Bluebird.map(devices, async (device) => {
const files = await client.readdir(device.id, '/sdcard');
// Synchronous, so we don't have to care about returning at the
// right time
files.forEach((file) => {
if (file.isFile()) {
console.log(`[${device.id}] Found file "${file.name}"`);
}
});
});
console.log('Done checking /sdcard files on connected devices');
} catch (err) {
console.error('Something went wrong:', err.stack);
}
};
See sync.readdir()
for details.
A convenience shortcut for sync.readdir2()
, mainly for one-off use cases. The connection cannot be reused, resulting in poorer performance over multiple calls. However, the Sync client will be closed automatically for you, so that's one less thing to worry about.
Files Lists
See sync.readdir()
for details.
Puts the device into root mode which may be needed by certain shell commands. A remount is generally required after a successful root call. Note that this will only work if your device supports this feature. Production devices almost never do.
true
Optional
type: RebootTypeRemove the port forward at ADB server host (local). This is analogous to adb forward --remove
true
A string representing the local endpoint on the ADB host. At time of writing, can be one of: tcp:<port>
, localabstract:<unix domain socket name>
, localreserved:<unix domain socket name>
, localfilesystem:<unix domain socket name>
, dev:<character device name>
Reverses socket connections from the device (remote) to the ADB server host (local). This is analogous to adb reverse <remote> <local>
. It's important to note that if you are connected to a remote ADB server, the reverse will be created on that host.
true
A string representing the remote endpoint on the device. At time of writing, can be one of:
tcp:<port>
localabstract:<unix domain socket name>
localreserved:<unix domain socket name>
localfilesystem:<unix domain socket name>
A string representing the local endpoint on the ADB host. At time of writing, can be any value accepted by the remote
argument.
Puts the device into root mode which may be needed by certain shell commands. A remount is generally required after a successful root call. Note that this will only work if your device supports this feature. Production devices almost never do.
true
prepare a Scrcpy server this server must be started with the start() method
Optional
options: Partial<ScrcpyOptions>Takes a screenshot in PNG format using the built-in screencap
utility. This is analogous to adb shell screencap -p
. Sadly, the utility is not available on most Android <=2.3
devices, but a silent fallback to the client.framebuffer()
command in PNG mode is attempted, so you should have its dependencies installed just in case.
Generating the PNG on the device naturally requires considerably more processing time on that side. However, as the data transferred over USB easily decreases by ~95%, and no conversion being required on the host, this method is usually several times faster than using the framebuffer. Naturally, this benefit does not apply if we're forced to fall back to the framebuffer.
For convenience purposes, if the screencap command fails (e.g. because it doesn't exist on older Androids), we fall back to client.framebuffer(serial, 'png')
, which is slower and has additional installation requirements.
The PNG stream.
Runs a shell command on the device. Note that you'll be limited to the permissions of the shell
user, which ADB uses.
A readable stream (Socket
actually) containing the progressive stdout
of the command. Use with adb.util.readAll
to get a readable String from it.
Read the output of an instantaneous command
import Adb from '@u4/adbkit';
try {
const client = Adb.createClient();
const devices = await client.listDevices();
for (const device of devices) {
const stream = await device.getClient().shell('echo $RANDOM');
// Use the readAll() utility to read all the content without
// having to deal with the readable stream. `output` will be a Buffer
// containing all the output.
const output = await adb.util.readAll(stream);
console.log('[%s] %s', device.id, output.toString().trim());
}
console.log('Done.');
} catch(err) {
console.error('Something went wrong:', err.stack);
}
Progressively read the output of a long-running command and terminate it
import Adb from '@u4/adbkit';
const client = Adb.createClient();
const devices = await client.listDevices()
for (const device of devices) {
// logcat just for illustration, prefer client.openLogcat in real use
const conn = await device.getClient().shell('logcat')
let line = 0
conn.on('data', function(data) {
// here `ps` on the device shows the running logcat process
console.log(data.toString())
line += 1
// close the stream and the running process
// on the device will be gone, gracefully
if (line > 100) conn.end()
});
conn.on('close', function() {
// here `ps` on the device shows the logcat process is gone
console.log('100 lines read already, bye')
})
}
console.log('Done.')
The shell command to execute. When String
, the command is run as-is. When Array
, the elements will be rudimentarily escaped (for convenience, not security) and joined to form a command.
Starts the configured activity on the device. Roughly analogous to adb shell am start <options>
.
The activity configuration.
Starts the configured service on the device. Roughly analogous to adb shell am startservice <options>
.
The activity configuration.
A convenience shortcut for sync.stat()
, mainly for one-off use cases. The connection cannot be reused, resulting in poorer performance over multiple calls. However, the Sync client will be closed automatically for you, so that's one less thing to worry about.
An [fs.Stats
][node-fs-stats] instance. While the stats.is*
methods are available, only the following properties are supported:
Date
.The path.
A convenience shortcut for sync.stat64()
, mainly for one-off use cases. The connection cannot be reused, resulting in poorer performance over multiple calls. However, the Sync client will be closed automatically for you, so that's one less thing to worry about.
*
*
An [fs.Stats
][node-fs-stats] instance. While the stats.is*
methods are available, only the following properties are supported:
Date
.The path.
* *
Establishes a new Sync connection that can be used to push and pull files. This method provides the most freedom and the best performance for repeated use, but can be a bit cumbersome to use. For simple use cases, consider using client.stat()
, client.push()
and client.pull()
.
The Sync client. See below for details. Call sync.end()
when done.
Puts the device's ADB daemon into tcp mode, allowing you to use adb connect
or client.connect()
to connect to it. Note that the device will still be visible to ADB as a regular USB-connected device until you unplug it. Same as adb tcpip <port>
.
The port the device started listening on.
Optional. The port the device should listen on. Defaults to 5555
.
Starts a JDWP tracker for the given device.
Note that as the tracker will keep a connection open, you must call tracker.end()
if you wish to stop tracking JDWP processes.
The JDWP tracker, which is an [EventEmitter
][node-events]. The following events are available:
return a new connextion to the current Host devices
Get a localTCP port connected to remote socket, this method will try to get the requested port, but if the port is already taken, will choose an other one. Note if a foward already existe to the same destination with a different port, no new foward will be create.
the used port
A string representing the remote endpoint on the device. At time of writing, can be one of:
Any value accepted by the local
argument
jdwp:<process pid>
Optional
preferedPort: numberthe TCP port you would like to get.
Waits until ADB can see the device. Note that you must know the serial in advance. Other than that, works like adb -s serial wait-for-device
. If you're planning on reacting to random devices being plugged in and out, consider using client.trackDevices()
instead.
The device ID. Can be useful for chaining.
Generated using TypeDoc
get extra fucntions
Returns
an DeviceClientExtra