Implement readRSSI on Android and Darwin (#203)

This commit is contained in:
EricKwok
2026-01-06 00:25:19 +08:00
committed by Foti Dim
parent a5b6af6168
commit 1adfa9b485
25 changed files with 456 additions and 91 deletions
+3
View File
@@ -1,3 +1,6 @@
## 1.1.0
* Add readRssi method
## 1.0.1
* Enforce C++20 standard for Windows builds
+16
View File
@@ -131,3 +131,19 @@ This method will **attempt** to set the MTU (Maximum Transmission Unit) but it i
```dart
int mtu = await UniversalBle.requestMtu(widget.deviceId, 247);
```
### Read RSSI
Read the signal strength (RSSI) of a connected device.
```dart
int rssi = await UniversalBle.readRssi(deviceId);
```
> ⚠️ Note: The device must be connected before reading RSSI.
#### Platform Limitations
* **Android / iOS / macOS**: Fully supported.
* **Windows / Linux / Web**: Not supported.
+20 -1
View File
@@ -27,6 +27,7 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE
- [Pairing](#pairing)
- [Bluetooth Availability](#bluetooth-availability)
- [Requesting MTU](#requesting-mtu)
- [Reading RSSI](#reading-rssi)
- [Command Queue](#command-queue)
- [Timeout](#timeout)
- [Error Handling](#error-handling)
@@ -52,6 +53,7 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE
| enable/disable Bluetooth | ✔️ | ❌ | ❌ | ✔️ | ✔️ | ❌ |
| onAvailabilityChange | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| requestMtu | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ |
| readRssi | ✔️ | ✔️ | ✔️ | ❌ | 🚧 | ❌ |
| requestPermissions | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
## Getting Started
@@ -409,7 +411,7 @@ UniversalBle.disableBluetooth();
```dart
int mtu = await bleDevice.requestMtu(256);
````
```
> ⚠️ Note: Requesting an MTU is a *best-effort* operation.
> On many platforms the final MTU is fully controlled by the OS and remote device.
@@ -460,6 +462,23 @@ When developing cross-platform BLE applications and devices:
* Take advantage of higher MTUs when available, without depending on them
### Reading RSSI
Read the signal strength (RSSI) of a connected device.
```dart
int rssi = await bleDevice.readRssi();
```
> ⚠️ Note: The device must be connected before reading RSSI.
#### Platform Limitations
* **Android / iOS / macOS**: Fully supported.
* **Windows / Linux / Web**: Not supported.
## Command Queue
By default, all commands are executed in a global queue (`QueueType.global`), with each command waiting for the previous one to finish. While this method is slower it is the safest to avoid command exceptions and therefore is the default.
@@ -529,6 +529,7 @@ interface UniversalBlePlatformChannel {
fun unPair(deviceId: String)
fun getSystemDevices(withServices: List<String>, callback: (Result<List<UniversalBleScanResult>>) -> Unit)
fun getConnectionState(deviceId: String): Long
fun readRssi(deviceId: String, callback: (Result<Long>) -> Unit)
fun setLogLevel(logLevel: UniversalBleLogLevel)
companion object {
@@ -919,6 +920,26 @@ interface UniversalBlePlatformChannel {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val deviceIdArg = args[0] as String
api.readRssi(deviceIdArg) { result: Result<Long> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else {
val data = result.getOrNull()
reply.reply(UniversalBlePigeonUtils.wrapResult(data))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$separatedMessageChannelSuffix", codec)
if (api != null) {
@@ -344,3 +344,8 @@ class SubscriptionResultFuture(
val serviceId: String,
val result: (Result<Unit>) -> Unit,
)
class RssiResultFuture(
val deviceId: String,
val result: (Result<Long>) -> Unit,
)
@@ -60,6 +60,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
private val writeResultFutureList = mutableListOf<WriteResultFuture>()
private val subscriptionResultFutureList = mutableListOf<SubscriptionResultFuture>()
private val pairResultFutures = mutableMapOf<String, (Result<Boolean>) -> Unit>()
private val rssiResultFutureList = mutableListOf<RssiResultFuture>()
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
UniversalBlePlatformChannel.setUp(flutterPluginBinding.binaryMessenger, this)
@@ -279,6 +280,49 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
UniversalBleLogger.setLogLevel(logLevel)
}
override fun readRssi(deviceId: String, callback: (Result<Long>) -> Unit) {
try {
val gatt = deviceId.toBluetoothGatt()
if (gatt.readRemoteRssi()) {
rssiResultFutureList.add(RssiResultFuture(deviceId, callback))
} else {
callback(
Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to read RSSI"
)
)
)
}
} catch (e: FlutterError) {
callback(Result.failure(e))
}
}
override fun onReadRemoteRssi(gatt: BluetoothGatt?, rssi: Int, status: Int) {
val deviceId = gatt?.device?.address ?: return
rssiResultFutureList.removeAll {
if (it.deviceId == deviceId) {
if (status == BluetoothGatt.GATT_SUCCESS) {
it.result(Result.success(rssi.toLong()))
} else {
it.result(
Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to read RSSI"
)
)
)
}
true
} else {
false
}
}
}
override fun discoverServices(
deviceId: String,
withDescriptors: Boolean,
@@ -311,36 +355,44 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
if (status != BluetoothGatt.GATT_SUCCESS) {
discoverServicesFutureList.filter { it.deviceId == gatt.device.address }.forEach {
discoverServicesFutureList.remove(it)
it.result(
Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to discover services"
discoverServicesFutureList.removeAll {
if (it.deviceId == gatt.device.address) {
it.result(
Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to discover services"
)
)
)
)
true
} else {
false
}
}
return
}
setCachedServices(gatt.device.address, gatt.services.map { it.uuid.toString() })
discoverServicesFutureList.filter { it.deviceId == gatt.device.address }.forEach {
discoverServicesFutureList.remove(it)
it.result(Result.success(gatt.services.map { service ->
UniversalBleService(
uuid = service.uuid.toString(),
characteristics = service.characteristics.map { char ->
UniversalBleCharacteristic(
uuid = char.uuid.toString(),
properties = char.getPropertiesList(),
descriptors = if (it.withDescriptors) char.descriptors.map { descriptor ->
UniversalBleDescriptor(descriptor.uuid.toString())
} else listOf()
)
}
)
}))
discoverServicesFutureList.removeAll {
if (it.deviceId == gatt.device.address) {
it.result(Result.success(gatt.services.map { service ->
UniversalBleService(
uuid = service.uuid.toString(),
characteristics = service.characteristics.map { char ->
UniversalBleCharacteristic(
uuid = char.uuid.toString(),
properties = char.getPropertiesList(),
descriptors = if (it.withDescriptors) char.descriptors.map { descriptor ->
UniversalBleDescriptor(descriptor.uuid.toString())
} else listOf()
)
}
)
}))
true
} else {
false
}
}
}
@@ -517,29 +569,31 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
value: ByteArray,
status: Int,
) {
readResultFutureList.filter {
it.deviceId == gatt.device.address &&
it.characteristicId == characteristic.uuid.toString() &&
it.serviceId == characteristic.service.uuid.toString()
}.forEach {
readResultFutureList.remove(it)
if (status == BluetoothGatt.GATT_SUCCESS) {
it.result(Result.success(value))
} else {
UniversalBleLogger.logError(
"READ_FAILED <- ${gatt.device.address} ${characteristic.uuid} status=$status"
)
it.result(
Result.failure(
createFlutterError(
gattStatusToUniversalBleErrorCode(status),
"Failed to read",
status.toString()
readResultFutureList.removeAll {
if (it.deviceId == gatt.device.address &&
it.characteristicId == characteristic.uuid.toString() &&
it.serviceId == characteristic.service.uuid.toString()
) {
if (status == BluetoothGatt.GATT_SUCCESS) {
it.result(Result.success(value))
} else {
UniversalBleLogger.logError(
"READ_FAILED <- ${gatt.device.address} ${characteristic.uuid} status=$status"
)
it.result(
Result.failure(
createFlutterError(
gattStatusToUniversalBleErrorCode(status),
"Failed to read",
status.toString()
)
)
)
)
}
true
} else {
false
}
}
}
@@ -640,27 +694,30 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
characteristic: BluetoothGattCharacteristic,
status: Int,
) {
writeResultFutureList.filter {
it.deviceId == gatt?.device?.address &&
it.characteristicId == characteristic.uuid.toString() &&
it.serviceId == characteristic.service.uuid.toString()
}.forEach {
writeResultFutureList.remove(it)
if (status == BluetoothGatt.GATT_SUCCESS) {
it.result(Result.success(Unit))
} else {
UniversalBleLogger.logError(
"WRITE_FAILED <- ${gatt?.device?.address} ${characteristic.uuid} status=$status"
)
it.result(
Result.failure(
createFlutterError(
gattStatusToUniversalBleErrorCode(status),
"Failed to write",
status.toString()
writeResultFutureList.removeAll {
if (it.deviceId == gatt?.device?.address &&
it.characteristicId == characteristic.uuid.toString() &&
it.serviceId == characteristic.service.uuid.toString()
) {
if (status == BluetoothGatt.GATT_SUCCESS) {
it.result(Result.success(Unit))
} else {
UniversalBleLogger.logError(
"WRITE_FAILED <- ${gatt?.device?.address} ${characteristic.uuid} status=$status"
)
it.result(
Result.failure(
createFlutterError(
gattStatusToUniversalBleErrorCode(status),
"Failed to write",
status.toString()
)
)
)
)
}
true
} else {
false
}
}
}
@@ -679,19 +736,23 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
val deviceId = gatt?.device?.address ?: return
mtuResultFutureList.filter { it.deviceId == deviceId }.forEach {
mtuResultFutureList.remove(it)
if (status == BluetoothGatt.GATT_SUCCESS) {
it.result(Result.success(mtu.toLong()))
} else {
it.result(
Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to change MTU"
mtuResultFutureList.removeAll {
if (it.deviceId == deviceId) {
if (status == BluetoothGatt.GATT_SUCCESS) {
it.result(Result.success(mtu.toLong()))
} else {
it.result(
Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to change MTU"
)
)
)
)
}
true
} else {
false
}
}
}
@@ -941,6 +1002,14 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
false
}
}
rssiResultFutureList.removeAll {
if (it.deviceId == gatt.device.address) {
it.result(Result.failure(deviceDisconnectedError))
true
} else {
false
}
}
}
private fun onBondStateUpdate(deviceId: String, bonded: Boolean, error: String? = null) {
@@ -1116,24 +1185,27 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
service: String,
status: Int,
) {
subscriptionResultFutureList.filter {
it.deviceId == deviceId &&
it.characteristicId == characteristic &&
it.serviceId == service
}.forEach {
subscriptionResultFutureList.remove(it)
if (status != BluetoothGatt.GATT_SUCCESS) {
it.result(
Result.failure(
createFlutterError(
gattStatusToUniversalBleErrorCode(status),
"Failed to update subscription state",
status.toString()
subscriptionResultFutureList.removeAll {
if (it.deviceId == deviceId &&
it.characteristicId == characteristic &&
it.serviceId == service
) {
if (status != BluetoothGatt.GATT_SUCCESS) {
it.result(
Result.failure(
createFlutterError(
gattStatusToUniversalBleErrorCode(status),
"Failed to update subscription state",
status.toString()
)
)
)
)
} else {
it.result(Result.success(Unit))
}
true
} else {
it.result(Result.success(Unit))
false
}
}
}
+18
View File
@@ -548,6 +548,7 @@ protocol UniversalBlePlatformChannel {
func unPair(deviceId: String) throws
func getSystemDevices(withServices: [String], completion: @escaping (Result<[UniversalBleScanResult], Error>) -> Void)
func getConnectionState(deviceId: String) throws -> Int64
func readRssi(deviceId: String, completion: @escaping (Result<Int64, Error>) -> Void)
func setLogLevel(logLevel: UniversalBleLogLevel) throws
}
@@ -882,6 +883,23 @@ class UniversalBlePlatformChannelSetup {
} else {
getConnectionStateChannel.setMessageHandler(nil)
}
let readRssiChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
readRssiChannel.setMessageHandler { message, reply in
let args = message as! [Any?]
let deviceIdArg = args[0] as! String
api.readRssi(deviceId: deviceIdArg) { result in
switch result {
case .success(let res):
reply(wrapResult(res))
case .failure(let error):
reply(wrapError(error))
}
}
}
} else {
readRssiChannel.setMessageHandler(nil)
}
let setLogLevelChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
setLogLevelChannel.setMessageHandler { message, reply in
+10
View File
@@ -258,3 +258,13 @@ class DiscoverServicesFuture {
self.result = result
}
}
class RssiReadFuture {
let deviceId: String
let result: (Result<Int64, Error>) -> Void
init(deviceId: String, result: @escaping (Result<Int64, Error>) -> Void) {
self.deviceId = deviceId
self.result = result
}
}
+35
View File
@@ -40,6 +40,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
private var characteristicWriteWithoutResponseFutures = [CharacteristicWriteFuture]()
private var characteristicNotifyFutures = [CharacteristicNotifyFuture]()
private var discoverServicesFutures = [DiscoverServicesFuture]()
private var rssiReadFutures = [RssiReadFuture]()
private var isManageScanning = false
init(callbackChannel: UniversalBleCallbackChannel) {
@@ -200,6 +201,15 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
}
return false
}
rssiReadFutures.removeAll { future in
if future.deviceId == deviceId {
future.result(
Result.failure(createFlutterError(code: .deviceDisconnected, message: "Device Disconnected"))
)
return true
}
return false
}
activeServiceDiscoveries[deviceId]?.cleanup()
activeServiceDiscoveries[deviceId] = nil
}
@@ -334,6 +344,16 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
completion(Result.success(mtuResult))
}
func readRssi(deviceId: String, completion: @escaping (Result<Int64, Error>) -> Void) {
UniversalBleLogger.shared.logDebug("READ_RSSI -> \(deviceId)")
guard let peripheral = deviceId.findPeripheral(manager: manager) else {
completion(Result.failure(createFlutterError(code: .deviceNotFound, message: "Unknown deviceId:\(deviceId)")))
return
}
peripheral.readRSSI()
rssiReadFutures.append(RssiReadFuture(deviceId: deviceId, result: completion))
}
func isPaired(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) {
completion(Result.failure(createFlutterError(code: .notSupported)))
}
@@ -531,6 +551,21 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
return false
}
}
public func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
rssiReadFutures.removeAll { future in
if future.deviceId == peripheral.uuid.uuidString {
if let flutterError = error?.toFlutterError() {
UniversalBleLogger.shared.logError("READ_RSSI_FAILED <- \(peripheral.uuid.uuidString): \(flutterError.message ?? "")")
future.result(Result.failure(flutterError))
} else {
future.result(Result.success(RSSI.int64Value))
}
return true
}
return false
}
}
}
extension CBPeripheral {
+6
View File
@@ -113,6 +113,12 @@ class MockUniversalBle extends UniversalBlePlatform {
return 512;
}
@override
Future<int> readRssi(String deviceId) async {
await Future.delayed(const Duration(milliseconds: 500));
return -50; // Mock RSSI value in dBm
}
@override
Future<void> setNotifiable(String deviceId, String service,
String characteristic, BleInputProperty bleInputProperty) async {}
@@ -1097,6 +1097,30 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
),
),
),
OutlinedButton.icon(
onPressed: isConnected
? () async {
try {
int rssi = await bleDevice.readRssi();
_addLog('RSSI', '$rssi dBm');
} catch (e) {
_addLog('ReadRssiError (${e.runtimeType})', e);
}
}
: null,
icon: const Icon(Icons.signal_cellular_alt),
label: const Text('Get RSSI'),
style: OutlinedButton.styleFrom(
foregroundColor: colorScheme.onSurface,
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
if (BleCapabilities.supportsRequestMtuApi)
ElevatedButton.icon(
onPressed: isConnected
+13
View File
@@ -26,6 +26,19 @@ class BleDevice {
Future<BleConnectionState> get connectionState =>
UniversalBle.getConnectionState(deviceId);
/// Read the RSSI value of this connected device.
///
/// Returns the current RSSI value in dBm. This value indicates the signal strength
/// between the device and the connected peripheral. Lower (more negative) values
/// indicate weaker signal, while higher (less negative) values indicate stronger signal.
///
/// **Note**: The device must be connected before reading RSSI.
///
/// Throws [BleException] if:
/// - The device is not connected
/// - Reading RSSI fails
Future<int> readRssi() => UniversalBle.readRssi(deviceId);
/// On web, it returns true if the web browser supports receiving advertisements from this device.
/// The rest of the platforms will always return true.
bool get receivesAdvertisements =>
+22
View File
@@ -340,6 +340,28 @@ class UniversalBle {
);
}
/// Read the RSSI value of a connected device.
///
/// Returns the current RSSI value in dBm. This value indicates the signal strength
/// between the device and the connected peripheral. Lower (more negative) values
/// indicate weaker signal, while higher (less negative) values indicate stronger signal.
///
/// **Note**: The device must be connected before reading RSSI.
///
/// Throws [BleException] if:
/// - The device is not connected
/// - Reading RSSI fails
static Future<int> readRssi(
String deviceId, {
Duration? timeout,
}) async {
return await _bleCommandQueue.queueCommand(
() => _platform.readRssi(deviceId),
timeout: timeout,
deviceId: deviceId,
);
}
/// Check if a device is paired.
///
/// For `Apple` and `Web`, you have to pass a "pairingCommand" with an encrypted read or write characteristic.
@@ -378,6 +378,14 @@ class UniversalBleLinux extends UniversalBlePlatform {
);
}
@override
Future<int> readRssi(String deviceId) async {
throw UniversalBleException(
code: UniversalBleErrorCode.notImplemented,
message: "readRssi is not implemented on Linux platform",
);
}
@override
Future<bool> pair(String deviceId) async {
BlueZDevice device = _findDeviceById(deviceId);
@@ -1106,6 +1106,35 @@ class UniversalBlePlatformChannel {
}
}
Future<int> readRssi(String deviceId) async {
final pigeonVar_channelName =
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[deviceId]);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else if (pigeonVar_replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (pigeonVar_replyList[0] as int?)!;
}
}
Future<void> setLogLevel(UniversalBleLogLevel logLevel) async {
final pigeonVar_channelName =
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$pigeonVar_messageChannelSuffix';
@@ -133,6 +133,10 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
_executeWithErrorHandling(
() => _channel.requestMtu(deviceId, expectedMtu));
@override
Future<int> readRssi(String deviceId) =>
_executeWithErrorHandling(() => _channel.readRssi(deviceId));
@override
Future<bool> isPaired(String deviceId) =>
_executeWithErrorHandling(() => _channel.isPaired(deviceId));
@@ -79,6 +79,8 @@ abstract class UniversalBlePlatform {
Future<int> requestMtu(String deviceId, int expectedMtu);
Future<int> readRssi(String deviceId);
Future<bool> isPaired(String deviceId);
Future<bool> pair(String deviceId);
@@ -283,6 +283,15 @@ class UniversalBleWeb extends UniversalBlePlatform {
);
}
/// `Unimplemented`
@override
Future<int> readRssi(String deviceId) {
throw UniversalBleException(
code: UniversalBleErrorCode.notImplemented,
message: "readRssi is not implemented on Web platform",
);
}
@override
Future<bool> isPaired(String deviceId) {
throw UniversalBleException(
+3
View File
@@ -93,6 +93,9 @@ abstract class UniversalBlePlatformChannel {
int getConnectionState(String deviceId);
@async
int readRssi(String deviceId);
void setLogLevel(UniversalBleLogLevel logLevel);
}
+1 -1
View File
@@ -1,6 +1,6 @@
name: universal_ble
description: A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE) plugin for Flutter
version: 1.0.1+3
version: 1.1.0
homepage: https://navideck.com
repository: https://github.com/Navideck/universal_ble
issue_tracker: https://github.com/Navideck/universal_ble/issues
+5
View File
@@ -132,4 +132,9 @@ class _UniversalBleMock extends UniversalBlePlatformMock {
Future<void> requestPermissions({bool withAndroidFineLocation = false}) {
throw UnimplementedError();
}
@override
Future<int> readRssi(String deviceId) async {
return -50; // Mock RSSI value
}
}
+29
View File
@@ -1189,6 +1189,35 @@ void UniversalBlePlatformChannel::SetUp(
channel.SetMessageHandler(nullptr);
}
}
{
BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi" + prepended_suffix, &GetCodec());
if (api != nullptr) {
channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply<EncodableValue>& reply) {
try {
const auto& args = std::get<EncodableList>(message);
const auto& encodable_device_id_arg = args.at(0);
if (encodable_device_id_arg.IsNull()) {
reply(WrapError("device_id_arg unexpectedly null."));
return;
}
const auto& device_id_arg = std::get<std::string>(encodable_device_id_arg);
api->ReadRssi(device_id_arg, [reply](ErrorOr<int64_t>&& output) {
if (output.has_error()) {
reply(WrapError(output.error()));
return;
}
EncodableList wrapped;
wrapped.push_back(EncodableValue(std::move(output).TakeValue()));
reply(EncodableValue(std::move(wrapped)));
});
} catch (const std::exception& exception) {
reply(WrapError(exception.what()));
}
});
} else {
channel.SetMessageHandler(nullptr);
}
}
{
BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel" + prepended_suffix, &GetCodec());
if (api != nullptr) {
+3
View File
@@ -435,6 +435,9 @@ class UniversalBlePlatformChannel {
const flutter::EncodableList& with_services,
std::function<void(ErrorOr<flutter::EncodableList> reply)> result) = 0;
virtual ErrorOr<int64_t> GetConnectionState(const std::string& device_id) = 0;
virtual void ReadRssi(
const std::string& device_id,
std::function<void(ErrorOr<int64_t> reply)> result) = 0;
virtual std::optional<FlutterError> SetLogLevel(const UniversalBleLogLevel& log_level) = 0;
// The codec used by UniversalBlePlatformChannel.
+7
View File
@@ -451,6 +451,13 @@ void UniversalBlePlugin::RequestMtu(
}
}
void UniversalBlePlugin::ReadRssi(
const std::string &device_id,
std::function<void(ErrorOr<int64_t> reply)> result) {
result(create_flutter_error(UniversalBleErrorCode::kNotImplemented,
"readRssi is not implemented on Windows platform"));
}
void UniversalBlePlugin::IsPaired(
const std::string &device_id,
std::function<void(ErrorOr<bool> reply)> result) {
+2
View File
@@ -200,6 +200,8 @@ private:
std::function<void(std::optional<FlutterError> reply)> result) override;
void RequestMtu(const std::string &device_id, int64_t expected_mtu,
std::function<void(ErrorOr<int64_t> reply)> result) override;
void ReadRssi(const std::string &device_id,
std::function<void(ErrorOr<int64_t> reply)> result) override;
void IsPaired(const std::string &device_id,
std::function<void(ErrorOr<bool> reply)> result) override;
void Pair(const std::string &device_id,