This repo is the Android client of MasterDnsVPN. The upstream Go core lives
under cmd/ and internal/; the bridge to Android is under mobile/. Plan
executors (e.g. dispatched by the /improve skill) and human contributors
should follow the conventions below.
| Path | Role | Edit policy |
|---|---|---|
android/ |
Gradle Android app: Kotlin + Jetpack Compose + Hilt + Room + DataStore. minSdk 21, compileSdk 36, JDK 17. |
Free to edit. |
mobile/ |
Go gomobile bridge. mobile.go exports mobile.Mobile.* to Kotlin via gomobile bind. mobile/tun/ is the FakeDNS proxy + DNS mapper. |
Free to edit. Rebuild AAR after. |
cmd/, internal/ |
Upstream Go core. | DO NOT EDIT in Android-client plans. The script android/build_go_mobile.sh auto-traps if go.mod/go.sum are touched. |
scripts/, docker/, assets/ |
Server-side tooling. | Out of scope for the Android client. |
plans/ |
Advisor plan files + this index. | Executors update their row in plans/README.md when done. |
.github/workflows/ |
CI: android-ci.yml (Debug APK + AAR), go-test.yml (Go tests, mobile/ top-level excluded), release-manual.yml (signed release). |
Edit when adding CI steps (e.g. lint, tests). |
All commands run from the repository root unless noted.
# Build the gomobile AAR (writes android/app/libs/masterdnsvpn.aar; pinned via android/gomobile.version)
bash ./android/build_go_mobile.sh
# Build the debug APK (AAR must already exist)
cd android && ./gradlew :app:assembleDebug
# Run the Go tests that CI runs (top-level mobile/ package is excluded)
go test $(go list ./... | grep -v -e '^masterdnsvpn-go$' -e '^masterdnsvpn-go/mobile$')
# Typecheck Kotlin (no dedicated script — assembleDebug IS the typecheck)
cd android && ./gradlew :app:compileDebugKotlinThere is currently no Android lint task, no ktlint/detekt plugin, and no
Kotlin unit-test or instrumented-test suite. Plans that need verification on
the Kotlin side must add the scaffolding first (see plans/005-kotlin-test-baseline.md).
go.modandgo.sumare immutable from the Android side. The scriptandroid/build_go_mobile.shruns in an isolatedmktemptree precisely so the real root files are not perturbed, and traps on changes:If a plan appears to require editingif ! git diff --quiet -- go.mod go.sum; then echo "ERROR: gomobile build modified shared Go module files." exit 1 figo.mod/go.sum, stop and report back — the upstream core owns those files.- The Go bridge
mobile/mobile.gotop-level package is excluded fromgo-test.yml(grep -v '^masterdnsvpn-go/mobile$'). Do not add Go files tomobile/expecting CI to test them automatically; either add a test file inmobile/AND remove the exclusion, or scope the file tomobile/tun/. - The FakeDNS code path is Go-side (
mobile/tun/fakedns_proxy.go), NOT the legacy Kotlindns/FakeDnsServer.kt/FakeDnsInterceptor.kt. The Kotlindns/package is dead code perplans/007-delete-dead-code.md. Do not re-wire Kotlin-side FakeDNS; do not import fromcom.masterdns.vpn.dns.
- Kotlin ViewModel: use Hilt
@HiltViewModel constructor(...). Expose StateFlow via... .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), defaultValue). Exemplar:ui/home/HomeViewModel.kt. - Room entity + DAO: exemplar
data/local/ProfileEntity.kt+ProfileDao.kt. - Compose screen: exemplar files in
ui/<feature>/. UseMdvColorfromui/theme/MdvTokens.ktfor colors — do not hardcode hex. - DI: Hilt module under
di/. Exemplar:di/AppModule.kt. - Error handling: prefer
runCatching { }.onFailure { }for I/O / IPC; swallow only with a loggedVpnManager.appendLog(...)call. - Commit style: conventional commits, lowercase, scope in parens
(
fix(vpn):,feat(ui):,chore:,docs:). Seegit log --oneline -15for recent examples.
Local signed release (cd android && ./gradlew :app:assembleRelease):
ANDROID_SIGNING_ENABLED=trueANDROID_KEYSTORE_PATH,ANDROID_KEYSTORE_PASSWORD,ANDROID_KEY_ALIAS,ANDROID_KEY_PASSWORD- Optional:
ANDROID_VERSION_NAME,ANDROID_VERSION_CODE
CI signed release (.github/workflows/release-manual.yml):
ANDROID_KEYSTORE_BASE64(decoded toandroid/release.jksby the workflow)
Do NOT commit keystores or AARs — both are gitignored per plans/001-gitignore-android-entries.md.
See plans/README.md for the active plan list, execution order, and status.