Device
The Device class is the primary interface for interacting with a mobile device. Test functions receive a device instance through the test fixtures.
In addition to the locator methods above, Device provides device-level actions that don’t target a specific element.
device.platform: "android" | "ios"
Section titled “device.platform: "android" | "ios"”Read-only property exposing the platform the device is running. Useful for branching on platform-specific behaviour in tests (e.g. native dialog labels or soft-keyboard handling).
if (device.platform === "android") { await device.pressBack();}device.swipe(direction: SwipeDirection, options?: SwipeOptions): Promise<void>
Section titled “device.swipe(direction: SwipeDirection, options?: SwipeOptions): Promise<void>”Perform a swipe gesture across the screen in the given direction: "up", "down", "left" or "right" (the way the finger moves, so "up" reveals what is below; case-insensitive). See SwipeDirection.
On Android, swipe() (like dragXY()) returns once any scrolling it started has come to rest: it waits until no scroll along the swipe’s axis has been reported for 300 ms, at most 3 s. A scroll view that is still flinging takes the next touch as “stop scrolling”, so a tap() made straight after the swipe would otherwise be lost.
await device.swipe("up");await device.swipe("left", { speed: 500, distance: 0.5 });SwipeOptions:
| Option | Type | Description |
|---|---|---|
speed |
number |
Swipe speed in pixels per second |
distance |
number |
Swipe distance as a fraction of screen size (0-1) |
timeoutMs |
number |
Override the default timeout |
device.pressKey(key: DeviceKey): Promise<void>
Section titled “device.pressKey(key: DeviceKey): Promise<void>”Press a device key by name, case-insensitive. The names are typed as DeviceKey for autocompletion; any other string still compiles, since Android also takes a numeric key code ("66") and iOS a single character to type. A name the platform does not support throws.
await device.pressKey("ENTER");await device.pressKey("HOME");await device.pressKey("VOLUME_UP");Role, SwipeDirection and DeviceKey
Section titled “Role, SwipeDirection and DeviceKey”The role, direction and key parameters are typed as unions of their known names, so your editor autocompletes them. Each parameter also takes any other string (it is typed Role | (string & {}) and so on). getByRole() throws at once on an unknown role; toHaveRole() does not check the name, it compares it with the element’s role; the agents reject an unknown direction or key when the action runs.
import type { DeviceKey, Role, SwipeDirection } from "tapsmith";| Type | Used by | Names |
|---|---|---|
Role |
getByRole(), toHaveRole() |
The native roles in the role table, plus the React Native aliases header, slider, search and radio. Also exported: NativeRole, the native roles alone. |
SwipeDirection |
device.swipe(), scroll(), scrollIntoView({ direction }) |
"up", "down", "left", "right" |
DeviceKey |
device.pressKey() |
BACK, HOME, ENTER / RETURN, TAB, DELETE / BACKSPACE, FORWARD_DELETE, ESCAPE / ESC, MENU, SEARCH, VOLUME_UP, VOLUME_DOWN, POWER, CAMERA, DPAD_UP, DPAD_DOWN, DPAD_LEFT, DPAD_RIGHT, DPAD_CENTER, SPACE, RECENTS / APP_SWITCH |
All names are case-insensitive. scroll() and scrollIntoView() take the way the view scrolls ("down" reveals what is below), while device.swipe() takes the way the finger moves ("up" reveals what is below). Every DeviceKey works on Android. iOS supports HOME, ENTER / RETURN, TAB, DELETE / BACKSPACE, ESCAPE / ESC (which submits, like ENTER), SPACE and BACK (which taps the navigation bar’s back button), and types any single character.
device.pressBack(): Promise<void> (Android only)
Section titled “device.pressBack(): Promise<void> (Android only)”Press the Android back button. Convenience method equivalent to device.pressKey("BACK").
await device.pressBack();device.tapXY(x: number, y: number): Promise<void>
Section titled “device.tapXY(x: number, y: number): Promise<void>”Tap at raw screen coordinates in logical points (Android pixels; iOS points). Prefer locator-based tap() in tests; use this for coordinate-driven interaction (e.g., device mirror gestures). On iOS what is at the point is unknown, so the touch is held 20 ms, as on a switch (see Touch hold).
await device.tapXY(120, 340);device.longPressXY(x: number, y: number, options?: { duration?: number }): Promise<void>
Section titled “device.longPressXY(x: number, y: number, options?: { duration?: number }): Promise<void>”Long-press at raw screen coordinates in logical points. options.duration specifies the hold duration in milliseconds (default 1000). The press is held for that long, so a duration shorter than the app’s own long-press delay (often around 500 ms) can register as a tap.
await device.longPressXY(120, 340, { duration: 800 });device.dragXY(from: { x: number; y: number }, to: { x: number; y: number }, options?: { duration?: number }): Promise<void>
Section titled “device.dragXY(from: { x: number; y: number }, to: { x: number; y: number }, options?: { duration?: number }): Promise<void>”Drag/swipe from one point to another in logical points. options.duration specifies the drag duration in milliseconds (default 300).
await device.dragXY({ x: 50, y: 200 }, { x: 50, y: 600 }, { duration: 400 });Platform note: on Android the drag takes
duration, at least 25 ms (then waits for any scroll it started to come to rest, asswipe()does). On iOS, the drag is performed via a fixed-duration synthesized gesture, sodurationcurrently has no effect on speed.
device.inputText(text: string): Promise<void>
Section titled “device.inputText(text: string): Promise<void>”Type text into whatever element currently has focus (no locator). Useful for inserting text without first tapping a field.
await device.inputText("hello world");device.takeScreenshot(): Promise<ScreenshotResponse>
Section titled “device.takeScreenshot(): Promise<ScreenshotResponse>”Capture a screenshot of the current device screen. Returns an object with success, data (PNG bytes), and errorMessage fields.
const screenshot = await device.takeScreenshot();device.waitForIdle(timeoutMs?: number): Promise<void>
Section titled “device.waitForIdle(timeoutMs?: number): Promise<void>”Give the app’s UI a moment to settle. On Android it waits for accessibility events to go quiet, up to timeoutMs (the configured default timeout if none is specified); on iOS it waits until two screenshots taken a couple of frames apart match, up to timeoutMs or a quarter of a second, whichever is shorter. It does not prove the screen is idle, so wait for what you need with an assertion.
await device.waitForIdle();await device.waitForIdle(5000);device.installApk(apkPath: string): Promise<void>
Section titled “device.installApk(apkPath: string): Promise<void>”Install an APK on the connected device.
await device.installApk("./app-debug.apk");device.listDevices(): Promise<ListDevicesResponse>
Section titled “device.listDevices(): Promise<ListDevicesResponse>”List the devices the daemon can see. Resolves to { requestId, devices, unusableDevices }, where each
entry is { serial, model, state, isEmulator, platform, osVersion }.
devicesare the devices Tapsmith can target, Android and iOS. A device that was selected and has since gone away stays here withstate: 'Disconnected'.unusableDevicesare Android devices adb lists but cannot use (unauthorized, offline,no permissions (…), …). Theirstateis adb’s whole state string. Tapsmith never selects them, so they cannot be passed tosetDevice;tapsmith list-devicesshows how to fix each one. A serial can appear in both lists when two attached devices share it.
device.setDevice(serial: string): Promise<void>
Section titled “device.setDevice(serial: string): Promise<void>”Target a specific device by its serial number.
Tapsmith’s run paths claim a device before selecting it, and refuse a device that another running Tapsmith session holds
(see Several sessions on one machine). setDevice
itself does not check claims: switching devices mid-test is up to the test.
await device.setDevice("emulator-5554");device.startAgent(targetPackage: string): Promise<void>
Section titled “device.startAgent(targetPackage: string): Promise<void>”Start the Tapsmith on-device agent for the given app package.
await device.startAgent("com.myapp");device.launchApp(packageName: string, options?: LaunchAppOptions): Promise<void>
Section titled “device.launchApp(packageName: string, options?: LaunchAppOptions): Promise<void>”Launch an Android app by package name. This is the mobile equivalent of page.goto(url).
await device.launchApp("com.example.myapp");await device.launchApp("com.example.myapp", { activity: ".MainActivity" });await device.launchApp("com.example.myapp", { clearData: true }); // fresh startawait device.launchApp("com.example.myapp", { waitForIdle: false }); // return immediatelyOptions:
activity?— specific Activity to launch (e.g.,".settings.ProfileActivity")clearData?— clear all app data before launching (default:false)waitForIdle?— wait for the UI to settle after launch (default:true)
device.openDeepLink(uri: string, options?: OpenDeepLinkOptions): Promise<void>
Section titled “device.openDeepLink(uri: string, options?: OpenDeepLinkOptions): Promise<void>”Navigate to a screen via deep link URI.
await device.openDeepLink("myapp://settings/profile");await device.openDeepLink("https://example.com/product/123"); // app linksawait device.openDeepLink("myapp://__reset", { forceColdLaunch: true });Options:
forceColdLaunch?— on iOS simulators, skip the warm in-process delivery attempt and cold-relaunch the app with the URL (default:false). Use when the deep link must start from a fresh process, e.g. a state-clearing reset. No effect on Android or physical iOS, which always deliver warm.
Deep links are delivered to the running app without relaunching it (warm delivery) whenever possible. On iOS simulators, if warm delivery does not reach its destination within a bounded window, Tapsmith automatically falls back to a cold relaunch with the URL.
device.currentPackage(): Promise<string>
Section titled “device.currentPackage(): Promise<string>”Returns the package name of the foreground app. On iOS it always returns the configured app’s bundle ID, whichever app is in front.
const pkg = await device.currentPackage(); // "com.example.myapp"device.currentActivity(): Promise<string> (Android only)
Section titled “device.currentActivity(): Promise<string> (Android only)”Returns the current activity name.
const activity = await device.currentActivity(); // ".settings.ProfileActivity"device.terminateApp(packageName?: string): Promise<void>
Section titled “device.terminateApp(packageName?: string): Promise<void>”Force-stop an app.
await device.terminateApp("com.example.myapp");device.getAppState(packageName?: string, options?): Promise<AppState>
Section titled “device.getAppState(packageName?: string, options?): Promise<AppState>”Check the state of an app: the config’s package unless you name another. Returns "not_installed", "stopped", "background", or "foreground". It reads the state once and does not wait for one; wrap it in expect.poll() to wait. timeout bounds the query, and with no package it is the first argument (getAppState({ timeout: 5000 })). With no package named and none configured, it throws.
const state = await device.getAppState(); // the config's appconst other = await device.getAppState("com.example.other");await expect.poll(() => device.getAppState()).toBe("foreground");device.sendToBackground(): Promise<void>
Section titled “device.sendToBackground(): Promise<void>”Press the home button to send the current app to the background.
await device.sendToBackground();device.bringToForeground(packageName: string): Promise<void>
Section titled “device.bringToForeground(packageName: string): Promise<void>”Bring the app back to the foreground. On Android this resumes a backgrounded app (or launches it if it is stopped). On iOS it relaunches the app, so in-memory state such as form input and the navigation stack is lost.
await device.bringToForeground("com.example.myapp");device.resetApp(options?): Promise<AppResetResult>
Section titled “device.resetApp(options?): Promise<AppResetResult>”Bring the app to a known state — the same reset the runner performs for the declared appReset policy, callable from inside a test. The daemon runs a ladder and reports which rung actually ran:
- warm — in-app reset through the app’s reset hook (
@tapsmith/react-nativemarker, orresetAppDeepLink), process kept; - restart — terminate and relaunch, data kept;
- clear — wipe app data and relaunch.
Note that on an app with no in-app reset hook, the default warm request falls back to restart, which keeps app data — pass mode: "clear" when you need an isolation-grade wipe.
Mid-test resets share the daemon’s warm-window state with the runner’s own resets and honour the same appResetColdEvery setting (default 10, 0 = off; a scope’s test.use({ appResetColdEvery }) applies to them too), so a warm resetApp() can come back as a cold relaunch with reason: "cold relaunch: warm-window bound reached (…)".
const result = await device.resetApp() // warm, falling back as neededawait device.resetApp({ mode: "clear", fallback: false }) // exactly a clear, or throwawait device.resetApp({ target: "/settings" }) // warm reset landing on a route| Option | Type | Default | Description |
|---|---|---|---|
mode |
'warm' | 'restart' | 'clear' |
'warm' |
How far to reset |
fallback |
boolean |
true |
Escalate warm → restart → clear when a rung fails |
target |
string |
'/' |
Route to land on after an in-app (warm) reset — it is the reset deep link’s path. A restart/clear rung leaves the app at its launch route; check targetReached and navigate if needed. |
AppResetResult
| Field | Type | Description |
|---|---|---|
modeRequested / modeUsed |
'warm' | 'restart' | 'clear' |
What was asked for and what actually ran |
fellBack |
boolean |
A lower rung ran because a higher one failed |
coldLaunch |
boolean |
The process was recreated — by a restart/clear rung, a cold-window relaunch, or a warm delivery that had to relaunch the app to land (the reason says which) |
reason |
string? |
Why a fallback or cold relaunch happened, e.g. "cold relaunch: warm-window bound reached (10 resets)" |
durationMs |
number |
Wall time of the whole ladder |
hooksDetected |
boolean |
@tapsmith/react-native hooks were found in the app |
epochBefore / epochAfter |
number? |
In-app reset counter (hooks only) |
targetReached |
boolean |
The app ended on target: an in-app reset was acknowledged on that route. false after a restart/clear rung (the app is at its launch route), and when the target screen hid the hooks marker, so the reset was confirmed on / instead |
steps |
{ name, durationMs, ok, detail? }[] |
Per-rung timings |
The call is recorded in the trace as a resetApp action whose detail line names the rung and reason. Throws when the ladder is exhausted (or fallback: false and the requested rung failed).
device.restartApp(packageName: string, options?: { waitForIdle?: boolean }): Promise<void>
Section titled “device.restartApp(packageName: string, options?: { waitForIdle?: boolean }): Promise<void>”Force-stops and relaunches the app without clearing persistent storage. Resets all in-memory state (React component state, navigation stack) while preserving data on disk (AsyncStorage, SQLite, SharedPreferences).
Use it in the middle of a test, for example to check that state survives a restart. To restart before every test, declare test.use({ appReset: "restart", appResetScope: "test" }) instead of a beforeEach that only restarts the app (the tapsmith/prefer-app-reset-option lint rule flags such a hook; see Test isolation):
test("remembers the signed-in user across a restart", async ({ device }) => { await device.getByRole("textfield", { name: "Email" }).type("user@example.com") await device.getByRole("textfield", { name: "Password" }).type("password123") await device.getByRole("button", { name: "Sign In" }).tap() await expect(device.getByText("Welcome back")).toBeVisible() await device.restartApp("com.example.myapp") await expect(device.getByText("Welcome back")).toBeVisible()})Options:
waitForIdle?— wait for the UI to settle after relaunch (default:true)
device.clearAppData(packageName: string): Promise<void>
Section titled “device.clearAppData(packageName: string): Promise<void>”Clear all app data and cache, providing test isolation similar to Playwright’s fresh browser context.
await device.clearAppData("com.example.myapp");- Android:
pm clear— wipes all persisted state, including the app’s Android Keystore keys. - iOS simulator: clears the app’s data container and the simulator’s keychain, so keychain-backed state (e.g. native Firebase Auth sessions,
expo-secure-storeitems) doesn’t survive a “full” clear. The simulator keychain is device-global, so this clears keychain items for every app on the simulator — fine for test-owned simulators. A keychain that holds no items beyond the twosecuritydcreates with it (so nothing any app or system service has stored since the last clear) is left as it is. Any other keychain is emptied in place withsimctl keychain reset(securitydkeeps running); only if that reset fails are the keychain files deleted andsecuritydrestarted. SetTAPSMITH_NO_KEYCHAIN_STATE=1to skip the keychain wipe. - iOS physical device: uninstalls and reinstalls the app bundle (iOS deletes the app’s keychain entries on uninstall).
device.saveAppState(packageName: string, path: string): Promise<void>
Section titled “device.saveAppState(packageName: string, path: string): Promise<void>”Snapshot the app’s persisted state and save it as a tar.gz archive on the host. The app is stopped before snapshotting to avoid data corruption.
- Android: archives the app’s data directory (
/data/data/<package>/) — SharedPreferences, databases, and internal files. Requires root (emulators) or a debuggable app (run-asfallback on physical devices). Keystore-backed values (EncryptedSharedPreferences,expo-secure-store, and many native auth SDKs) store only their ciphertext in the data directory; the decryption key lives in the Android Keystore, which is device-bound and not captured in the archive.restoreAppStatepreserves the Keystore (it clears the data directory in place rather than runningpm clear, which would wipe the app’s Keystore keys), so these values do round-trip across a save/restore on the same device. Limitation — cross-device / CI: an archive is not portable across devices. The Keystore key only exists on the device that saved the archive, so the restored ciphertext can’t be decrypted on a different device or CI runner, leaving the app unauthenticated. This applies even to auth SDKs that look like plain SharedPreferences: the Firebase Android SDK (used by@react-native-firebase/auth) persists its session token encrypted with a Tink keyset wrapped by an Android Keystore key. For cross-device/CI, mint auth state per device (run the login flow as a setup project on each device) or use API-driven auth (e.g. custom-token sign-in). - iOS simulator: archives the app’s data container plus the simulator’s keychain database (as a reserved
.tapsmith-keychainarchive member), so keychain-backed auth state (e.g. native Firebase Auth,expo-secure-store) round-trips correctly. SetTAPSMITH_NO_KEYCHAIN_STATE=1to disable keychain capture. Best-effort across iOS runtimes: a save/restore on the same simulator is fully supported; restoring an archive captured on a different iOS version is not guaranteed. - iOS physical device: archives the app’s data container only. The keychain is not host-accessible on physical devices, so keychain-backed state (e.g. native auth SDK credentials) is not captured — a warning is logged. Prefer API-driven auth (e.g. custom-token sign-in) for test setup on physical devices.
// Save authenticated state after loginawait device.saveAppState("com.example.myapp", "./auth-state.tar.gz");device.restoreAppState(packageName: string, path: string): Promise<void>
Section titled “device.restoreAppState(packageName: string, path: string): Promise<void>”Restore a previously saved app state archive. Clears the app’s data first, then extracts the archive.
- Android: clears the app’s data directory in place (rather than
pm clear) so the app’s Android Keystore keys survive — this is what lets Keystore-backed values (e.g. native auth tokens) decrypt after a restore on the same device. Then extracts the archive, fixing file ownership and SELinux contexts when running as root. SeesaveAppStatefor the cross-device limitation. - iOS simulator: clears and re-extracts the data container; if the archive contains keychain state, the simulator’s keychain is swapped to match and
securitydis restarted so the change takes effect. An archived keychain that holds no items is restored by clearing the simulator’s keychain instead, asclearAppDatadoes. The simulator keychain is device-global, so restoring swaps keychain state for every app on the simulator. Archives saved by older Tapsmith versions (without keychain state) restore exactly as before. SetTAPSMITH_NO_KEYCHAIN_STATE=1to skip the keychain swap. - iOS physical device: reinstalls the app and pushes the archived container contents (keychain state is not restored — see
saveAppState).
// Restore state instead of logging in againawait device.restoreAppState("com.example.myapp", "./auth-state.tar.gz");device.grantPermission(packageName: string, permission: string): Promise<void>
Section titled “device.grantPermission(packageName: string, permission: string): Promise<void>”Programmatically grant a permission. On Android, permission is a runtime permission name; on an iOS simulator, it is a service that xcrun simctl privacy accepts, such as photos, location, contacts, calendar or microphone (xcrun simctl help privacy lists them, and camera is accepted too; notifications are not). Some changes make iOS terminate the app if it is running. Not supported on physical iOS devices.
await device.grantPermission("com.example.myapp", "android.permission.CAMERA");await device.grantPermission("com.example.myapp", "android.permission.ACCESS_FINE_LOCATION");await device.grantPermission("com.example.myapp", "photos"); // iOS simulatordevice.revokePermission(packageName: string, permission: string): Promise<void>
Section titled “device.revokePermission(packageName: string, permission: string): Promise<void>”Revoke a previously granted permission. Takes the same permission values as grantPermission(), with the same platform support.
await device.revokePermission("com.example.myapp", "android.permission.CAMERA");device.setClipboard(text: string): Promise<void>
Section titled “device.setClipboard(text: string): Promise<void>”Set the device clipboard content.
await device.setClipboard("Hello, world!");device.getClipboard(): Promise<string>
Section titled “device.getClipboard(): Promise<string>”Read the current device clipboard content.
const text = await device.getClipboard();device.setOrientation(orientation: Orientation): Promise<void>
Section titled “device.setOrientation(orientation: Orientation): Promise<void>”Set the device orientation. Accepts "portrait" or "landscape".
await device.setOrientation("landscape");await device.setOrientation("portrait");device.getOrientation(): Promise<Orientation>
Section titled “device.getOrientation(): Promise<Orientation>”Get the current device orientation.
const orientation = await device.getOrientation(); // "portrait" | "landscape"device.isKeyboardShown(): Promise<boolean>
Section titled “device.isKeyboardShown(): Promise<boolean>”Check if the soft keyboard is currently visible. On iOS, the keyboard counts as shown only while part of it is on screen, which is the same check hideKeyboard() uses. A keyboard that is still sliding in gets a moment to arrive before the answer is false. When a hardware keyboard is connected to an iPhone simulator, iOS keeps the software keyboard off screen, so this returns false even while a text field has focus.
if (await device.isKeyboardShown()) { await device.hideKeyboard();}device.hideKeyboard(): Promise<void>
Section titled “device.hideKeyboard(): Promise<void>”Hide the soft keyboard if it is visible. Resolves at once when no keyboard is shown, or when the app is not in the foreground. On iOS it throws if the app is in front but its screen cannot be read, since it cannot tell whether a keyboard is up.
await device.hideKeyboard();On Android this presses BACK, which normally dismisses the soft keyboard. A BACK that the keyboard doesn’t answer goes on to the app and navigates back, so hideKeyboard() first checks that the keyboard and the app respond, and waits while they don’t. If they still don’t after about 15 s, it throws without pressing BACK.
iOS has no API that puts the keyboard away, so hideKeyboard() does what a user would. It tries these in order and stops as soon as the keyboard is gone:
- Drag the scroll view the focused field is in a few points, if it shows above the keyboard. The drag only starts from a spot clear of the scroll view’s controls. A scroll view beside the field (a list under a search bar) is not dragged, and neither is a web view.
- Tap the keyboard’s own dismiss key, where it has one (iPad).
- Tap a blank spot beside the focused field, above the keyboard, where no control, text, or image is drawn. The spot is inside the field’s own container, so a sheet’s backdrop is not tapped. This works on screens that dismiss the keyboard when you tap outside the field.
- Press the return key, but only in a single-line field whose return key reads “return” or “done”. This also submits the field, as it would for a user (React Native’s
onSubmitEditingfires). An action key such as “go”, “send”, “search” or “next” is never pressed, and neither is return in a multi-line field, where it would type a new line.
If the keyboard is still up after all of them, hideKeyboard() throws instead of reporting success. The error lists what it tried and why each step failed. Dismiss the keyboard the way your screen allows: tap its own Done or close button, or call device.pressKey("enter") if submitting the field is fine.
device.wake(): Promise<void>
Section titled “device.wake(): Promise<void>”Wake the device screen if it is off.
await device.wake();device.unlock(): Promise<void>
Section titled “device.unlock(): Promise<void>”Wake the screen and dismiss the lock screen. Works with non-secure lock screens (no PIN/pattern). Useful for CI and emulator setups. On Android the lock screen is only dismissed when it is actually showing, so calling this on an unlocked device never sends gestures to the foreground app.
await device.unlock();device.pressHome(): Promise<void>
Section titled “device.pressHome(): Promise<void>”Press the home button. Convenience method equivalent to device.pressKey("HOME").
await device.pressHome();device.openNotifications(): Promise<void> (Android only)
Section titled “device.openNotifications(): Promise<void> (Android only)”Pull down the notification shade.
await device.openNotifications();device.openQuickSettings(): Promise<void> (Android only)
Section titled “device.openQuickSettings(): Promise<void> (Android only)”Pull down the quick settings panel.
await device.openQuickSettings();device.pressRecentApps(): Promise<void> (Android only)
Section titled “device.pressRecentApps(): Promise<void> (Android only)”Open the recent apps screen. Convenience method equivalent to device.pressKey("APP_SWITCH").
await device.pressRecentApps();device.setColorScheme(scheme: ColorScheme): Promise<void> (Android only)
Section titled “device.setColorScheme(scheme: ColorScheme): Promise<void> (Android only)”Set the system UI mode. Accepts "dark" or "light".
await device.setColorScheme("dark");await device.setColorScheme("light");device.getColorScheme(): Promise<ColorScheme>
Section titled “device.getColorScheme(): Promise<ColorScheme>”Get the current system color scheme.
const scheme = await device.getColorScheme(); // "dark" | "light"device.close(): void
Section titled “device.close(): void”Close the gRPC connection to the daemon.

