apps/android/README.md
Status: extremely alpha. The app is actively being rebuilt from the ground up.
Setup Code + Manual modesapps/android.cd apps/android
./gradlew :app:assemblePlayDebug
./gradlew :app:installPlayDebug
./gradlew :app:testPlayDebugUnitTest
cd ../..
bun run android:bundle:release
Third-party debug flavor:
cd apps/android
./gradlew :app:assembleThirdPartyDebug
./gradlew :app:installThirdPartyDebug
./gradlew :app:testThirdPartyDebugUnitTest
bun run android:bundle:release auto-bumps Android versionName/versionCode in apps/android/app/build.gradle.kts, then builds two signed release bundles:
apps/android/build/release-bundles/openclaw-<version>-play-release.aabapps/android/build/release-bundles/openclaw-<version>-third-party-release.aabFlavor-specific direct Gradle tasks:
cd apps/android
./gradlew :app:bundlePlayRelease
./gradlew :app:bundleThirdPartyRelease
pnpm android:lint
pnpm android:format
Android framework/resource lint (separate pass):
pnpm android:lint:android
Direct Gradle tasks:
cd apps/android
./gradlew :app:ktlintCheck :benchmark:ktlintCheck
./gradlew :app:ktlintFormat :benchmark:ktlintFormat
./gradlew :app:lintDebug
gradlew auto-detects the Android SDK at ~/Library/Android/sdk (macOS default) if ANDROID_SDK_ROOT / ANDROID_HOME are unset.
cd apps/android
./gradlew :benchmark:connectedDebugAndroidTest
Reports are written under:
apps/android/benchmark/build/reports/androidTests/connected/Deterministic startup measurement + hotspot extraction with compact CLI output:
cd apps/android
./scripts/perf-startup-benchmark.sh
./scripts/perf-startup-hotspots.sh
Benchmark script behavior:
StartupMacrobenchmark#coldStartup (10 iterations).apps/android/benchmark/results/.--baseline <old-benchmarkData.json>).Hotspot script behavior:
simpleperf data for .MainActivity.perf.data path for deeper follow-up if needed.adb devices -l
pnpm android:install
pnpm android:run
If adb devices -l shows unauthorized, re-plug and accept the trust prompt again.
Use adb reverse so Android localhost:18789 tunnels to your laptop localhost:18789.
Terminal A (gateway):
pnpm openclaw gateway --port 18789 --verbose
Terminal B (USB tunnel):
adb reverse tcp:18789 tcp:18789
Then in app Connect → Manual:
127.0.0.118789This app is native Kotlin + Jetpack Compose.
minSdk=31 already meets API requirement).pnpm android:run).__openclaw__/canvas/ (see docs/platforms/android.md).pnpm openclaw gateway --port 18789 --verbose
openclaw devices list
openclaw devices approve <requestId>
More details: docs/platforms/android.md.
API 33+): NEARBY_WIFI_DEVICESACCESS_FINE_LOCATION (required for NSD scanning)POST_NOTIFICATIONSCAMERA for camera.snap and camera.clipRECORD_AUDIO for camera.clip when includeAudio=trueAs of March 19, 2026, these manifest permissions are the main Google Play policy risk for this app:
READ_SMSSEND_SMSREAD_CALL_LOGWhy these matter:
Permissions Declaration Form, policy justification, and demo video evidence in Play Console.Current OpenClaw Android implication:
play: removes READ_SMS, SEND_SMS, and READ_CALL_LOG, and hides SMS / Call Log surfaces in onboarding, settings, and advertised node capabilities.thirdParty: keeps the full permission set and the existing SMS / Call Log functionality.Policy links:
Other Play-restricted surfaces to watch if added later:
ACCESS_BACKGROUND_LOCATIONMANAGE_EXTERNAL_STORAGEQUERY_ALL_PACKAGESREQUEST_INSTALL_PACKAGESAccessibilityServiceReference links:
This suite assumes setup is already done manually. It does not install/run/pair automatically.
Pre-req checklist:
openclaw nodes status shows it as paired + connected.OPENCLAW_SKIP_CANVAS_HOST=1; startup logs should include canvas host mounted at .../__openclaw__/).pairing required, approve latest pending device pairing request, then rerun:openclaw devices list
openclaw devices approve --latest
Run:
pnpm android:test:integration
Optional overrides:
OPENCLAW_ANDROID_GATEWAY_URL=ws://... (default: from your local OpenClaw config)OPENCLAW_ANDROID_GATEWAY_TOKEN=...OPENCLAW_ANDROID_GATEWAY_PASSWORD=...OPENCLAW_ANDROID_NODE_ID=... or OPENCLAW_ANDROID_NODE_NAME=...What it does:
node.describe command list from the selected Android node.screen.record in this suite (Android requires interactive per-invocation screen-capture consent).sms.send and notifications.actions).Common failure quick-fixes:
pairing required before tests start:
openclaw devices approve --latest) and rerun.A2UI host not reachable / A2UI_HOST_NOT_CONFIGURED:
NODE_BACKGROUND_UNAVAILABLE: canvas unavailable:
This Android app is currently being rebuilt. Maintainer: @obviyus. For issues/questions/contributions, please open an issue or reach out on Discord.