# 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 --install` > > **Linux 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 ```bash # 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 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 dev` in `frontend-react/`) - React/TS changes hot-reload instantly without restarting - Go changes (in `app.go`, `backend-go/`) require re-running `dev.sh` > **When to re-run `dev.sh` vs 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-run `dev.sh` to rebuild Go + regenerate bindings > - Edited anything under `backend-go/` → re-run `dev.sh` to rebuild **Frontend only** (browser preview, no Wails bindings): ```bash 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 bash scripts/build.sh ``` Or manually: ```bash # 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 ```bash cd backend-go go build ./... ``` --- ### Frontend only (static bundle) ```bash cd frontend-react npm run build # Output: desktop/frontend/dist/ ``` --- ### Android SDK ```bash cd android-sdk ./gradlew :sdk:assembleDebug # debug AAR ./gradlew :sdk:assembleRelease # release AAR # Output: android-sdk/sdk/build/outputs/aar/ ``` --- ## Type Checking (no build) ```bash # 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`: ```bash 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 1. Add the method to `desktop/app.go` (must be exported, receiver `*App`) 2. Run `wails generate module` from `desktop/` 3. Import from `@/wailsjs/go/main/App` in React ### Adding a new backend-go package 1. Create the package under `backend-go/` 2. The `go.work` workspace + `replace` directive in `desktop/go.mod` handle local resolution — no publishing needed ### Active device scoping (all features) - Import `useActiveDevice` from `@/hooks/use-active-device` - Check `isMonitoring` before starting streams or polls - Store per-device data in `deviceCache` via `patchDeviceCache(deviceId, data)` — never cleared on device switch - Show `` when `!isMonitoring` --- ## ADB Binary Bundling For **local development** the app resolves ADB in this order: 1. Embedded binary in `desktop/internal/adbembed/bin/` (empty until `download-adb.sh` is run) 2. `$ANDROID_HOME/platform-tools/adb` 3. `adb` on `$PATH` For **distribution builds** run `scripts/download-adb.sh` once before `wails build` to embed ADB for all platforms.