← Platforms

Android SDK (Kotlin)

Remote debugging for Android: your AI coding tool inspects the View and Compose trees, injects real taps, swipes and text, and reads logcat on a physical device — over one wss connection, from anywhere.

The Android client is a single Kotlin module published as an AAR on JitPack. Integration is one call in Application.onCreate; from there the library handles heartbeat, reconnection and dispatch, and exposes 20 built-in tasks the AI calls synchronously through MCP. Views and Compose land in the same tree snapshot, so the AI never needs to know which toolkit drew the screen.

What it gives your AI

One tree for View + Compose

ui_traverse returns the view hierarchy and the Compose semantics tree in a single snapshot (flat, cap 3000 nodes), each node with path, class, text, id, bounds, visibility and clickability.

Real input, not mocks

ui_click dispatches a full touch sequence on the target's own window root, so dialogs, popups and overlay masks get the event like a real finger. swipe keeps ~16 ms intermediate moves, so fling inertia works.

Locate and act in one call

Since v0.2.2 every write task takes a path, or locates the node atomically by text / id / desc / testTag (+index) with the same filters as find_objects.

Logcat with history

read_logs reads the app's own logcat buffer, so entries from before the SDK connected are still there. Filter by level, substring, sinceMs and limit.

Performance and app state

get_perf reports Java/native heap, PSS, battery, threads and Choreographer-sampled fps with frame-time percentiles; get_state the activity stack, Fragment tree, permissions and network.

Screenshots as real images

screenshot renders the current Activity window to JPEG and returns a native image block, shrinking quality and size to fit the message budget.

Requirements

Install from JitPack

Add the JitPack repository and the dependency, pinned to a release tag (recommended) or tracking the latest one:

repositories {
    maven { url 'https://jitpack.io' }
}
dependencies {
    implementation 'com.github.omnidebuglink:omnidebuglink_android:v0.2.2'  // pinned (recommended)
    // or always the latest release tag:
    // implementation 'com.github.omnidebuglink:omnidebuglink_android:latest.release'
}

Get started

1

Create a device token pair

In the OmniDebugLink console, create a token pair for this device. One token pair = one device — give every device you want to debug its own pair.

2

Add the dependency

JitPack repository plus the AAR, as shown above.

3

Start the client in Application.onCreate

One line, that's it. Reconnect, heartbeat and task dispatch are handled for you.

// Application.onCreate — one line, that's it
OmniDebugLink.start(this, "<clientToken>")

// read-only observation mode, if you want it:
OmniDebugLink.actionsEnabled = false

Pass the Application context so the library can track the activity stack; OmniDebugLink.stop() shuts it down.

4

Point your AI tool at the MCP server

No token to paste into the tool — sign in with your account in a browser on first use, and the AI can drive every device under your account.

claude mcp add --transport http odl \
  "https://api.omnidebuglink.dev/mcp"

Built-in tasks (20)

The library announces its task list on connect, so the AI always sees exactly what this device can do. Read tasks:

TaskWhat it does
ui_traverseView + Compose semantics tree dump in one snapshot (flat, cap 3000 nodes), each node with path, class, text, id, bounds, visibility, clickability.
find_objectsSubstring search (case-insensitive) by text / id / desc / testTag / cls — cheaper than a full dump when locating one control.
view_componentOne node in depth: properties, children paths, plus reflection-scanned readable fields.
wait_forPolls every 200 ms until a node matching text/id/desc/testTag appears; on timeout it returns found: false instead of an error.
screenshotCurrent Activity window rendered from the view tree as JPEG; quality and size shrink automatically to fit the frame budget.
read_logsThe app's own logcat buffer — full history while the buffer holds it, with level / contains / sinceMs / limit filters.
get_perfJava/native heap, PSS, battery, thread count, and optional Choreographer-sampled fps with frame-time percentiles.
get_stateActivity stack and recent history, current intent, Fragment tree, screen metrics, granted permissions, network status.
prefsSharedPreferences: read side is get / list (the same task also writes — see below).

Write tasks — every one is gated by actionsEnabled:

TaskWhat it does
ui_clickPhysical delivery since v0.2.1: a full touch sequence at the view's center on its own window root, so Dialog/PopupWindow targets resolve correctly and overlays receive the tap like a real one. Locates by path or atomically by text/id/desc/testTag (+index) since v0.2.2; falls back to performClick() for zero-size views; Compose nodes go through the accessibility action channel.
tap_screenTap at normalized 0-1 coordinates (top-left origin) through the real touch pipeline on the decorView.
swipeDrag between two points over durationMs with ~16 ms intermediate moves, so scroll/fling inertia works.
long_pressPress and hold (default 800 ms) then release — triggers long-click where a plain click would not.
input_textSet text on TextView/EditText (TextWatchers fire normally) or on Compose nodes via accessibility.
set_componentMutate a View node: text / visibility / enabled / selected. Compose nodes are not settable this way — use input_text or ui_click.
send_keyback / home / recents / menu / volume / dpad / enter and more. Back is delivered through activity dispatch and is reliable; home/recents may be rejected by the OS.
launch_intentStart an Activity by deep link (uri), explicit component, or action — handy as the entry point of an automated flow.
prefsWrite / delete SharedPreferences with value-type coercion.

Basics every client answers: echo, ping, get_stats. prefs appears in both tables above because it is one task with a read and a write side — 9 + 9 rows minus that duplicate is the 20 built-in tasks.

Jetpack Compose support

Compose needs no extra dependency and no setup. When the bridge detects a AndroidComposeView it walks the semantics owner and merges Compose nodes into the same snapshot as the View tree. They are addressed as /<semantics node id> alongside normal View paths, and the text, content description, test tag, click and disabled flags come straight from the semantics configuration.

Interacting with Compose nodes goes through the accessibility action channel rather than View.performClick(), which is why ui_click and input_text work on them at all. set_component is View-only and says so if you point it at a Compose node.

Addressing and coordinates

Worth knowing