BLE Bluetooth Low Energy + Compose Guide
Integrate Bluetooth Low Energy for IoT devices. Handle permissions, scanning, and GATT communication in Compose.
Permissions Setup
// AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
Request runtime permissions:
val permissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
// Handle permission results
}
BLE Scanning
class BleViewModel : ViewModel() {
private val _devices = MutableStateFlow<List<BluetoothDevice>>(emptyList())
val devices: StateFlow<List<BluetoothDevice>> = _devices.asStateFlow()
fun startScanning(context: Context) {
val bluetoothManager = context.getSystemService(BluetoothManager::class.java)
val scanner = bluetoothManager.adapter.bluetoothLeScanner
val scanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
val device = result.device
_devices.value = (_devices.value + device).distinctBy { it.address }
}
}
scanner.startScan(scanCallback)
}
}
GATT Connection
fun connectToDevice(context: Context, device: BluetoothDevice) {
val gattCallback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices()
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
if (status == BluetoothGatt.GATT_SUCCESS) {
val services = gatt.services
// Handle discovered services
}
}
}
device.connectGatt(context, false, gattCallback)
}
Compose UI
@Composable
fun BleDeviceList(viewModel: BleViewModel) {
val devices by viewModel.devices.collectAsState()
LazyColumn {
items(devices) { device ->
DeviceCard(device = device, onClick = { viewModel.connectToDevice(it) })
}
}
}
Best Practices
- Always check permissions before scanning
- Stop scanning when not needed (battery drain)
- Handle GATT disconnections gracefully
- Use coroutines for background scanning
8 Android app templates on Gumroad
Top comments (0)