7.3 KiB
DroidScope — Development Guide
Prerequisites
| Tool | Version | Install |
|---|---|---|
| Go | 1.23+ | https://go.dev/dl |
| Node.js | 20+ | https://nodejs.org |
| Wails CLI | v2 | go install github.com/wailsapp/wails/v2/cmd/wails@latest |
| Git | any | — |
macOS only: Wails requires Xcode Command Line Tools —
xcode-select --installLinux only: Wails requires
libgtk-3-dev libwebkit2gtk-4.0-dev(Debian/Ubuntu) or equivalent.Windows only: Wails requires WebView2 (ships with Windows 11, otherwise install from Microsoft).
First-time Setup
# 1. Install frontend dependencies
cd frontend-react
npm install
# 2. (Optional) Download bundled ADB binaries for distribution builds
# Skip this for local dev — the app falls back to your system ADB
bash scripts/download-adb.sh
# 3. Make sure your system ADB is accessible for local dev
# Either via ANDROID_HOME or PATH:
export ANDROID_HOME=~/Library/Android/sdk # macOS example
# or: ensure `adb` is on your PATH
Running in Development
bash scripts/dev.sh
What dev.sh does, in order:
| Step | Command | What it checks |
|---|---|---|
| 1 | go build ./... in backend-go/ |
Backend packages compile without errors |
| 2 | go build ./... in desktop/ |
Desktop Go code (app.go, main.go, embeds) compiles |
| 3 | wails generate module in desktop/ |
Regenerates frontend-react/src/wailsjs/ from current app.go bindings |
| 4 | npm install + tsc -b --noEmit in frontend-react/ |
Installs any new deps, type-checks TypeScript |
| — | wails dev in desktop/ |
Starts the desktop app with hot reload |
If any step fails the script exits immediately (due to set -e) — fix the error and re-run.
What happens once running:
- Wails compiles the Go backend and opens a native desktop window
- Wails starts the Vite dev server (
npm run devinfrontend-react/) - React/TS changes hot-reload instantly without restarting
- Go changes (in
app.go,backend-go/) require re-runningdev.sh
When to re-run
dev.shvs just saving a file:
- Edited only
.tsx/.ts/.css→ Vite hot-reloads automatically, no restart needed- Edited
app.go(added/changed a bound method) → re-rundev.shto rebuild Go + regenerate bindings- Edited anything under
backend-go/→ re-rundev.shto rebuild
Frontend only (browser preview, no Wails bindings):
cd frontend-react
npm run dev
# → http://localhost:5173
Wails bindings (
ListDevices,GetDeviceInfo, etc.) are no-ops in plain browser mode — they only work inside the Wails desktop window.
Building for Production
Full desktop app (recommended)
bash scripts/build.sh
Or manually:
# Step 1 — build frontend (outputs to desktop/frontend/dist/)
cd frontend-react
npm run build
# Step 2 — build desktop binary (embeds frontend dist + ADB binaries)
cd desktop
export PATH="$PATH:$(go env GOPATH)/bin"
wails build
Output: desktop/build/bin/DroidScope (macOS/Linux) or desktop/build/bin/DroidScope.exe (Windows)
Backend only
cd backend-go
go build ./...
Frontend only (static bundle)
cd frontend-react
npm run build
# Output: desktop/frontend/dist/
Android SDK
cd android-sdk
./gradlew :sdk:assembleDebug # debug AAR
./gradlew :sdk:assembleRelease # release AAR
# Output: android-sdk/sdk/build/outputs/aar/
Type Checking (no build)
# TypeScript
cd frontend-react
npx tsc -b --noEmit
# Go
cd backend-go && go build ./...
cd desktop && go build ./...
Regenerating Wails JS Bindings
Run this after adding or changing any exported method on App in desktop/app.go:
cd desktop
export PATH="$PATH:$(go env GOPATH)/bin"
wails generate module
# Output: frontend-react/src/wailsjs/
Project Structure
DroidScope/
├── desktop/ ← Wails app (Go entry point)
│ ├── app.go ← Wails-bound methods (called from frontend)
│ ├── main.go ← App bootstrap
│ ├── wails.json ← Wails config (frontend dir, dev server)
│ └── internal/adbembed/ ← ADB binary embedding + runtime extraction
│
├── backend-go/ ← Go backend packages
│ ├── adb/ ← ADB command wrapper
│ ├── device/ ← Device manager + DeviceInfo fetcher
│ ├── logcat/ ← (stub) Logcat streaming
│ ├── network/ ← (stub) Network inspector
│ ├── storage/ ← (stub) SharedPrefs, SQLite, files
│ ├── runtime/ ← (stub) Runtime config override
│ ├── session/ ← (stub) Session management
│ └── protocol/ ← Shared event types (Go structs)
│
├── frontend-react/ ← Vite + React + TypeScript
│ ├── src/
│ │ ├── wailsjs/ ← Auto-generated Wails bindings (do not edit)
│ │ ├── features/ ← Feature modules (devices, logcat, network…)
│ │ ├── components/ ← Shared UI components (layout, shadcn/ui)
│ │ ├── hooks/ ← Shared hooks (useActiveDevice)
│ │ ├── store/ ← Zustand global state
│ │ └── types/ ← Shared TypeScript types (protocol)
│ └── vite.config.ts ← Build outputs to ../desktop/frontend/dist/
│
├── android-sdk/ ← Kotlin Android SDK (Gradle)
│ └── sdk/src/main/kotlin/dev/achmad/droidscope/
│
├── scripts/
│ ├── dev.sh ← Start full dev environment
│ ├── build.sh ← Production build
│ └── download-adb.sh ← Download ADB binaries for bundling
│
├── go.work ← Go workspace (links desktop + backend-go)
├── README.md ← Project overview and feature roadmap
└── docs/
├── DEVELOPMENT.md ← This file
└── TODO.md ← Implementation status
Key Conventions
Adding a new Go method callable from the frontend
- Add the method to
desktop/app.go(must be exported, receiver*App) - Run
wails generate modulefromdesktop/ - Import from
@/wailsjs/go/main/Appin React
Adding a new backend-go package
- Create the package under
backend-go/ - The
go.workworkspace +replacedirective indesktop/go.modhandle local resolution — no publishing needed
Active device scoping (all features)
- Import
useActiveDevicefrom@/hooks/use-active-device - Check
isMonitoringbefore starting streams or polls - Store per-device data in
deviceCacheviapatchDeviceCache(deviceId, data)— never cleared on device switch - Show
<NoDeviceSelected />when!isMonitoring
ADB Binary Bundling
For local development the app resolves ADB in this order:
- Embedded binary in
desktop/internal/adbembed/bin/(empty untildownload-adb.shis run) $ANDROID_HOME/platform-tools/adbadbon$PATH
For distribution builds run scripts/download-adb.sh once before wails build to embed ADB for all platforms.