SkillAgentSearch skills...

QsBle

The Android Ble framework supports Kotlin coroutine, chain call, mtu subcontracting and packaging, and perfect ota support, perfectly adapting to the current Android development and programming style

Install / Use

/learn @zqisheng/QsBle
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

QsBle is an Android Ble framework

中文文档

English Document

Click to download demo

Features

  • Compared with the old Ble framework, it is more in line with the code style of current Android developers
  • Fully functional programming, all Ble callbacks are functional
  • Supports callbacks for all Ble operations
  • The data sent exceeds mtu, and QsBle also has a perfect packet grouping mechanism
  • Support disconnection and automatic reconnection
  • Supports Kotlin coroutines, allowing you to operate asynchronous code in a synchronous way without worrying about the various callback hells of Bluetooth
  • Support Flow
  • Supports chain programming, allowing you to perform various operations on Bluetooth sequentially. The logic that could only be implemented in hundreds of lines of code before, QsBle only needs one line of code
  • Perfect ota support, you only need to provide your ota file, all other operations are handed over to QsBle
  • The perfect exception handling mechanism allows you to locate the problem in time when an exception occurs.
  • The core code is written in Java, and people who develop in Java do not need to worry about the inability to use Java, and Kotlin calls Java code also provides various nullability mechanisms, so that you don't have to worry about the null pointer of Kotlin calling Java code
  • Other Ble frameworks have some, and QsBle also has them

Add dependencies

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }


dependencies {
    //Dependencies that QsBle must add
   implementation 'com.github.zqisheng.QsBle:ble:1.2.6
    //If you want to use the kotlin coroutine function, you must add the following dependencies, not required
   //implementation 'com.github.zqisheng.QsBle:ble_coroutines:1.2.6
}

Before use

Adding permissions for Bluetooth scanning needs to be added, and apply for permissions at runtime

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

For the Bluetooth adaptation of Android 12, the following three permissions have been added by default in the framework, so there is no need to add them manually, but these three permissions are dynamically applied for permissions. In Android 12 and above, they must be dynamically applied in the code.

<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

Initialization

Usage 1(Recommend):

QsBle.getInstance().init(Context context);

Usage 2:

QsBle.getInstance().init(Context context,Handler handler);

Note 1: All operations and callbacks of QsBle to Ble are executed in one thread. The initialization of mode 1 is to use the thread implemented by the framework to operate Ble by default. But if you want all operations of Ble to be specified by yourself You can also pass in a Handler, so that all Ble operations and callbacks will be called in the specified Handler <br/>For example, if you want all operations to be called back in the main thread, you can pass a The Handler of the main thread, so that all Ble operations and callbacks are called back in the main thread, but the author strongly does not recommend doing this

Note 2: The initialization of QsBle will not obtain any private information of the user's mobile phone, so rest assured to initialize at any time

Simple to use

Usage 1:

QsBle.getInstance().startScan();
QsBle.getInstance().connect(mac);
QsBle.getInstance().connect(mac);
QsBle.getInstance().openNotify(mac,serviceuuid,notifyUuid);
QsBle.getInstance().writeByLock(mac,serviceUuid,writeUuid,value)
....

Usage 2(Chain)(Java Recommended):

QsBle.getInstance().chain(mac)
    .connect()...
    .openNotify(serviceUuid,notifyUuid)...
    .requestConnectionToHigh()...
    .writeByLock(serviceUuid,writeUuid,value)...
    .writeByLock(serviceUuid,writeUuid,value)...
    .writeByLock(serviceUuid,writeUuid,value)...
    .disconnect()...
    ...
    .start()

Note: The above chain operation process is: first connect to the device whose address is mac. After the connection is successful, the notify of the device will be opened. After the notify is opened successfully, the Connection parameter will be set. After the parameter is set successfully, data will be written to the feature. , After the framework confirms that the data is written successfully, it will disconnect the connection of the device, and any part of the link will not continue to execute if it does not achieve the expected result

Usage 3(Kotlin coroutines)(Kotlin Recommended)

//Use kotlin coroutine to implement the operation of mode 2
bleLifeScope.launch ({
    val chain = ble.chain(mac)
    //true:connection succeeded
    val isConnect:Boolean=chain.connect().reConnectCount(3).connectTimeout(7000).dump(false).await()
    //Three values: notification, indication, disable, the first two are notifications already turned on
    val notifyStatus1:String?=chain.openNotify(serviceUuid,notifyUuid).dump(false).retry(3).await()
    val notifyStatus2:String?=chain.cancelNotify().await()
    //new int[]{interval, latency, timeout}
    //As long as it is not empty, the setting is successful
    val status1:IntArray?=chain.requestConnectionToLowPower().dump(false).await()
    val status2:IntArray?=chain.requestConnectionToBalanced().dump(false).await()
    val status3:IntArray?=chain.requestConnectionToHigh().dump(false).await()
    //true: write successfully false: write failed
    val status4:Boolean=chain.writeByLock(serviceUuid,writeUuid,value).dump(false).await()
    //true: write successfully false: write failed
    //The speed of norsp is about 3-30 times faster than that without norsp, which is related to the connection parameters of the device
    val status5:Boolean=chain.writeByLockNoRsp(serviceUuid,writeUuid,value).dump(false).await()
    //Returns the value of the characteristic value in the device
    val readValue:ByteArray?=chain.read(serviceUuid,readUuid).dump(false).await()
    //Returns the value of the description in the device
    val readDescValue:ByteArray?=chain.readDesc(serviceUuid,readUuid,descUuid).dump(false).await()
    //new int[]{txPhy,rxPhy}
    val phy:IntArray?=chain.readPhy().await()
    //return rssi
    val rssi:Int?=chain.readRssi().await()
    //Returns the mtu that has been successfully set, and if it is null, the setting fails.
    val mtu:Int?=chain.requestMtu(517).await()
    //Disconnect
    chain.disconnect().await()
},onError = {
    //The coroutine execution error will be called, and the callback will be in the main thread
},onStart = {
   //Called before the execution of the coroutine starts, the callback is in the main thread
},onFinally = {
    //Regardless of the success or failure of the coroutine execution, this method will eventually be called, and the callback is in the main thread
})

Note: bleLifeScope is an extension object of the Lifecycle object. When the Lifecycle is destroyed, bleLifeScope will automatically interrupt the internal Bluetooth coroutine operation and destroy the coroutine

Description of public operators

The characteristics of these operators are that all chained operations are supported. Using each operator together can solve some very complex scenarios.

Operator1:dump(boolean dump)<br/> Explanation:Whether the current chained segment ends the whole execution chain when the execution fails. The default value is true, which ends the whole chain<br/> Chain:

//Connect 5 devices directly by chain
QsBle.getInstance().chain()
    .connect(mac1)...
    .connect(mac2).dump(false)...
    .connect(mac3).dump(true)...//The default is true, which can not be set
    .connect(mac4)
    .connect(mac5)
    .start()

Explanation:After the connection of mac1 is successful, it will connect to mac2. If the connection of mac2 fails, such as the connection timeout or the system returns an error, will mac3 continue to connect? The answer is whether it will continue to connect. Because the dump of mac2 chain is false, even if the connection fails, it will not interrupt the whole chain. Mac3 will continue to connect after the connection of mac2 fails. If the connection of mac3 fails, it will also fail? Because dump=true, the execution of the whole chain is interrupted directly, and mac4 and mac5 will not perform connection operations later<br/> Coroutine:

bleLifeScope.launch ({
    //Connect 5 devices directly by chain
    QsBle.getInstance().chain().apply{
        connect(mac1).await()
        connect(mac2).dump(false).await()
        connect(mac3).dump(true).await()//The default is true, which can not be set
        connect(mac4).await()
        connect(mac5).await()
    }
},onError = {
    //The coroutine execution error will be called, and the callback will be in the main thread
},onStart = {
   //Called before the execution of the coroutine starts, the callback is in the main thread
},onFinally = {
    //Regardless of the success or failure of the coroutine execution, this method will eventually be called, and the callback is in the main thread
})

**Explanation:The chain execution process is the same as that above. The only difference in the collaboration process is that when the dump of this chain=true, the connection failure occurs, and an exception will be thrown directly in the collaboration process. Therefore, when the connection to the mac3 fails, the onErro functio

View on GitHub
GitHub Stars88
CategoryDevelopment
Updated28d ago
Forks13

Languages

Java

Security Score

100/100

Audited on Mar 2, 2026

No findings