Loading repository data…
Loading repository data…
atick-faisal / repository
Boilerplate for Bluetooth Low Energy (BLE) Applications
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
The template has 3 separate modules.
app module contains all the UI related code.core module contains all the common dependencises and base classes used by other modules.ble module contains all the code required for BLE applications.The ble module provides 2 easy to use interfaces (BleUtils and BleManager) for implementating BLE tasks. It uses Dagger-Hilt for providing the interfaces. Use the @Inject annotation for injecting these interfaces into your ViewModels, Fragments or Activities.
Example injection in an Activity:
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
lateinit var bleUtils: BleUtils
...
}
Example injection in a ViewModel:
@HiltViewModel
class MyViewModel @Inject constructor(
private val bleManager: BleManager
) : ViewModel() {
...
}
This interface provides utilities for Permission Management and Enabling Bluetooth.
interface BleUtils {
fun initialize(activity: ComponentActivity, onSuccess: () -> Unit)
fun isAllPermissionsProvided(activity: ComponentActivity): Boolean
fun setupBluetooth(activity: ComponentActivity)
}
initialize: Initializes the callbacks for permission/bluetooth enable request. MUST be called in the onCreate() method of the lifecycle before calling setupBluetooth.isAllPermissionsProvided: (Optional) For checking if all the permissions are granted for using Bluetooth.setupBluetooth: Asks for permission if not granted already and enables bluetooth if not already. Should be called in the onResume() method.This interface provides utilities for BLE I/O operations.
interface BleManager {
val loading: LiveData<Event<Boolean>>
fun setBleCallbacks(
onDeviceFound: (BleDevice) -> Unit,
onConnectionChange: (ConnectionStatus) -> Unit,
onServiceDiscovered: (List<BleService>) -> Unit,
onCharacteristicRead: (BleCharacteristic) -> Unit,
onCharacteristicChange: (BleCharacteristic) -> Unit,
onCharacteristicWrite: (BleCharacteristic) -> Unit = {}
)
fun startScan()
fun stopScan()
fun connect(context: Context, address: String)
fun disconnect()
fun discoverServices()
fun readCharacteristic(serviceUuid: String, charUuid: String)
fun writeCharacteristic(serviceUuid: String, charUuid: String, payload: ByteArray)
fun enableNotification(serviceUuid: String, charUuid: String)
fun disableNotification(serviceUuid: String, charUuid: String)
}
The loading LiveData provides live update of any ongoing process. The BLE operations (discover/read/write) MUST be done sequentially. An operation can not be initiated while any othe roperation is going on. The operations can be queued using a Queuing API. But that's more advanced and I wish to do that in the future.
The other functions are self explanatory in my opinion. Example implementation of these can be found in the MainActivity.
setBleCallbacks method should be called before doing any BLE operation. Otherwise there will be missed callback events.disconnect method when you no longer need BLE to free up the resources.Unfortunatelly the official Android BLE documentation is not clear enough and skips some of the important details. So a BIG THANKS goes to the authors of this article for breaking things down more clearly.
This code was written with simplicity and readibility in mind and by no means the most optimized solution. But there are better alternatives:
This work is licensed under MIT License.