Files
Meshtastic-Android/core/ble
James Rich 89cc679941 fix(ble): resolve first-ever wasmJs compile of the BLE actuals
WebBleDevice/WebBleService were public classes exposing internal JS-interop types
(JsBluetoothDevice, JsBluetoothRemoteGATTService, JsBluetoothRemoteGATTCharacteristic) in
their constructors/companion function -- Kotlin's visibility checker correctly rejects a
public declaration leaking an internal type. Made both classes internal, matching the
documented intent that only the BleDevice/BleService contracts should ever be visible
outside this file.

Also upgraded WebBluetoothApi.kt's byte-conversion helpers from hand-rolled per-byte js()
loops to kotlinx-browser (org.jetbrains.kotlinx:kotlinx-browser:0.5.0, confirmed to publish
a wasmJs variant) -- the real, documented Kotlin/Wasm typed-array interop library, per its
own official docs. DataView still needs one small js() snippet to view it as an Int8Array
(kotlinx-browser has no DataView-specific conversion); everything past that point goes
through the library's real toByteArray()/toInt8Array() extensions instead of a manual
per-index loop.

core:ble:compileKotlinWasmJs now passes -- this code has never compiled before. Verified
via gradle-runner: zero errors (98 expected ExperimentalWasmJsInterop opt-in warnings),
full regression (android/jvm/iOS compiles, allTests, detekt, spotlessCheck) passes across
all five touched modules (core:ble, core:common, core:di, core:model, core:resources).
2026-08-30 19:44:25 -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;