Files
magnus919_agent-skills/mobile-development/references/android.md
T
Magnus HedemarkGitHubfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
f68721873e feat(skill): add mobile development skill (iOS / Android / Flutter / React Native) (#248) (#268)
ONE family skill covering iOS, Android, Flutter, and React Native with
per-framework references (ios.md, android.md, flutter.md, react-native.md),
shared scaffold/build/sign/test/ship workflow, mobile lifecycle, offline and
sync guidance, and mobile-specific testing. Ships a 5-heading human README and
a schema-v1 eval manifest with 6 cases covering build/sign, testing, and
store-readiness. Adds the README index entry and regenerates catalogs.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-03 19:48:20 -04:00

177 lines
8.3 KiB
Markdown

# Android Reference — Kotlin, Gradle, Google Play
> **Last Updated:** 2026-08-03
Load this reference when the target platform is **Android** — native Kotlin
apps built with Gradle, or an Android target inside a Flutter or React Native
project (tooling for those is in [flutter.md](flutter.md) and
[react-native.md](react-native.md); this file is the platform layer under
them). It complements the shared workflow in `SKILL.md`; this file is the
Android-specific detail for scaffolding, building and signing, emulator and
device testing, and Play Store submission.
## Android fundamentals
An Android app is a compiled, signed package built by Gradle:
- **Gradle project** — a project root with `settings.gradle(.kts)`, an `app`
module with `build.gradle(.kts)`, and `gradle/libs.versions.toml` for version
catalog dependency management. Kotlin DSL (`.kts`) is the current default.
- **Manifest** — `AndroidManifest.xml` declares the application, activities,
services, receivers, permissions, and the minimum/target SDK.
- **Build outputs** — `assembleDebug`/`assembleRelease` produce APKs;
`bundleRelease` produces an **Android App Bundle (AAB)**, the required
submission format for new apps on Google Play (since 2021, and still the
rule). Google Play derives per-device APKs from the AAB via **Play App
Signing**.
- **Gradle wrapper** — commit `gradlew` and `gradle/wrapper/` so builds use a
pinned Gradle version on every machine and CI runner.
Keep the version name (`versionName`) and version code (`versionCode`, a
monotonic integer) in `build.gradle.kts` — Play rejects a build whose version
code is lower than a previous upload.
## Scaffolding
- **New native app** — create the project in Android Studio or with the Gradle
template (`gradle init`); choose Kotlin and Jetpack Compose for new UI.
- **Minimum and target SDK** — set `minSdk` to the oldest Android version in
scope and keep `targetSdk` current; Play enforces minimum target API levels
for new and updated submissions, and raised target levels are announced
annually.
- **Dependencies** — prefer version catalogs (`libs.versions.toml`) and commit
the lockfile (`gradle.lockfile` or dependency locking) for reproducibility.
- **App structure** — a single-activity app with Compose navigation for new
work; keep the manifest minimal and declare only the permissions the app
actually uses.
## Builds and signing
### Signing model
- **Local signing** — a Java keystore (`.jks`/`.keystore`) with an alias,
configured via `signingConfigs` in `build.gradle.kts`. Signing configs must
never be committed with their passwords; read them from environment
variables or a secrets store at build time.
- **Play App Signing** — Google holds the app signing key; the **upload key**
you sign with is only used to upload the AAB to Play. Upload keys can be
rotated without user-visible changes; losing the upload key requires Play
Console support intervention.
- **Keystore custody** — the release keystore is a production secret: back it
up, store it outside the repository, and restrict access. Losing it means
the app can no longer be updated under the same identity.
### Signing practices
- **Debug builds sign automatically** with the debug keystore — never ship
them.
- **Release builds in CI** — inject keystore path, passwords, and aliases via
CI secrets; keep `keystore.properties` (or equivalent) out of version
control. Use `signingConfig` referenced from a file that CI can generate.
- **Two build types** — `debug` and `release` differ in signing, shrinking
(R8/ProGuard), and manifest merging. Smoke-test the signed release artifact,
not just the debug build.
### Build commands
```sh
# Debug APK (fast iteration)
./gradlew assembleDebug
# Release APK (signed, shrunk)
./gradlew assembleRelease
# Release App Bundle (required for Play Store submission)
./gradlew bundleRelease
```
The AAB lives in `app/build/outputs/bundle/release/`; the signed APK in
`app/build/outputs/apk/release/`. Verify the APK signature with
`apksigner verify --print-certs app-release.apk` before distribution.
## Emulators and devices
- **Emulators (AVD)** — Android Studio AVD Manager creates virtual devices;
headless emulators are scriptable for CI:
```sh
emulator -avd Pixel_8 -no-window -no-audio -no-boot-anim &
adb wait-for-device
adb install app/build/outputs/apk/debug/app-debug.apk
adb shell am start -n com.example.app/.MainActivity
```
- **Physical devices** — enable USB debugging and use `adb devices` to verify
the connection; real devices reveal networking, battery, and sensor
behavior the emulator hides.
- **Debugging** — `adb logcat` for logs, `adb shell dumpsys` for system
state, and Android Studio Profiler for CPU/memory/network. `adb reverse`
maps device ports to the host for local API servers.
- **Device matrix** — cover the min SDK, the current SDK, and a mid-range
device; use Firebase Test Lab (or a farm) for broad matrix coverage without
local hardware.
## Lifecycle and backgrounding
- **Component lifecycle** — Activities/Fragments move through
started/paused/stopped states; ViewModels survive configuration changes and
should own UI state. `Process death` can destroy everything else.
- **State persistence** — save and restore instance state (`SavedStateHandle`,
`rememberSaveable` in Compose) for process death; persist anything important
to a durable store.
- **Background work is restricted** — Android restricts background execution
and network. Use `WorkManager` for deferrable, guaranteed work, and
foreground services (with a visible notification) only for user-visible
tasks. `AlarmManager` is for alarms, not general scheduling.
- **Doze and app standby** — the system batches background work when idle;
test offline sync and push handling under Doze, not just with the screen on.
## Offline and sync
- **Local persistence** — Room (SQLite ORM) for structured data, DataStore
(Preferences/Proto) for settings, and file storage under the app's
internal/external storage. Keep the database schema versioned with
migrations tested.
- **Sync pattern** — write locally, then sync: queue writes, replay them with
retry and backoff when connectivity returns, and resolve conflicts
explicitly. `WorkManager` with network constraints is the idiomatic sync
trigger.
- **Connectivity** — use `ConnectivityManager`/NetworkCallback to observe
connectivity, but design for a lost network degrading gracefully.
## Testing
- **Unit tests** — JUnit + MockK/mockito for logic; Robolectric runs
Android-framework code on the JVM for fast local tests.
- **Instrumented/UI tests** — Espresso (Views) or Compose UI tests
(`createAndroidComposeRule`) drive the real app on an emulator/device.
- **Snapshot tests** — Compose Preview-based snapshot testing (e.g.,
Roborazzi, Paparazzi) catches UI regressions without a device.
- **Device farms** — run the instrumentation suite on Firebase Test Lab
across the device matrix; a test passing on one API level is not a
guarantee across them.
## Store submission
1. **Play Console setup** — the $25 developer account, app record, and
developer verification (new developers complete identity verification and
a closed-test requirement with at least 12 testers for 14 days before
production access).
2. **Upload the AAB** — upload `app-release.aab` to an internal, closed, or
open testing track first; run internal testing with your own devices before
production. Play generates and signs per-device APKs via Play App Signing.
3. **Store listing and policies** — screenshots, feature graphic, privacy
policy URL, and a **data safety** declaration matching what the app
collects. Play policy review rejects apps for undeclared data collection,
broken core functionality, and misleading metadata.
4. **Staged rollout** — use phased rollouts (e.g., 10% → 50% → 100%) and
monitor crash and ANR rates in Play Console before full release. Pause the
rollout immediately if a serious regression appears.
## Key references
- Google Play Console help and policy center (support.google.com/googleplay)
— current data-safety and testing-track requirements.
- Android developer documentation (developer.android.com) — target API
level deadlines and app bundle guidance change annually.