--- name: android-dev description: "Production-grade Android app development guide covering native (Kotlin/Java), cross-platform (Flutter, RN, KMM), and hybrid architectures." risk: safe source: community date_added: "2026-06-08" --- # Android App Development Skill ## Overview This skill guides production-grade Android and cross-platform (non-iOS) app development following practices used at big tech companies. It covers the entire development lifecycle — architecture, UI, code quality, testing, error handling, release, and maintenance. ## When to Use This Skill - Use when deciding on a tech stack (see §1 Stack Selection) - Use when setting up project architecture (see §2 Architecture) - Use when designing UI, screens, or a design system (see §3 UI & Design) - Use when ensuring code quality, patterns, or APIs (see Best Practices) - Use when implementing error handling or debugging crashes (see §5 Error Handling) - Use when planning testing strategy (see §6 Testing) - Use when configuring build, CI/CD, or release pipelines (see §7 Build & Release) - Use when optimizing performance or memory (see §8 Performance) - Use when debugging or fixing bugs (see §9 Debugging) - Use when following the full development roadmap (see §10 Development Roadmap) - Use when needing deep reference for a stack (see `references/` directory) --- ## §1 Stack Selection Choose based on team, requirements, and platform targets. **Do not recommend iOS-specific paths.** ### Native Android — Kotlin + Jetpack Compose **Best for:** Android-only apps, hardware-intensive features, best-in-class UX, new projects. - Language: **Kotlin** - UI: **Jetpack Compose** (modern declarative UI) - Key libs: Room, Retrofit/Ktor, Hilt, WorkManager, DataStore, Navigation Compose - Reference: `references/native-android.md` ### Native Android — Java + XML Views **Best for:** Existing Java codebases, teams without Kotlin experience, legacy app maintenance, incremental Kotlin migration. - Language: **Java** (fully supported by Google, not deprecated) - UI: **XML Layouts** (ConstraintLayout, RecyclerView, ViewBinding) - Key libs: Room, Retrofit, Hilt, WorkManager, LiveData, ViewModel - Java and Kotlin **coexist seamlessly** in the same project — migrate incrementally - Reference: `references/java-android.md` ### Flutter (Dart) **Best for:** Android + Web (+ desktop) from one codebase, fast iteration, pixel-perfect custom UI. - Language: **Dart** - UI: Flutter Widget tree (Material 3 / Cupertino widgets available but target Material for Android) - Key libs: Provider/Riverpod/Bloc, Dio, Drift/Isar, go_router, flutter_local_notifications - Reference: `references/flutter.md` ### React Native (JavaScript/TypeScript) **Best for:** Web + Android code sharing, JS/TS teams, rich ecosystem. - Language: **TypeScript** (preferred) - UI: React Native core components + NativeWind / React Native Paper - Key libs: React Navigation, Zustand/Redux Toolkit, React Query, MMKV - Reference: `references/react-native.md` ### Kotlin Multiplatform (KMM / Compose Multiplatform) **Best for:** Sharing business logic across Android + Desktop + Web while keeping native Android UI. - Language: **Kotlin** everywhere - UI: Native Compose on Android; Compose Multiplatform for shared UI - Key libs: Ktor, SQLDelight, Koin, kotlinx.serialization, Napier - Reference: `references/kmm.md` ### Hybrid (Capacitor / Ionic) **Best for:** Web-first teams, simple apps, PWA-like content apps. - Language: TypeScript + HTML/CSS - UI: Ionic components or custom web UI - Avoid for: Heavy animations, native sensor access, high-performance games - Reference: `references/hybrid.md` ### Decision Matrix | Requirement | Native Kotlin | Native Java | Flutter | RN | KMM | Hybrid | |---|---|---|---|---|---|---| | Android-only (new) | ✅ Best | ✅ | ✅ | ✅ | ✅ | ✅ | | Android-only (existing Java) | ⚠️ migrate | ✅ Best | ❌ | ❌ | ⚠️ | ❌ | | Android + Web | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ Best | | Android + Desktop | ❌ | ❌ | ✅ | ⚠️ | ✅ | ⚠️ | | Shared business logic only | N/A | N/A | N/A | N/A | ✅ Best | N/A | | Native performance | ✅ | ✅ | ✅ | ⚠️ | ✅ | ❌ | | JS/TS team | ❌ | ❌ | ❌ | ✅ Best | ❌ | ✅ | | Custom pixel-perfect UI | ✅ | ⚠️ | ✅ Best | ⚠️ | ✅ | ❌ | --- ## §2 Architecture ### Core Principle: Separation of Concerns Every production Android project must separate **UI**, **business logic**, and **data** into distinct, independently testable layers. ### Recommended Architecture: Clean Architecture + MVI/MVVM ``` app/ ├── ui/ # Composables / Activities / Fragments / Screen states ├── presentation/ # ViewModels, UI State, UI Events ├── domain/ # Use cases, domain models, repository interfaces ├── data/ # Repository impl, remote (API), local (DB), mappers └── di/ # Dependency injection modules ``` **Data flow (unidirectional):** ``` User Action → ViewModel/Store → Use Case → Repository → Data Source ↓ UI State (sealed class / StateFlow) ↓ Composable / View renders state ``` ### Key Architecture Patterns by Stack **Native (MVVM + MVI):** - `StateFlow` / `SharedFlow` for reactive state - `sealed class UiState` + `sealed class UiEvent` - Hilt for DI, coroutines + Flow for async - Repository pattern wrapping Room + Retrofit **Flutter (BLoC or Riverpod):** - `Bloc` or `Cubit` for business logic isolation - `AsyncNotifierProvider` (Riverpod) for data + state - Repositories as abstract classes with impl injected **React Native (Redux Toolkit or Zustand):** - RTK Query or React Query for server state - Zustand slices for client state - Custom hooks to encapsulate business logic per feature **KMM:** - Shared `commonMain` holds domain + data layers - `expect/actual` for platform-specific implementations - Kotlin coroutines + Flow bridged to platform (StateFlow on Android) ### Module Structure (Multi-module for large apps) ``` :app # Entry point, DI wiring :core:ui # Design system, shared composables :core:network # API client, interceptors :core:database # Room / SQLDelight setup :feature:home :feature:profile :feature:settings ``` --- ## §3 UI & Design ### Design System First Before writing screens, define: 1. **Color tokens** — Primary, secondary, surface, on-surface, error; light + dark variants 2. **Typography scale** — Display, headline, title, body, label (Material 3 type system) 3. **Spacing scale** — 4dp grid system (4, 8, 12, 16, 24, 32, 48dp) 4. **Shape tokens** — Corner radii per component family 5. **Component library** — Button, TextField, Card, BottomSheet, TopAppBar, etc. ### Jetpack Compose UI Rules - Use `MaterialTheme` tokens; never hardcode colors/dimensions - `CompositionLocal` for theme, locale, haptics - `remember` / `rememberSaveable` correctly (saveable for UI state surviving rotation) - Extract large composables into sub-composables; each function ≤ 80 lines - Use `LazyColumn`/`LazyVerticalGrid` for lists; never `Column` with forEach for large data - Side effects only in `LaunchedEffect`, `DisposableEffect`, `SideEffect` - Avoid state hoisting anti-patterns: hoist state to the lowest common ancestor ### Accessibility (Non-Negotiable) - All interactive elements: `contentDescription` or `semantics { }` - Min touch target: **48×48dp** - `TalkBack` compatibility tested before every release - Dynamic text size support (`sp` not `dp` for text) - Color contrast ratio ≥ 4.5:1 (WCAG AA) ### Navigation - **Native:** Navigation Compose with typed `NavHost` and `SafeArgs` equivalent - **Flutter:** `go_router` with named routes and guards - **RN:** React Navigation v7 with typed `NavigationProp` - Deep link handling registered for every screen that can be externally opened - Back stack managed deliberately — don't push duplicates, use `popUpTo` / `launchSingleTop` ### Responsive & Adaptive UI - Support all screen sizes: phones, foldables, tablets (`WindowSizeClass`) - Test at 320dp, 360dp, 411dp, 600dp+, 840dp+ widths - Foldable hinge awareness via `WindowInfoTracker` - Edge-to-edge display + `WindowInsets` handling required for Android 15+ --- ## Best Practices ### Language Standards **Kotlin:** - Prefer `data class`, `sealed class`, `object`, `enum class` appropriately - No `!!` null assertions — use `?.let`, `?: return`, `requireNotNull` with message - Coroutines: always specify `CoroutineScope` + `Dispatcher` explicitly; never `GlobalScope` - Use `@Stable` / `@Immutable` on Compose state classes for smart recomposition **Java:** - `@NonNull` / `@Nullable` annotations on every method param and return type - Never call methods on unchecked objects — null-check explicitly or use `Objects.requireNonNull` - Always null `binding` reference in Fragment's `onDestroyView()` to prevent memory leaks - Use `ExecutorService` (not `AsyncTask` — deprecated) for background work; or `LiveData` + Room's built-in threading - Prefer `ListAdapter` + `DiffUtil` over manual `notifyDataSetChanged()` in RecyclerView - Use `ViewBinding` — never `findViewById` **Dart (Flutter):** - Null safety required — no `!` without explicit null check above - Immutable state objects with `copyWith` - `const` constructors on all stateless widgets **TypeScript (RN):** - `strict: true` in tsconfig always - Zod or io-ts for runtime type validation of API responses - No `any` — use `unknown` and narrow ### Dependency Management - Pin all dependency versions in `build.gradle.kts` / `pubspec.yaml` / `package.json` - Audit dependencies monthly for security vulnerabilities - Avoid transitive dependency conflicts — use dependency resolution strategies - Keep dependency count minimal — every added lib is a maintenance burden ### Code Review Checklist (PR gate) - [ ] New public APIs have KDoc / DartDoc / JSDoc - [ ] No hardcoded strings — use string resources / l10n - [ ] No hardcoded dimensions or colors outside design tokens - [ ] No blocking I/O on main thread - [ ] No memory leaks (no `Activity` context stored in singletons) - [ ] Coroutine scopes / streams properly cancelled / disposed - [ ] Feature flag guarding any non-trivial feature --- ## §5 Error Handling ### The Golden Rule **Never let exceptions propagate to the user silently or crash the app.** ### Error Classification | Type | Strategy | |------|----------| | Network errors | Retry with exponential backoff; show retry UI | | Auth errors (401/403) | Refresh token → re-request → logout if fails | | Validation errors | Show inline field errors immediately | | Data parsing errors | Log + fallback to cached/default state | | Unexpected crashes | Catch at top-level; show error screen + report | | Background task failures | Retry via WorkManager; notify user if critical | ### Result / Either Pattern (Kotlin) ```kotlin sealed class AppResult { data class Success(val data: T) : AppResult() data class Error(val exception: AppException) : AppResult() } sealed class AppException(msg: String) : Exception(msg) { class NetworkException(msg: String) : AppException(msg) class AuthException(msg: String) : AppException(msg) class ParseException(msg: String) : AppException(msg) class UnknownException(msg: String) : AppException(msg) } ``` Use `AppResult` as return type for all repository + use case functions. ViewModels map to `UiState.Error`. ### Crash Reporting - Integrate **Firebase Crashlytics** or **Sentry** from day one - Set user identifiers and custom keys before crash occurs - Non-fatal exceptions logged for all caught errors - ANR monitoring enabled - Crash-free sessions target: **≥ 99.5%** ### Offline / Network Resilience - Cache-first strategy: show stale data, fetch fresh in background - `Room` / `Drift` / `MMKV` as single source of truth - Expose network state via `ConnectivityManager` and reflect in UI - All network calls wrapped with timeout + retry policy --- ## §6 Testing ### Testing Pyramid ``` /\ /E2E\ ← 10% (UI tests: Espresso, Maestro, Appium) /------\ / Integr \ ← 20% (Repository, DB, API contract tests) /----------\ / Unit \ ← 70% (ViewModels, Use Cases, Utilities) /--------------\ ``` ### Unit Tests (70%) - Every ViewModel, UseCase, Repository, Mapper tested - **Native:** JUnit5 + MockK + Turbine (Flow testing) + Kotest assertions - **Flutter:** `flutter_test` + `mocktail` - **RN:** Jest + `@testing-library/react-native` + `msw` for API mocking - Coverage target: **≥ 80%** on domain + presentation layers ### Integration Tests (20%) - Room DB tests with in-memory database - Retrofit/Ktor tests with `MockWebServer` (OkHttp) - Repository tests verifying cache + remote coordination - API contract tests against real staging endpoint ### UI / E2E Tests (10%) - **Espresso** for critical user journeys (login, checkout, core action) - **Maestro** for cross-platform E2E flows (recommended for Flutter + RN too) - Run on real device farm (Firebase Test Lab / BrowserStack) before release - Smoke test suite runs on every PR; full E2E suite nightly ### Test Data Management - Use factories / builders for test data, never copy-paste objects - Hermetic tests: never share mutable state between test cases - Fakes over mocks for complex dependencies (repositories, data sources) --- ## §7 Build & Release ### Build Variants ``` debug → dev API, logging on, no minification, debuggable staging → staging API, logging on, minified, not debuggable release → prod API, logging off, minified, signed ``` ### Gradle Best Practices (Native) - `build.gradle.kts` only — no Groovy DSL in new projects - Version catalog (`libs.versions.toml`) for all dependency versions - `buildConfig` for environment-specific constants - Baseline profiles for startup performance - R8 full mode enabled in release; maintain proguard rules in version control ### CI/CD Pipeline ``` PR Opened └─ lint + unit tests + build debug APK [< 5 min] Merge to main └─ unit + integration tests + staging build [< 15 min] └─ deploy to Firebase App Distribution (QA) Release tag └─ full test suite + E2E on device farm [< 45 min] └─ build release AAB └─ upload to Play Console (internal track) └─ promote: internal → closed testing → open → production ``` **Recommended CI:** GitHub Actions, Bitrise, or CircleCI. ### Play Store Release Strategy - Always release to **internal → closed → open testing** before production - Use **staged rollouts**: 5% → 20% → 50% → 100% with 24-48h monitoring - Monitor Crashlytics + ANR rate + rating before expanding rollout - **Never skip staged rollout** for significant changes ### App Signing - Upload key (Play App Signing): stored in CI secrets, never committed - Use Google Play App Signing for distribution key management - Document key recovery procedure in team runbook --- ## §8 Performance ### Startup Performance - App startup time target: **cold start < 1s**, warm start < 500ms - Use **App Startup library** for initializing libraries lazily - Baseline profiles generated + committed to repo - Heavy initialization moved off main thread ### UI Performance - Target: **60fps** (90/120fps on supported devices); **zero jank** - Measure with **Android Studio Profiler** + `FrameMetrics` API - Avoid allocation in `draw()` / `onMeasure()` / composition - Use `derivedStateOf` in Compose to avoid unnecessary recompositions - Image loading: Coil (Compose) / Glide / Picasso — never load full-res in thumbnails ### Memory - No `Activity` / `Context` references in ViewModels or singletons - WeakReferences for listeners stored beyond their owner's lifecycle - Bitmap recycling and memory cache sizing - Heap dump + leak detection via **LeakCanary** in debug builds (always) ### Network - HTTP caching headers respected - Image CDN + WebP format - Gzip/Brotli compression verified - Request batching where applicable - Connection pooling configured ### Battery - Background work only via **WorkManager** with appropriate constraints - Location updates: request only needed accuracy level; stop when backgrounded - Wakelocks used sparingly with explicit release --- ## §9 Debugging & Bug Fixing ### Debugging Process 1. **Reproduce reliably** — document exact steps, device, OS version, account state 2. **Isolate** — is it UI, business logic, network, or persistence? 3. **Instrument** — add targeted logs / breakpoints, NOT shotgun logging 4. **Hypothesize** — form 1-3 specific hypotheses before touching code 5. **Fix the root cause** — never patch symptoms; trace back to the source 6. **Regression test** — write a test that fails before fix, passes after 7. **Document** — comment explaining why the fix works, not just what it does ### Common Android Bug Patterns | Bug | Likely Cause | Fix | |-----|-------------|-----| | ANR | Main thread I/O / long computation | Move to coroutine/Dispatcher.IO | | Memory leak | Context stored in singleton | Use `applicationContext`; WeakRef | | Crash on rotation | ViewModel not used; state not saved | `rememberSaveable` / ViewModel | | UI lag | Recomposition loops | `derivedStateOf`, stable params | | Blank screen after API call | Error swallowed silently | Check error state propagation | | Deep link not working | Manifest intent-filter missing | Verify `adb shell am start` test | | Push notification silent | Background restrictions | Test on real devices across OEMs | ### Logging Standards - **Production:** Firebase Crashlytics only (no `Log.d` in release builds) - **Debug/Staging:** Timber with debug tree - Log levels: ERROR (crashes), WARN (recoverable), INFO (key events), DEBUG (dev only) - Never log PII — mask emails, phone numbers, tokens in logs ### OEM-Specific Issues - Test on **Samsung**, **Xiaomi/MIUI**, **OnePlus/OxygenOS**, **Huawei (no GMS)** for critical flows - Background restrictions vary widely by OEM — test push, alarms, background sync - Maintain a physical or cloud device farm with top market-share devices --- ## §10 Development Roadmap Follow this phase structure for any new Android project: ### Phase 0 — Foundation (Week 1-2) - [ ] Stack decision documented with rationale - [ ] Module structure defined - [ ] Design system tokens defined (colors, type, spacing, shapes) - [ ] CI pipeline running (lint + unit tests + build) - [ ] Crash reporting integrated (Crashlytics/Sentry) - [ ] Analytics baseline integrated (Firebase/Amplitude) - [ ] API contract / mock server set up - [ ] DI framework configured - [ ] Navigation skeleton implemented - [ ] Flavor/build variant config complete ### Phase 1 — Core Features (Weeks 3-8) - [ ] Auth flow (login, register, token refresh, logout) - [ ] Core screen shells with real navigation - [ ] Network layer (client, interceptors, error handling) - [ ] Local persistence layer (DB schema + DAOs) - [ ] Repository layer wiring remote + local - [ ] ViewModels + UI states for each feature - [ ] Unit tests for all ViewModels + use cases - [ ] Feature flags infrastructure ### Phase 2 — Polish (Weeks 9-12) - [ ] Design QA pass against Figma/spec - [ ] Accessibility audit (TalkBack, contrast, touch targets) - [ ] Dark mode implementation + verification - [ ] Localization (strings externalized, RTL support if needed) - [ ] Loading, empty, error states on every screen - [ ] Deep link handling - [ ] Widget / notification implementation - [ ] Offline mode verification ### Phase 3 — Hardening (Weeks 12-14) - [ ] Performance profiling (startup, scroll, memory) - [ ] E2E test suite on device farm (Firebase Test Lab) - [ ] Security review (certificate pinning, biometrics, secure storage) - [ ] Proguard / R8 rules verified - [ ] Crash-free rate ≥ 99.5% on staging - [ ] Play Store listing, screenshots, privacy policy ### Phase 4 — Release - [ ] AAB signed and uploaded to internal track - [ ] Staged rollout plan defined - [ ] Monitoring dashboard set up (Crashlytics, Play Console vitals) - [ ] Rollback plan documented - [ ] On-call rotation assigned ### Phase 5 — Post-Launch (Ongoing) - Crash-free rate monitored daily - ANR rate < 0.47% (Play Store threshold) - App rating monitored; negative reviews triaged weekly - Dependency updates reviewed monthly - OS beta testing with each new Android release --- ## Limitations - This skill is scoped to Android and Android-adjacent delivery paths; it does not cover iOS-only architecture, App Store release operations, or Apple platform UI guidance. - Version numbers, Play Console policy thresholds, and recommended libraries can change; verify release-critical details against current Android, Google Play, and library documentation before shipping. - Code snippets are architecture patterns, not complete applications; adapt package names, dependency versions, permissions, privacy disclosures, and security controls to the actual project. - The guidance does not replace device QA, accessibility review, security review, legal/privacy review, or store compliance checks for a production release. ## Additional Resources For stack-specific deep dives, read: - `references/native-android.md` — Kotlin, Compose, Room, Hilt, Coroutines - `references/java-android.md` — Java, XML Views, ViewBinding, LiveData, Retrofit, Room, Hilt, migration path - `references/flutter.md` — Dart, BLoC/Riverpod, Drift, go_router - `references/react-native.md` — TypeScript, RN architecture, Hermes, New Architecture - `references/kmm.md` — KMM shared modules, SQLDelight, Ktor, Compose Multiplatform - `references/hybrid.md` — Capacitor, Ionic, PWA considerations