Files
Meshtastic-Android/core/ble
James RichandClaude Sonnet 5 1433033436 fix(wasm): close detekt/test gaps found while building the webApp module
detekt's source set list never included src/wasmJsMain or src/nonWebMain,
so every prior "detekt clean" claim in this effort never actually scanned
wasmJs code. Found while adding :webApp (whose entire source lives in
wasmJsMain and reported NO-SOURCE forever) and fixed at the root: both
source sets are now scanned repo-wide. Real findings it surfaced are
suppressed with honest, specific justification (embedded js("...") string
interop that static analysis can't see into) or fixed outright — nothing
silenced to dodge a genuine issue.

core:ble's own compileTestKotlinWasmJs had never actually been exercised:
7 of its 9 commonTest files reference Kable directly, which has no wasmJs
target, so they silently never compiled for wasmJs until this pass tried.
Moved them to a new nonWebTest source set, matching this effort's existing
android/jvm/ios-only test pattern elsewhere.

core:repository had a latent iOS-hierarchy trap: a manual nonWebTest
dependsOn edge (needed once core:testing was pulled out of commonTest)
silently disabled Kotlin's default hierarchy template, which is what wires
iosMain to the leaf iOS compilations. Restored the explicit
applyHierarchyTemplate(default) call alongside the manual edge.

Also tried retrofitting every wasmJs-enabled module to wasmJs { browser() }
to satisfy KGP's root npm resolver ahead of the webApp module (see next
commit) — reverted repo-wide: browser() arms each module's
wasmJsBrowserTest task, which allTests then picks up with no
karma/headless-Chrome runner configured anywhere in this repo, a CI-gate
regression that outweighs the benefit. Every wasmJs-enabled module's
comment now explains this explicitly instead of the stale "that's for the
eventual webApp executable" text, which turned out to be wrong.

core:ui's MeshtasticNavigationSuite gained an optional visibleDestinations
parameter (default: today's full tab set) so a host can hide a tab it has
no entry provider for without a per-platform expect/actual — needed by
webApp, which omits Map.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-31 04:42:26 -05:00
..

:core:ble

Overview

The :core:ble module contains the foundation for Bluetooth Low Energy (BLE) communication in the Meshtastic Android app. It uses the Kable multiplatform BLE library to provide a unified, Coroutine-based architecture across all supported targets (Android, Desktop, and future iOS).

This module abstracts platform-specific BLE operations behind common Kotlin interfaces (BleDevice, BleScanner, BleConnection, BleConnectionFactory), ensuring that business logic in commonMain remains platform-agnostic and testable.

Key Components

1. BleConnection

A robust wrapper around Kable's Peripheral that simplifies the connection lifecycle and service discovery using modern Coroutine APIs.

  • Features:
    • Connection & Await: Provides suspend functions to connect and wait for a terminal state (Connected or Disconnected).
    • Unified Profile Helper: A profile function that manages service discovery, characteristic setup, and lifecycle in a single block, with automatic timeout and error handling.
    • Observability: Exposes connectionState as a Flow for reactive UI and service updates.
    • Platform Setup: Seamlessly handles platform-specific configuration (like MTU negotiation on Android or direct connections on Desktop) via platformConfig() extensions.

2. BluetoothRepository

A Singleton repository responsible for the global state of Bluetooth on the device.

  • Features:
    • State Management: Exposes a StateFlow<BluetoothState> reflecting whether Bluetooth is enabled, permissions are granted, and which devices are bonded.
    • Permission Handling: Centralizes logic for checking Bluetooth and Location permissions across different platforms.
    • Bonding: Simplifies the process of creating and validating bonds with peripherals.

3. BleScanner

A wrapper around Kable's Scanner to provide a consistent and easy-to-use API for BLE scanning with built-in peripheral mapping.

4. BleRetry

A utility for executing BLE operations with retry logic, essential for handling the inherent unreliability of wireless communication.

Integration

The :core:ble module is used by BleRadioTransport in :core:network to implement the RadioTransport contract for Bluetooth devices.

Usage

Dependencies are managed via the version catalog (libs.versions.toml).

[versions]
kable = "0.44.2"

[libraries]
kable-core = { module = "com.juul.kable:kable-core", version.ref = "kable" }

Architecture

The module follows a clean multiplatform architecture approach:

  • Repository Pattern: BluetoothRepository mediates data access.
  • Coroutines & Flow: All asynchronous operations use Kotlin Coroutines and Flows.
  • Dependency Injection: Koin is used for dependency injection.

Testing

The module includes unit tests for key components, utilizing Kable's architecture and standard coroutine testing tools to ensure logic correctness.

Dependency Graph

graph TB
  :core:ble[ble]:::kmp-library
  :core:ble --> :core:common
  :core:ble -.-> :core:di
  :core:ble -.-> :core:model
  :core:ble -.-> :core:testing

classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef compose-desktop-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-library-compose fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;