This repository contains a Kotlin Multiplatform project for Ultra-Wideband (UWB) device discovery and ranging on both Android and iOS platforms. The project consists of a modular architecture with the core UWB functionality packaged as a separate library module (uwbmodule) and a sample application (composeApp) demonstrating its usage.
- Overview
- Features
- Architecture
- Setup & Installation
- Usage
- Prerequisites
- Dependencies
- Contributing
- License
This project provides a Kotlin Multiplatform solution for Ultra-Wideband (UWB) device discovery and ranging. The project is structured as:
uwbmodule: A Kotlin Multiplatform library module containing the core UWB functionalitycomposeApp: A sample Compose Multiplatform application demonstrating library usage
The library combines Bluetooth Low Energy (BLE) for initial device discovery with UWB for precise distance measurement, offering a unified API across Android and iOS platforms.
- Device Discovery: Uses BLE advertising and scanning to find nearby UWB-capable devices
- UWB Ranging: Provides precise distance measurements between devices using UWB technology
- Cross-Platform Abstraction: Common API with platform-specific implementations for optimal hardware access
- Reactive Architecture: Uses Kotlin Flow for real-time device and distance updates
- BLE Device Discovery: Automatic scanning and advertising for UWB-capable devices
- Precise UWB Ranging: Real-time distance measurements with centimeter-level accuracy
- Cross-Platform API: Unified interface for both Android and iOS platforms
- Reactive Data Flow: Kotlin Flow-based real-time updates for device discovery and ranging
- Permission Management: Integrated permission handling for BLE and UWB access
- Error Handling: Comprehensive error reporting and recovery mechanisms
The project follows a modular architecture with the UWB functionality extracted into a separate library module:
uwbmodule/: Kotlin Multiplatform library module containing the core UWB functionalitycomposeApp/: Sample Compose Multiplatform application demonstrating library usage
-
Common Module (
src/commonMain/kotlin/):DeviceDiscoveryManager: Orchestrates BLE discovery and UWB rangingMultiplatformUwb: Main entry point and data modelsMultiplatformUwbManager: Expect class for UWB operationsBleManager: Expect class for Bluetooth LE operations (moved from common project)ManagerFactory: Factory for creating platform-specific managers
-
Android Implementation (
src/androidMain/kotlin/):MultiplatformUwbManager.android.kt: Uses androidx.core.uwb for UWB rangingBleManager.kt: Android Bluetooth LE scanning and advertisingManagerFactory.android.kt: Creates Android-specific manager instances
-
iOS Implementation (
src/iosMain/kotlin/):MultiplatformUwbManager.ios.kt: Uses NearbyInteraction framework for UWBBleManager.kt: CoreBluetooth-based scanning and advertisingManagerFactory.ios.kt: Creates iOS-specific manager instances
The uwbmodule is configured as an Android library and iOS framework with the following key dependencies:
- Koin: For dependency injection
- androidx.uwb: Android UWB API
- kotlinx.datetime: Timestamp management
- moko-permissions: Cross-platform permission handling
- lifecycle-viewmodel: ViewModel support
- Discovery Phase: BLE scanning discovers nearby devices advertising UWB service UUID
- Ranging Phase: Discovered devices automatically initiate UWB ranging sessions
- Updates: Real-time distance measurements flow through reactive Kotlin Flow streams
- Session Management: Automatic lifecycle management for UWB sessions
The library uses a callback-based system to bridge platform-specific implementations with common code:
- Device discovery callbacks trigger UWB session initiation
- Ranging callbacks provide real-time distance updates
- Error callbacks handle platform-specific failures
- Android Studio for Android development
- Xcode for iOS development
- Kotlin Multiplatform plugin
- UWB-capable devices for testing
-
Clone the repository:
git clone <repository-url> cd "Multiplatform UWB"
-
Open in Android Studio with the Kotlin Multiplatform plugin installed
-
Build the project:
./gradlew build
To integrate the uwbmodule in your own project:
// In your build.gradle.kts, add the module dependency
dependencies {
implementation(project(":uwbmodule"))
}
// Or if published, use:
// implementation("com.dustedrob:uwbmodule:1.0.0")Add required permissions to AndroidManifest.xml:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.UWB_RANGING" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />Add required permissions to Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to discover nearby UWB devices</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app uses Bluetooth to advertise UWB capabilities</string>// Create managers using factory
val managerFactory = ManagerFactory(context) // Android context or iOS equivalent
val deviceDiscoveryManager = DeviceDiscoveryManager(
managerFactory.createUwbManager(),
managerFactory.createBleManager()
)
// Observe nearby devices
deviceDiscoveryManager.nearbyDevices.collect { devices ->
devices.forEach { device ->
println("Device: ${device.name}, Distance: ${device.distance}m")
}
}
// Start discovery and ranging
deviceDiscoveryManager.startScanning()
// Stop when done
deviceDiscoveryManager.stopScanning()class UwbDiscoveryViewModel(
private val controller: PermissionsController,
private val managerFactory: ManagerFactory
) : ViewModel() {
private val deviceDiscoveryManager = DeviceDiscoveryManager(
managerFactory.createUwbManager(),
managerFactory.createBleManager()
)
val nearbyDevices = deviceDiscoveryManager.nearbyDevices
val isScanning: StateFlow<Boolean>
var permissionState: PermissionState
fun toggleScanning() {
// Handle scanning state with permission checks
}
fun requestPermissions() {
// Request BLE and UWB permissions
}
}- Android: Requires Android 11 (API level 30) or higher and UWB-capable hardware.
- iOS: Requires iOS 14.0 or higher and UWB-capable hardware (iPhone 11 or newer).
- UWB Chipset: Devices must have UWB hardware to participate in the network.
- kotlinx-coroutines: For asynchronous operations
- kotlinx-datetime: For timestamp management
- moko-permissions: Cross-platform permission handling
- androidx.core.uwb: Android UWB API
- Android Bluetooth LE APIs: Device discovery and advertising
- NearbyInteraction: iOS UWB framework
- CoreBluetooth: iOS Bluetooth LE framework
Main orchestrator class that combines BLE discovery with UWB ranging.
class DeviceDiscoveryManager(
multiplatformUwbManager: MultiplatformUwbManager,
bleManager: BleManager
)
// Properties
val nearbyDevices: Flow<List<NearbyDevice>>
// Methods
fun startScanning()
fun stopScanning()Data class representing a discovered device.
data class NearbyDevice(
val id: String,
val name: String,
val distance: Double? = null,
val lastSeen: Long
)Cross-platform UWB ranging interface.
expect class MultiplatformUwbManager {
fun initialize()
fun startRanging(peerId: String)
fun stopRanging(peerId: String)
fun setRangingCallback(callback: (peerId: String, distance: Double) -> Unit)
fun setErrorCallback(callback: (error: String) -> Unit)
}Cross-platform Bluetooth LE interface.
expect class BleManager {
fun startScanning()
fun stopScanning()
fun advertise()
fun stopAdvertising()
fun setDeviceDiscoveredCallback(callback: (id: String, name: String) -> Unit)
}Contributions are welcome! Please ensure you follow the existing code patterns and test on both platforms.
This project is licensed under the MIT License.
Build precise location-aware applications with Kotlin Multiplatform and UWB! 🚀