Kotlin Multiplatform BLE library for iOS, Android, macos, windows and javascript
This example demonstrates how to create a custom Blue Falcon engine.
A complete, working custom engine implementation that simulates BLE operations.
Features:
BlueFalconEngine interfaceCustom engines allow you to:
All engines must implement the BlueFalconEngine interface:
interface BlueFalconEngine {
val scope: CoroutineScope
val peripherals: StateFlow<Set<BluetoothPeripheral>>
val managerState: StateFlow<BluetoothManagerState>
suspend fun scan(serviceFilter: List<ServiceFilter>)
suspend fun stopScanning()
suspend fun connect(peripheral: BluetoothPeripheral, autoConnect: Boolean)
suspend fun disconnect(peripheral: BluetoothPeripheral)
// ... and more
}
import dev.bluefalcon.example.engine.MockBLEEngine
val blueFalcon = BlueFalcon {
engine = MockBLEEngine()
// Can still use plugins!
install(LoggingPlugin) {
level = LogLevel.DEBUG
}
}
// Use normally
blueFalcon.scan()
Provide a scope for async operations:
override val scope: CoroutineScope =
CoroutineScope(Dispatchers.Default + SupervisorJob())
Use MutableStateFlow for reactive state:
private val _peripherals = MutableStateFlow<Set<BluetoothPeripheral>>(emptySet())
override val peripherals: StateFlow<Set<BluetoothPeripheral>> =
_peripherals.asStateFlow()
All BLE operations are suspend functions:
override suspend fun connect(
peripheral: BluetoothPeripheral,
autoConnect: Boolean
) {
// Your platform-specific connection logic
delay(500) // Simulate async operation
connectedDevices.add(peripheral.uuid)
}
Throw appropriate exceptions:
override suspend fun readCharacteristic(...): ByteArray {
if (!isConnected(peripheral)) {
throw BluetoothException("Not connected")
}
// Read logic
}
class AndroidEngine(private val context: Context) : BlueFalconEngine {
private val bluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
override suspend fun scan(serviceFilter: List<ServiceFilter>) {
bluetoothManager.adapter.bluetoothLeScanner.startScan(...)
}
// ... implement other methods using android.bluetooth APIs
}
class iOSEngine : BlueFalconEngine {
private val centralManager = CBCentralManager(...)
override suspend fun scan(serviceFilter: List<ServiceFilter>) {
centralManager.scanForPeripheralsWithServices(...)
}
// ... implement using CoreBluetooth
}
class JSEngine : BlueFalconEngine {
override suspend fun scan(serviceFilter: List<ServiceFilter>) {
val bluetooth = window.navigator.bluetooth
bluetooth.requestDevice(...)
}
// ... implement using Web Bluetooth API
}
class MyEngineTest {
@Test
fun testScanning() = runBlocking {
val engine = MyCustomEngine()
val blueFalcon = BlueFalcon { engine = engine }
blueFalcon.scan()
delay(1000)
assertTrue(blueFalcon.peripherals.value.isNotEmpty())
}
}
When creating an engine for a new platform:
Want to contribute an engine for a new platform? Great!
See CONTRIBUTING.md and create an ADR for major platform additions.