mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
104 lines
10 KiB
Markdown
104 lines
10 KiB
Markdown
# Meshtastic Android - Agent Guide
|
|
|
|
This file serves as a comprehensive guide for AI agents and developers working on the `Meshtastic-Android` codebase. Use this as your primary reference for understanding the architecture, conventions, and strict rules of this project.
|
|
|
|
For execution-focused recipes, see `docs/agent-playbooks/README.md`.
|
|
|
|
## 1. Project Vision
|
|
We are incrementally migrating Meshtastic-Android to a **Kotlin Multiplatform (KMP)** architecture. The goal is to decouple business logic from the Android framework, enabling future expansion to iOS and other platforms while maintaining a high-performance native Android experience.
|
|
|
|
## 2. Codebase Map
|
|
|
|
| Directory | Description |
|
|
| :--- | :--- |
|
|
| `app/` | Main application module. Contains `MainActivity`, Koin DI modules, and app-level logic. Uses package `org.meshtastic.app`. |
|
|
| `build-logic/` | Convention plugins for shared build configuration (e.g., `meshtastic.kmp.library`, `meshtastic.koin`). |
|
|
| `config/` | Detekt static analysis rules (`config/detekt/detekt.yml`) and Spotless formatting config (`config/spotless/.editorconfig`). |
|
|
| `docs/` | Architecture docs and agent playbooks. See `docs/agent-playbooks/README.md` for version baseline and task recipes. |
|
|
| `core/model` | Domain models and common data structures. |
|
|
| `core:proto` | Protobuf definitions (Git submodule). |
|
|
| `core:common` | Low-level utilities, I/O abstractions (Okio), and common types. |
|
|
| `core:database` | Room KMP database implementation. |
|
|
| `core:datastore` | Multiplatform DataStore for preferences. |
|
|
| `core:repository` | High-level domain interfaces (e.g., `NodeRepository`, `LocationRepository`). |
|
|
| `core:domain` | Pure KMP business logic and UseCases. |
|
|
| `core:data` | Core manager implementations and data orchestration. |
|
|
| `core:network` | KMP networking layer using Ktor, MQTT abstractions, and shared transport (`StreamFrameCodec` in commonMain, `TcpTransport` in jvmAndroidMain). |
|
|
| `core:di` | Common DI qualifiers and dispatchers. |
|
|
| `core:navigation` | Shared navigation keys/routes for Navigation 3. |
|
|
| `core:ui` | Shared Compose UI components (`EmptyDetailPlaceholder`, `MainAppBar`, dialogs, preferences) and platform abstractions, including `jvmAndroidMain` bridges for shared JVM/Android actuals. |
|
|
| `core:service` | KMP service layer; Android bindings stay in `androidMain`. |
|
|
| `core:api` | Public AIDL/API integration module for external clients. |
|
|
| `core:prefs` | KMP preferences layer built on DataStore abstractions. |
|
|
| `core:barcode` | Barcode scanning (Android-only). Shared UI in `main/`; only the decoder (`createBarcodeAnalyzer`) differs per flavor (ML Kit / ZXing). Shared contract in `core:ui`. |
|
|
| `core:nfc` | NFC abstractions (KMP). Android NFC hardware implementation in `androidMain`; shared contract via `LocalNfcScannerProvider` in `core:ui`. |
|
|
| `core/ble/` | Bluetooth Low Energy stack using Nordic libraries. |
|
|
| `core/resources/` | Centralized string and image resources (Compose Multiplatform). |
|
|
| `core/testing/` | **Shared test doubles, fakes, and utilities for `commonTest` across all KMP modules.** Lightweight with minimal dependencies (only `core:model`, `core:repository`, + test libs). Keeps module dependency graph clean by centralizing test consolidation. See `core/testing/README.md`. |
|
|
| `feature/` | Feature modules (e.g., `settings`, `map`, `messaging`, `node`, `intro`, `connections`). All are KMP with `jvm()` target. |
|
|
| `feature/connections` | Connections UI — device discovery, BLE/TCP/USB scanning, shared composables in `commonMain`; Android BLE bonding/NSD/USB in `androidMain`. |
|
|
| `feature/firmware` | Firmware update flow (KMP module with Android DFU in `androidMain`). |
|
|
| `desktop/` | Compose Desktop application — first non-Android KMP target. Nav 3 shell, full Koin DI graph, TCP transport with `want_config` handshake, adaptive list-detail screens for nodes/messaging, ~35 real settings screens, connections UI. See `docs/kmp-status.md`. |
|
|
| `mesh_service_example/` | Sample app showing `core:api` service integration. |
|
|
|
|
## 3. Development Guidelines
|
|
|
|
### A. UI Development (Jetpack Compose)
|
|
- **Material 3:** The app uses Material 3.
|
|
- **Strings:**
|
|
- **Rule:** MUST use the **Compose Multiplatform Resource** library in `core:resources`.
|
|
- **Location:** `core/resources/src/commonMain/composeResources/values/strings.xml`.
|
|
- **Dialogs:** Use centralized components in `core:ui`.
|
|
- **Platform/Flavor UI:** Inject platform-specific behavior (e.g., map providers) via `CompositionLocal` from `app`. See `core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/util/MapViewProvider.kt` for the contract pattern and `app/src/main/kotlin/org/meshtastic/app/MainActivity.kt` for provider wiring.
|
|
|
|
### B. Logic & Data Layer
|
|
- **KMP Focus:** All business logic must reside in `commonMain` of the respective `core` module.
|
|
- **Platform purity:** Never import `java.*` or `android.*` in `commonMain`. Use KMP alternatives:
|
|
- `java.util.Locale` → Kotlin `uppercase()` / `lowercase()` (locale-independent for ASCII) or `expect`/`actual`.
|
|
- `java.util.concurrent.ConcurrentHashMap` → `atomicfu` or `Mutex`-guarded `mutableMapOf()`.
|
|
- `java.util.concurrent.locks.*` → `kotlinx.coroutines.sync.Mutex`.
|
|
- `java.io.*` → Okio (`BufferedSource`/`BufferedSink`).
|
|
- **I/O:** Use **Okio** (`BufferedSource`/`BufferedSink`) for stream operations. Never use `java.io` in `commonMain`.
|
|
- **Concurrency:** Use Kotlin Coroutines and Flow.
|
|
- **Thread-Safety:** Use `atomicfu` and `kotlinx.collections.immutable` for shared state in `commonMain`. Avoid `synchronized` or JVM-specific atomics.
|
|
- **Dependency Injection:**
|
|
- Use **Koin Annotations** with the K2 compiler plugin.
|
|
- Keep root graph assembly in `app` (module inclusion in `AppKoinModule` and startup wiring in `MeshUtilApplication`).
|
|
- It is the recommended best practice to use `@Module`, `@ComponentScan`, and `@KoinViewModel` annotations directly in `commonMain` shared modules. This provides compile-time safety and encapsulates dependency graphs per feature.
|
|
- **ViewModels:** Follow the MVI/UDF pattern. Use the multiplatform `androidx.lifecycle.ViewModel` in `commonMain` to maintain a single source of truth for UI state, relying heavily on `StateFlow`.
|
|
- **BLE:** All Bluetooth communication must route through `core:ble` using Nordic Semiconductor's Android Common Libraries and Kotlin Coroutines/Flows. Never use legacy Android Bluetooth callbacks directly.
|
|
- **Dependencies:** Check `gradle/libs.versions.toml` before assuming a library is available. New dependencies MUST be added to the version catalog, not directly to a `build.gradle.kts` file.
|
|
- **Shared JVM + Android code:** If a KMP module needs a `jvmAndroidMain` source set for code shared between desktop JVM and Android, apply the `meshtastic.kmp.jvm.android` convention plugin. Do **not** hand-wire `sourceSets.dependsOn(...)` edges in module `build.gradle.kts` files—the convention uses Kotlin's hierarchy template API and avoids default hierarchy warnings.
|
|
- **Room KMP:** Always use `factory = { MeshtasticDatabaseConstructor.initialize() }` in `Room.databaseBuilder` and `inMemoryDatabaseBuilder`. DAOs and Entities reside in `commonMain`.
|
|
- **Testing:** Write ViewModel and business logic tests in `commonTest` (not `test/` Robolectric) so every target runs them. Use `core:testing` shared fakes when available. **Test framework dependencies** (`kotlin("test")` for both `commonTest` and `androidHostTest` source sets) are automatically provided by the `meshtastic.kmp.library` convention plugin—no need to add them manually to individual module `build.gradle.kts` files. See `build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt::configureKmpTestDependencies()` for details.
|
|
|
|
### C. Namespacing
|
|
- **Standard:** Use the `org.meshtastic.*` namespace for all code.
|
|
- **Legacy:** Maintain the `com.geeksville.mesh` Application ID and specific intent strings for backward compatibility.
|
|
|
|
## 4. Execution Protocol
|
|
|
|
### A. Build and Verify
|
|
**Prerequisite:** JDK 17 is required. Copy `secrets.defaults.properties` to `local.properties` before building.
|
|
1. **Clean:** `./gradlew clean`
|
|
2. **Format:** `./gradlew spotlessCheck` then `./gradlew spotlessApply`
|
|
3. **Lint:** `./gradlew detekt`
|
|
4. **Build + Unit Tests:** `./gradlew assembleDebug test` (CI also runs `testDebugUnitTest`)
|
|
5. **Flavor/CI Parity (when relevant):** `./gradlew lintFdroidDebug lintGoogleDebug testFdroidDebug testGoogleDebug`
|
|
6. **Desktop (when touched):** `./gradlew :desktop:test :desktop:run`
|
|
|
|
### B. Documentation Sync
|
|
- If you change architecture, module boundaries, target declarations, CI tasks, validation commands, or agent workflow rules, update the corresponding docs in the same slice.
|
|
- KMP status: `docs/kmp-status.md`. Roadmap: `docs/roadmap.md`. Decisions: `docs/decisions/`. Architecture review: `docs/decisions/architecture-review-2026-03.md`.
|
|
- At minimum, review and update the relevant source of truth among `AGENTS.md`, `.github/copilot-instructions.md`, `GEMINI.md`, `docs/agent-playbooks/*`, and `docs/kmp-status.md` when those areas are affected.
|
|
|
|
### C. Expect/Actual Patterns
|
|
Use `expect`/`actual` sparingly for platform-specific types (e.g., `Location`, platform utilities) to keep core logic pure. For navigation, prefer shared Navigation 3 backstack state (`List<NavKey>`) over platform controller types.
|
|
|
|
## 5. Troubleshooting
|
|
- **Build Failures:** Always check `gradle/libs.versions.toml` for dependency conflicts.
|
|
- **Missing Secrets:** Copy `secrets.defaults.properties` → `local.properties` with valid (or dummy) values for `MAPS_API_KEY`, `datadogApplicationId`, and `datadogClientToken`.
|
|
- **JDK Version:** JDK 17 is required. Mismatched JDK versions cause Gradle sync/build failures.
|
|
- **Configuration Cache:** Add `--no-configuration-cache` flag if cache-related issues persist.
|
|
- **Koin Injection Failures:** Verify the KMP component is included in `app` root module wiring (`AppKoinModule`) and that `startKoin` loads that module at app startup.
|
|
- **Desktop `Dispatchers.Main` missing:** JVM/Desktop requires `kotlinx-coroutines-swing` for `Dispatchers.Main`. Without it, any code using `lifecycle.coroutineScope` or `Dispatchers.Main` will crash at runtime. The desktop module already includes this dependency.
|