Kotlin Multiplatform BLE library for iOS, Android, macos, windows and javascript
The main client class for interacting with Bluetooth Low Energy devices.
class BlueFalcon(
val engine: BlueFalconEngine
)
fun BlueFalcon(block: BlueFalconConfig.() -> Unit): BlueFalcon
Example:
val blueFalcon = BlueFalcon {
engine = AndroidBlueFalconEngine(context)
install(LoggingPlugin) { /* config */ }
}
| Property | Type | Description |
|---|---|---|
engine |
BlueFalconEngine |
Underlying platform engine |
plugins |
PluginRegistry |
Installed plugins |
peripherals |
StateFlow<Set<BluetoothPeripheral>> |
Discovered devices |
managerState |
StateFlow<BluetoothManagerState> |
Bluetooth adapter state |
isScanning |
Boolean |
Whether currently scanning |
suspend fun scan(filters: List<ServiceFilter> = emptyList())
Start scanning for BLE devices.
Parameters:
filters: Optional list of service UUIDs to filter devicesExample:
// Scan for all devices
blueFalcon.scan()
// Scan for devices with specific service
blueFalcon.scan(filters = listOf(
ServiceFilter(Uuid("0000180D-0000-1000-8000-00805F9B34FB"))
))
suspend fun stopScanning()
Stop scanning for devices.
fun clearPeripherals()
Clear all discovered peripherals from cache.
suspend fun connect(
peripheral: BluetoothPeripheral,
autoConnect: Boolean = false
)
Connect to a BLE peripheral.
Parameters:
peripheral: The device to connect toautoConnect: Auto-reconnect on disconnection (Android only)Throws:
BluetoothException: If connection failsExample:
try {
blueFalcon.connect(peripheral, autoConnect = true)
println("Connected!")
} catch (e: BluetoothException) {
println("Failed: ${e.message}")
}
suspend fun disconnect(peripheral: BluetoothPeripheral)
Disconnect from a peripheral.
fun connectionState(peripheral: BluetoothPeripheral): BluetoothPeripheralState
Get current connection state.
Returns: Connected, Connecting, Disconnected, Disconnecting
fun retrievePeripheral(identifier: String): BluetoothPeripheral?
Retrieve a peripheral by platform-specific identifier.
Parameters:
identifier: MAC address (Android) or UUID string (iOS/macOS)Returns: Peripheral if found, null otherwise
fun requestConnectionPriority(
peripheral: BluetoothPeripheral,
priority: ConnectionPriority
)
Request connection priority change (Android only, no-op on other platforms).
Priority levels: Balanced, High, LowPower
suspend fun discoverServices(
peripheral: BluetoothPeripheral,
serviceUUIDs: List<Uuid> = emptyList()
)
Discover GATT services on a connected peripheral.
Parameters:
peripheral: Connected deviceserviceUUIDs: Optional filter for specific servicesExample:
blueFalcon.connect(peripheral)
blueFalcon.discoverServices(peripheral)
peripheral.services.forEach { service ->
println("Service: ${service.uuid}")
}
suspend fun discoverCharacteristics(
peripheral: BluetoothPeripheral,
service: BluetoothService,
characteristicUUIDs: List<Uuid> = emptyList()
)
Discover characteristics for a service.
suspend fun readCharacteristic(
peripheral: BluetoothPeripheral,
characteristic: BluetoothCharacteristic
)
Read a characteristic value. Result is stored in characteristic.value.
Example:
blueFalcon.readCharacteristic(peripheral, characteristic)
val value = characteristic.value
println("Read: ${value?.decodeToString()}")
suspend fun writeCharacteristic(
peripheral: BluetoothPeripheral,
characteristic: BluetoothCharacteristic,
value: String,
writeType: Int? = null
)
suspend fun writeCharacteristic(
peripheral: BluetoothPeripheral,
characteristic: BluetoothCharacteristic,
value: ByteArray,
writeType: Int? = null
)
Write to a characteristic.
Parameters:
value: String or ByteArray to writewriteType: Optional write type (platform-specific)Example:
// Write string
blueFalcon.writeCharacteristic(peripheral, characteristic, "Hello BLE")
// Write bytes
blueFalcon.writeCharacteristic(peripheral, characteristic, byteArrayOf(0x01, 0x02))
suspend fun notifyCharacteristic(
peripheral: BluetoothPeripheral,
characteristic: BluetoothCharacteristic,
notify: Boolean
)
Enable/disable notifications for a characteristic.
Example:
// Enable notifications
blueFalcon.notifyCharacteristic(peripheral, characteristic, notify = true)
// Disable notifications
blueFalcon.notifyCharacteristic(peripheral, characteristic, notify = false)
suspend fun indicateCharacteristic(
peripheral: BluetoothPeripheral,
characteristic: BluetoothCharacteristic,
indicate: Boolean
)
Enable/disable indications for a characteristic.
suspend fun readDescriptor(
peripheral: BluetoothPeripheral,
characteristic: BluetoothCharacteristic,
descriptor: BluetoothCharacteristicDescriptor
)
Read a characteristic descriptor.
suspend fun writeDescriptor(
peripheral: BluetoothPeripheral,
descriptor: BluetoothCharacteristicDescriptor,
value: ByteArray
)
Write to a characteristic descriptor.
suspend fun changeMTU(peripheral: BluetoothPeripheral, mtuSize: Int)
Request MTU (Maximum Transmission Unit) size change.
fun refreshGattCache(peripheral: BluetoothPeripheral): Boolean
Refresh GATT cache (Android only).
suspend fun openL2capChannel(peripheral: BluetoothPeripheral, psm: Int)
Open L2CAP channel (platform-dependent).
suspend fun createBond(peripheral: BluetoothPeripheral)
Create a bond (pair) with the peripheral.
suspend fun removeBond(peripheral: BluetoothPeripheral)
Remove bond (unpair) with the peripheral.
Base interface for creating plugins.
interface BlueFalconPlugin {
fun install(client: BlueFalconClient, config: PluginConfig)
suspend fun onBeforeScan(call: ScanCall): ScanCall = call
suspend fun onAfterScan(call: ScanCall) {}
suspend fun onBeforeConnect(call: ConnectCall): ConnectCall = call
suspend fun onAfterConnect(call: ConnectCall, result: Result<Unit>) {}
suspend fun onBeforeRead(call: ReadCall): ReadCall = call
suspend fun onAfterRead(call: ReadCall, result: Result<ByteArray?>) {}
suspend fun onBeforeWrite(call: WriteCall): WriteCall = call
suspend fun onAfterWrite(call: WriteCall, result: Result<Unit>) {}
}
Hook Methods:
| Method | Description | When Called |
|---|---|---|
install() |
Plugin initialization | Once on installation |
onBeforeScan() |
Intercept scan | Before scan starts |
onAfterScan() |
Post-scan hook | After scan completes |
onBeforeConnect() |
Intercept connect | Before connection attempt |
onAfterConnect() |
Post-connect hook | After connection result |
onBeforeRead() |
Intercept read | Before reading characteristic |
onAfterRead() |
Post-read hook | After read completes |
onBeforeWrite() |
Intercept write | Before writing characteristic |
onAfterWrite() |
Post-write hook | After write completes |
Example:
class MyPlugin : BlueFalconPlugin {
override fun install(client: BlueFalconClient, config: PluginConfig) {
println("Plugin installed")
}
override suspend fun onBeforeRead(call: ReadCall): ReadCall {
println("About to read ${call.characteristic.uuid}")
return call
}
override suspend fun onAfterRead(call: ReadCall, result: Result<ByteArray?>) {
result.onSuccess { data ->
println("Read ${data?.size ?: 0} bytes")
}
}
}
Manages installed plugins.
class PluginRegistry {
fun install(plugin: BlueFalconPlugin, configure: PluginConfig.() -> Unit = {})
fun uninstall(plugin: BlueFalconPlugin)
}
Example:
val plugins = blueFalcon.plugins
// Install a plugin
plugins.install(LoggingPlugin(LoggingPlugin.Config()))
// Uninstall a plugin
plugins.uninstall(loggingPlugin)
Base class for plugin configurations.
open class PluginConfig
Example:
class MyPluginConfig : PluginConfig() {
var enabled: Boolean = true
var timeout: Duration = 5.seconds
}
data class ScanCall(val filters: List<ServiceFilter>)
data class ConnectCall(
val peripheral: BluetoothPeripheral,
val autoConnect: Boolean
)
data class ReadCall(
val peripheral: BluetoothPeripheral,
val characteristic: BluetoothCharacteristic
)
data class WriteCall(
val peripheral: BluetoothPeripheral,
val characteristic: BluetoothCharacteristic,
val value: ByteArray,
val writeType: Int?
)
Represents a BLE device.
interface BluetoothPeripheral {
val name: String? // Device name
val uuid: String // Platform-specific ID
val rssi: Float? // Signal strength (dBm)
val mtuSize: Int? // MTU size
val services: List<BluetoothService> // GATT services
val characteristics: List<BluetoothCharacteristic>
}
Example:
blueFalcon.peripherals.collect { devices ->
devices.forEach { device ->
println("${device.name} (${device.uuid})")
println("RSSI: ${device.rssi} dBm")
}
}
Represents a GATT service.
interface BluetoothService {
val uuid: Uuid // Service UUID
val name: String? // Human-readable name
val characteristics: List<BluetoothCharacteristic>
}
Example:
peripheral.services.forEach { service ->
println("Service: ${service.uuid}")
service.characteristics.forEach { char ->
println(" Characteristic: ${char.uuid}")
}
}
Represents a GATT characteristic.
interface BluetoothCharacteristic {
val uuid: Uuid // Characteristic UUID
val name: String? // Human-readable name
val value: ByteArray? // Current value
val descriptors: List<BluetoothCharacteristicDescriptor>
val isNotifying: Boolean // Notifications enabled?
val service: BluetoothService? // Parent service
}
Example:
blueFalcon.readCharacteristic(peripheral, characteristic)
val text = characteristic.value?.decodeToString()
println("Value: $text")
Represents a GATT descriptor.
interface BluetoothCharacteristicDescriptor {
val uuid: Uuid // Descriptor UUID
val name: String? // Human-readable name
val value: ByteArray? // Current value
val characteristic: BluetoothCharacteristic? // Parent characteristic
}
UUID wrapper for BLE UUIDs.
class Uuid(val value: String) {
override fun toString(): String = value
}
Common UUIDs:
// Standard service UUIDs
val HEART_RATE_SERVICE = Uuid("0000180D-0000-1000-8000-00805F9B34FB")
val BATTERY_SERVICE = Uuid("0000180F-0000-1000-8000-00805F9B34FB")
val DEVICE_INFO = Uuid("0000180A-0000-1000-8000-00805F9B34FB")
// Standard characteristic UUIDs
val HEART_RATE_MEASUREMENT = Uuid("00002A37-0000-1000-8000-00805F9B34FB")
val BATTERY_LEVEL = Uuid("00002A19-0000-1000-8000-00805F9B34FB")
Filter for scanning operations.
class ServiceFilter(val uuid: Uuid)
Example:
val heartRateFilter = ServiceFilter(
Uuid("0000180D-0000-1000-8000-00805F9B34FB")
)
blueFalcon.scan(filters = listOf(heartRateFilter))
Connection state enum.
enum class BluetoothPeripheralState {
Connected,
Connecting,
Disconnected,
Disconnecting
}
Bluetooth adapter state.
enum class BluetoothManagerState {
Unknown,
Resetting,
Unsupported,
Unauthorized,
PoweredOff,
PoweredOn
}
Connection priority levels (Android).
enum class ConnectionPriority {
Balanced,
High,
LowPower
}
Core interface that all platform engines implement.
interface BlueFalconEngine {
val scope: CoroutineScope
val peripherals: StateFlow<Set<BluetoothPeripheral>>
val managerState: StateFlow<BluetoothManagerState>
val isScanning: Boolean
suspend fun scan(filters: List<ServiceFilter> = emptyList())
suspend fun stopScanning()
// ... all BlueFalcon methods
}
class AndroidBlueFalconEngine(
context: Context,
autoDiscoverServices: Boolean = true
) : BlueFalconEngine
Dependencies:
androidMain.dependencies {
implementation("dev.bluefalcon:blue-falcon-engine-android:3.0.0")
}
Example:
val engine = AndroidBlueFalconEngine(
context = applicationContext,
autoDiscoverServices = true
)
class IosBlueFalconEngine : BlueFalconEngine
Dependencies:
iosMain.dependencies {
implementation("dev.bluefalcon:blue-falcon-engine-ios:3.0.0")
}
Example:
val engine = IosBlueFalconEngine()
class MacOSBlueFalconEngine : BlueFalconEngine
Dependencies:
macosMain.dependencies {
implementation("dev.bluefalcon:blue-falcon-engine-macos:3.0.0")
}
class JsBlueFalconEngine : BlueFalconEngine
Dependencies:
jsMain.dependencies {
implementation("dev.bluefalcon:blue-falcon-engine-js:3.0.0")
}
Browser support: Chrome, Edge, Opera
class WindowsBlueFalconEngine : BlueFalconEngine
Dependencies:
windowsMain.dependencies {
implementation("dev.bluefalcon:blue-falcon-engine-windows:3.0.0")
}
Requirements: Windows 10 version 1803+
class RpiBlueFalconEngine : BlueFalconEngine
Dependencies:
rpiMain.dependencies {
implementation("dev.bluefalcon:blue-falcon-engine-rpi:3.0.0")
}
Configuration builder for DSL-based initialization.
class BlueFalconConfig {
lateinit var engine: BlueFalconEngine
fun <T : BlueFalconPlugin> install(
plugin: T,
configure: PluginConfig.() -> Unit = {}
)
}
Example:
val blueFalcon = BlueFalcon {
engine = AndroidBlueFalconEngine(context)
install(LoggingPlugin) {
level = LogLevel.DEBUG
logger = PrintLnLogger
}
install(RetryPlugin) {
maxRetries = 3
initialDelay = 500.milliseconds
}
}
sealed class BluetoothException : Exception()
class BluetoothUnknownException : BluetoothException()
class BluetoothResettingException : BluetoothException()
class BluetoothUnsupportedException : BluetoothException()
class BluetoothPermissionException : BluetoothException()
class BluetoothNotEnabledException : BluetoothException()
try {
blueFalcon.connect(peripheral)
} catch (e: BluetoothPermissionException) {
// Request permissions
} catch (e: BluetoothNotEnabledException) {
// Prompt user to enable Bluetooth
} catch (e: BluetoothException) {
// Handle other BLE errors
}
Plugin hooks receive Result<T> for operations:
override suspend fun onAfterConnect(call: ConnectCall, result: Result<Unit>) {
result.fold(
onSuccess = { println("Connected!") },
onFailure = { error -> println("Failed: $error") }
)
}
val peripherals: StateFlow<Set<BluetoothPeripheral>>
Example:
lifecycleScope.launch {
blueFalcon.peripherals.collect { devices ->
println("Found ${devices.size} devices")
updateUI(devices)
}
}
val managerState: StateFlow<BluetoothManagerState>
Example:
lifecycleScope.launch {
blueFalcon.managerState.collect { state ->
when (state) {
BluetoothManagerState.PoweredOn -> startScanning()
BluetoothManagerState.PoweredOff -> showBluetoothDisabledMessage()
BluetoothManagerState.Unauthorized -> requestPermissions()
else -> {}
}
}
}
lifecycleScope.launch {
combine(
blueFalcon.peripherals,
blueFalcon.managerState
) { devices, state ->
Pair(devices, state)
}.collect { (devices, state) ->
if (state == BluetoothManagerState.PoweredOn) {
updateDeviceList(devices)
}
}
}
// Initialize
val blueFalcon = BlueFalcon {
engine = AndroidBlueFalconEngine(context)
}
// Scan
blueFalcon.scan()
// Monitor discovered devices
blueFalcon.peripherals.collect { devices -> }
// Connect
blueFalcon.connect(peripheral)
// Discover services
blueFalcon.discoverServices(peripheral)
// Read characteristic
blueFalcon.readCharacteristic(peripheral, characteristic)
val value = characteristic.value
// Write characteristic
blueFalcon.writeCharacteristic(peripheral, characteristic, "data")
// Enable notifications
blueFalcon.notifyCharacteristic(peripheral, characteristic, true)
// Disconnect
blueFalcon.disconnect(peripheral)
| Platform | Engine | Context Required |
|---|---|---|
| Android | AndroidBlueFalconEngine |
✅ Android Context |
| iOS | IosBlueFalconEngine |
❌ None |
| macOS | MacOSBlueFalconEngine |
❌ None |
| JavaScript | JsBlueFalconEngine |
❌ None |
| Windows | WindowsBlueFalconEngine |
❌ None |
| Raspberry Pi | RpiBlueFalconEngine |
❌ None |
Need help? Open an issue on GitHub or check the examples in the examples/ directory.