Android monitoring agent for CashPilot that tracks passive income apps (EarnApp, IPRoyal Pawns, MystNodes, Traffmonetizer, Bytelixir, ByteBenefit, Grass, Titan Network, Nodle Cash, Uprock, Wipter) without root, reporting their status to the CashPilot fleet dashboard via periodic heartbeats.
- Kotlin 2.1+
- Jetpack Compose (Material 3)
- Ktor HTTP client
- Kotlinx Serialization
- DataStore Preferences
- Android SDK 26+ (minSdk), compileSdk 36, targetSdk 35
- Gradle with version catalogs (
libs.versions.toml) - ProGuard (release builds:
isMinifyEnabled = true,isShrinkResources = true)
# Build debug APK
./gradlew assembleDebug
# Run tests
./gradlew testNo local Java on macOS dev machine — all compilation is via GitHub Actions CI. Lint baseline at app/lint-baseline.xml — new lint errors are fatal.
- Package:
com.cashpilot.android - Version source of truth:
gradle.properties(VERSION_NAME,VERSION_CODE). CI overrides via-Pflags. - Release workflow: Push a
v*tag -> GitHub Actions builds signed APK+AAB, creates GitHub Release - CI workflow: On push to main -> debug APK + lint + signed release APK. On PR -> debug + lint only (no keystore access)
- Signing keystore: JKS at
~/repos/personal/keystores/cashpilot-release.jks(alias:cashpilot, password:cashpilot-release-2026). Base64-encoded in GitHub secretKEYSTORE_BASE64. - F-Droid: MR !35850 at gitlab.com/fdroid/fdroiddata. Metadata at
metadata/com.cashpilot.android.yml. UsesUpdateCheckDatato read version fromgradle.properties.
com.cashpilot.android/
├── model/ # Data classes (Heartbeat, AppStatus, MonitoredApp, Settings)
├── service/ # Android services (HeartbeatService, AppNotificationListener, AppDetector)
├── ui/ # Compose UI (MainActivity, screens, theme, components)
│ ├── screen/ # Full-screen composables (Dashboard, Settings)
│ ├── theme/ # Material 3 theme
│ └── component/ # Reusable composable components
└── util/ # Utilities (SettingsStore, formatters)
- HeartbeatService: Foreground service sending periodic HTTP POST to CashPilot server with app status. Uses Ktor client. Sticky service with boot receiver.
- AppNotificationListener: NotificationListenerService that detects when monitored apps have active foreground notifications. Primary detection mechanism — instant callback.
- AppDetector: Combines NotificationListener state with UsageStatsManager (last active time) and NetworkStatsManager (per-app bytes tx/rx) for complete app health picture.
- SettingsStore: DataStore-backed persistence for server URL, fleet API key, heartbeat interval, and enabled app list.
Three complementary APIs, no root required:
- NotificationListenerService — proves the app's foreground service is alive (instant)
- UsageStatsManager — last foreground time, ~2h bucket resolution
- NetworkStatsManager — per-app bandwidth in last 24h, proves data is flowing
POST to {serverUrl}/api/workers/heartbeat with bearer auth (fleet API key via CASHPILOT_API_KEY). Payload matches the server's WorkerHeartbeat schema (name, url, containers, system_info). Android-specific app status is packed into system_info.apps.
- Never hardcode the CashPilot server URL or API key
- Uses Bearer auth for server communication
- minSdk is 26 — guard any API 29+ calls with
Build.VERSION.SDK_INTchecks (lint enforces) - Use cancel-and-replace Job pattern for concurrent coroutine operations (see
refreshJobin MainViewModel) - Use
ensureActive()afterwithContext(Dispatchers.IO)blocks to discard stale results - Use
AppOpsManagerto check usage access permission (notUsageStatsManager.queryUsageStatsheuristic) - DataStore text field writes should be debounced (500ms per-field cancel-and-replace)
- POST_NOTIFICATIONS runtime permission must be requested on Android 13+
- License: GPL-3.0
11 passive income apps with verified Android package names defined in KnownApps.kt. All verified via adb shell pm list packages.
When adding new apps:
- Verify exact package name via
adb shell pm list packages | grep -i <name>— Play Store URLs are unreliable - Add to the
alllist inKnownApps - Add the package to
<queries>inAndroidManifest.xml(Android 11+ package visibility) - Update the README app count
Apps removed (APK-only, not on Play Store): Honeygain, PacketStream, Peer2Profit, GagaNode, PassiveApp, Repocket.
- ALWAYS install the release-signed APK (
app-release). NEVER use debug APK. Switching signatures requires full uninstall (wipes all app data). - Download from CI:
gh run download <run-id> --name app-release --dir /tmp/cashpilot-apk - Install:
adb install -r /tmp/cashpilot-apk/app-release.apk - If signature mismatch:
adb uninstall com.cashpilot.androidfirst
- Earnings collection on Android (server handles this)
- Auto-start monitored apps (requires accessibility service)
- Root-only features (Shizuku process enumeration)
- Widget — defer until core monitoring is solid
Generated by LynxPrompt CLI