Add service-data in advertisements (#207)
* Add service-data in advertisements * Fix windows serviceData parsing * Resolve Ai comments * Resolve Ai comments and validate service data * Cleanup and Update changelog
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
## 1.2.0
|
## 1.2.0
|
||||||
* Add `autoConnect` parameter to `connect()` method for automatic reconnection support on Android and iOS/macOS
|
* Add `autoConnect` parameter to `connect()` method for automatic reconnection support on Android and iOS/macOS
|
||||||
|
* Add `serviceData` in `BleDevice`
|
||||||
|
|
||||||
## 1.1.0
|
## 1.1.0
|
||||||
* Add readRssi method
|
* Add readRssi method
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ data class UniversalBleScanResult (
|
|||||||
val isPaired: Boolean? = null,
|
val isPaired: Boolean? = null,
|
||||||
val rssi: Long? = null,
|
val rssi: Long? = null,
|
||||||
val manufacturerDataList: List<UniversalManufacturerData>? = null,
|
val manufacturerDataList: List<UniversalManufacturerData>? = null,
|
||||||
|
val serviceData: Map<String, ByteArray>? = null,
|
||||||
val services: List<String>? = null,
|
val services: List<String>? = null,
|
||||||
val timestamp: Long? = null
|
val timestamp: Long? = null
|
||||||
)
|
)
|
||||||
@@ -185,9 +186,10 @@ data class UniversalBleScanResult (
|
|||||||
val isPaired = pigeonVar_list[2] as Boolean?
|
val isPaired = pigeonVar_list[2] as Boolean?
|
||||||
val rssi = pigeonVar_list[3] as Long?
|
val rssi = pigeonVar_list[3] as Long?
|
||||||
val manufacturerDataList = pigeonVar_list[4] as List<UniversalManufacturerData>?
|
val manufacturerDataList = pigeonVar_list[4] as List<UniversalManufacturerData>?
|
||||||
val services = pigeonVar_list[5] as List<String>?
|
val serviceData = pigeonVar_list[5] as Map<String, ByteArray>?
|
||||||
val timestamp = pigeonVar_list[6] as Long?
|
val services = pigeonVar_list[6] as List<String>?
|
||||||
return UniversalBleScanResult(deviceId, name, isPaired, rssi, manufacturerDataList, services, timestamp)
|
val timestamp = pigeonVar_list[7] as Long?
|
||||||
|
return UniversalBleScanResult(deviceId, name, isPaired, rssi, manufacturerDataList, serviceData, services, timestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun toList(): List<Any?> {
|
fun toList(): List<Any?> {
|
||||||
@@ -197,6 +199,7 @@ data class UniversalBleScanResult (
|
|||||||
isPaired,
|
isPaired,
|
||||||
rssi,
|
rssi,
|
||||||
manufacturerDataList,
|
manufacturerDataList,
|
||||||
|
serviceData,
|
||||||
services,
|
services,
|
||||||
timestamp,
|
timestamp,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -133,6 +133,11 @@ val ScanResult.manufacturerDataList: List<UniversalManufacturerData>
|
|||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val ScanResult.serviceData: Map<String, ByteArray>
|
||||||
|
get() {
|
||||||
|
return scanRecord?.serviceData?.mapKeys { it.key.uuid.toString() } ?: emptyMap()
|
||||||
|
}
|
||||||
|
|
||||||
fun <T> SparseArray<T>.toList(): List<Pair<Int, T>> {
|
fun <T> SparseArray<T>.toList(): List<Pair<Int, T>> {
|
||||||
return (0 until size).map { index ->
|
return (0 until size).map { index ->
|
||||||
keyAt(index) to valueAt(index)
|
keyAt(index) to valueAt(index)
|
||||||
|
|||||||
@@ -844,6 +844,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
|||||||
deviceId = it.address,
|
deviceId = it.address,
|
||||||
isPaired = it.bondState == BOND_BONDED,
|
isPaired = it.bondState == BOND_BONDED,
|
||||||
manufacturerDataList = null,
|
manufacturerDataList = null,
|
||||||
|
serviceData = null,
|
||||||
rssi = null,
|
rssi = null,
|
||||||
timestamp = System.currentTimeMillis()
|
timestamp = System.currentTimeMillis()
|
||||||
)
|
)
|
||||||
@@ -1100,6 +1101,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
|||||||
|
|
||||||
val name = result.device.name
|
val name = result.device.name
|
||||||
val manufacturerDataList = result.manufacturerDataList
|
val manufacturerDataList = result.manufacturerDataList
|
||||||
|
val serviceData = result.serviceData
|
||||||
|
|
||||||
if (!universalBleFilterUtil.filterDevice(
|
if (!universalBleFilterUtil.filterDevice(
|
||||||
name,
|
name,
|
||||||
@@ -1116,6 +1118,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
|||||||
deviceId = result.device.address,
|
deviceId = result.device.address,
|
||||||
isPaired = result.device.bondState == BOND_BONDED,
|
isPaired = result.device.bondState == BOND_BONDED,
|
||||||
manufacturerDataList = manufacturerDataList,
|
manufacturerDataList = manufacturerDataList,
|
||||||
|
serviceData = serviceData,
|
||||||
rssi = result.rssi.toLong(),
|
rssi = result.rssi.toLong(),
|
||||||
services = serviceUuids.map { it.toString() }.toList(),
|
services = serviceUuids.map { it.toString() }.toList(),
|
||||||
timestamp = System.currentTimeMillis()
|
timestamp = System.currentTimeMillis()
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ struct UniversalBleScanResult: Hashable {
|
|||||||
var isPaired: Bool? = nil
|
var isPaired: Bool? = nil
|
||||||
var rssi: Int64? = nil
|
var rssi: Int64? = nil
|
||||||
var manufacturerDataList: [UniversalManufacturerData]? = nil
|
var manufacturerDataList: [UniversalManufacturerData]? = nil
|
||||||
|
var serviceData: [String: FlutterStandardTypedData]? = nil
|
||||||
var services: [String]? = nil
|
var services: [String]? = nil
|
||||||
var timestamp: Int64? = nil
|
var timestamp: Int64? = nil
|
||||||
|
|
||||||
@@ -224,8 +225,9 @@ struct UniversalBleScanResult: Hashable {
|
|||||||
let isPaired: Bool? = nilOrValue(pigeonVar_list[2])
|
let isPaired: Bool? = nilOrValue(pigeonVar_list[2])
|
||||||
let rssi: Int64? = nilOrValue(pigeonVar_list[3])
|
let rssi: Int64? = nilOrValue(pigeonVar_list[3])
|
||||||
let manufacturerDataList: [UniversalManufacturerData]? = nilOrValue(pigeonVar_list[4])
|
let manufacturerDataList: [UniversalManufacturerData]? = nilOrValue(pigeonVar_list[4])
|
||||||
let services: [String]? = nilOrValue(pigeonVar_list[5])
|
let serviceData: [String: FlutterStandardTypedData]? = nilOrValue(pigeonVar_list[5])
|
||||||
let timestamp: Int64? = nilOrValue(pigeonVar_list[6])
|
let services: [String]? = nilOrValue(pigeonVar_list[6])
|
||||||
|
let timestamp: Int64? = nilOrValue(pigeonVar_list[7])
|
||||||
|
|
||||||
return UniversalBleScanResult(
|
return UniversalBleScanResult(
|
||||||
deviceId: deviceId,
|
deviceId: deviceId,
|
||||||
@@ -233,6 +235,7 @@ struct UniversalBleScanResult: Hashable {
|
|||||||
isPaired: isPaired,
|
isPaired: isPaired,
|
||||||
rssi: rssi,
|
rssi: rssi,
|
||||||
manufacturerDataList: manufacturerDataList,
|
manufacturerDataList: manufacturerDataList,
|
||||||
|
serviceData: serviceData,
|
||||||
services: services,
|
services: services,
|
||||||
timestamp: timestamp
|
timestamp: timestamp
|
||||||
)
|
)
|
||||||
@@ -244,6 +247,7 @@ struct UniversalBleScanResult: Hashable {
|
|||||||
isPaired,
|
isPaired,
|
||||||
rssi,
|
rssi,
|
||||||
manufacturerDataList,
|
manufacturerDataList,
|
||||||
|
serviceData,
|
||||||
services,
|
services,
|
||||||
timestamp,
|
timestamp,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -148,9 +148,9 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
|||||||
// (e.g., in central manager delegate callbacks).
|
// (e.g., in central manager delegate callbacks).
|
||||||
UniversalBleLogger.shared.logInfo(
|
UniversalBleLogger.shared.logInfo(
|
||||||
"autoConnect requested for device \(deviceId), " +
|
"autoConnect requested for device \(deviceId), " +
|
||||||
"but automatic reconnection via CBConnectPeripheralOptionEnableAutoReconnect " +
|
"but automatic reconnection via CBConnectPeripheralOptionEnableAutoReconnect " +
|
||||||
"is only available on iOS 17+/macOS 14+/watchOS 10+/tvOS 17+. " +
|
"is only available on iOS 17+/macOS 14+/watchOS 10+/tvOS 17+. " +
|
||||||
"On this OS version, reconnections must be handled manually."
|
"On this OS version, reconnections must be handled manually."
|
||||||
)
|
)
|
||||||
manager.connect(peripheral)
|
manager.connect(peripheral)
|
||||||
}
|
}
|
||||||
@@ -410,6 +410,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
|||||||
return UniversalBleScanResult(
|
return UniversalBleScanResult(
|
||||||
deviceId: id,
|
deviceId: id,
|
||||||
name: name,
|
name: name,
|
||||||
|
serviceData: nil,
|
||||||
timestamp: Int64(Date().timeIntervalSince1970 * 1000)
|
timestamp: Int64(Date().timeIntervalSince1970 * 1000)
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
@@ -437,6 +438,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
|||||||
// Extract manufacturer data and service UUIDs from the advertisement data
|
// Extract manufacturer data and service UUIDs from the advertisement data
|
||||||
let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data
|
let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data
|
||||||
let services = (advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID])
|
let services = (advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID])
|
||||||
|
let serviceDataDict = advertisementData[CBAdvertisementDataServiceDataKey] as? [CBUUID: Data]
|
||||||
|
|
||||||
var manufacturerDataList: [UniversalManufacturerData] = []
|
var manufacturerDataList: [UniversalManufacturerData] = []
|
||||||
var universalManufacturerData: UniversalManufacturerData? = nil
|
var universalManufacturerData: UniversalManufacturerData? = nil
|
||||||
@@ -448,6 +450,13 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
|||||||
manufacturerDataList.append(universalManufacturerData!)
|
manufacturerDataList.append(universalManufacturerData!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var serviceData: [String: FlutterStandardTypedData]? = nil
|
||||||
|
if let serviceDataDict = serviceDataDict {
|
||||||
|
serviceData = Dictionary(uniqueKeysWithValues: serviceDataDict.map { uuid, data in
|
||||||
|
(uuid.uuidStr, FlutterStandardTypedData(bytes: data))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let advertisedName = advertisementData[CBAdvertisementDataLocalNameKey] as? String
|
let advertisedName = advertisementData[CBAdvertisementDataLocalNameKey] as? String
|
||||||
let displayName = advertisedName ?? peripheral.name
|
let displayName = advertisedName ?? peripheral.name
|
||||||
advertisementNameCache[peripheral.uuid.uuidString] = displayName
|
advertisementNameCache[peripheral.uuid.uuidString] = displayName
|
||||||
@@ -463,6 +472,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
|||||||
isPaired: nil,
|
isPaired: nil,
|
||||||
rssi: RSSI as? Int64,
|
rssi: RSSI as? Int64,
|
||||||
manufacturerDataList: manufacturerDataList,
|
manufacturerDataList: manufacturerDataList,
|
||||||
|
serviceData: serviceData,
|
||||||
services: services?.map { $0.uuidStr },
|
services: services?.map { $0.uuidStr },
|
||||||
timestamp: Int64(Date().timeIntervalSince1970 * 1000)
|
timestamp: Int64(Date().timeIntervalSince1970 * 1000)
|
||||||
)) { _ in }
|
)) { _ in }
|
||||||
@@ -481,7 +491,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
|||||||
public func centralManager(
|
public func centralManager(
|
||||||
_: CBCentralManager,
|
_: CBCentralManager,
|
||||||
didDisconnectPeripheral peripheral: CBPeripheral,
|
didDisconnectPeripheral peripheral: CBPeripheral,
|
||||||
timestamp: CFAbsoluteTime,
|
timestamp _: CFAbsoluteTime,
|
||||||
isReconnecting: Bool,
|
isReconnecting: Bool,
|
||||||
error: Error?
|
error: Error?
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ EXTERNAL SOURCES:
|
|||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||||
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
|
package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b
|
||||||
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
|
path_provider_foundation: 0b743cbb62d8e47eab856f09262bb8c1ddcfe6ba
|
||||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
|
||||||
universal_ble: 45519b2aeafe62761e2c6309f8927edb5288b914
|
universal_ble: 65e1257dffc557cc7991a93d253beeddc7c1dc92
|
||||||
url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd
|
url_launcher_macos: 175a54c831f4375a6cf895875f716ee5af3888ce
|
||||||
|
|
||||||
PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3
|
PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class BleDevice {
|
|||||||
List<String> services;
|
List<String> services;
|
||||||
bool? isSystemDevice;
|
bool? isSystemDevice;
|
||||||
List<ManufacturerData> manufacturerDataList;
|
List<ManufacturerData> manufacturerDataList;
|
||||||
|
Map<String, Uint8List> serviceData;
|
||||||
|
|
||||||
@Deprecated("Use `manufacturerDataList` instead")
|
@Deprecated("Use `manufacturerDataList` instead")
|
||||||
Uint8List? get manufacturerData => manufacturerDataList.isEmpty
|
Uint8List? get manufacturerData => manufacturerDataList.isEmpty
|
||||||
@@ -52,16 +53,28 @@ class BleDevice {
|
|||||||
this.services = const [],
|
this.services = const [],
|
||||||
this.isSystemDevice,
|
this.isSystemDevice,
|
||||||
this.manufacturerDataList = const [],
|
this.manufacturerDataList = const [],
|
||||||
|
Map<String, Uint8List> serviceData = const {},
|
||||||
this.timestamp,
|
this.timestamp,
|
||||||
}) {
|
}) : serviceData = _validateServiceData(serviceData),
|
||||||
rawName = name;
|
rawName = name,
|
||||||
this.name = name?.replaceAll(RegExp(r'[^ -~]'), '').trim();
|
name = name?.replaceAll(RegExp(r'[^ -~]'), '').trim();
|
||||||
}
|
|
||||||
|
|
||||||
DateTime? get timestampDateTime => timestamp != null
|
DateTime? get timestampDateTime => timestamp != null
|
||||||
? DateTime.fromMillisecondsSinceEpoch(timestamp!)
|
? DateTime.fromMillisecondsSinceEpoch(timestamp!)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
static Map<String, Uint8List> _validateServiceData(
|
||||||
|
Map<String, Uint8List> data,
|
||||||
|
) {
|
||||||
|
if (data.isEmpty) return const {};
|
||||||
|
return data.map(
|
||||||
|
(key, value) => MapEntry(
|
||||||
|
BleUuidParser.stringOrNull(key) ?? key,
|
||||||
|
Uint8List.fromList(value),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'BleDevice: '
|
return 'BleDevice: '
|
||||||
@@ -72,6 +85,7 @@ class BleDevice {
|
|||||||
'services: $services, '
|
'services: $services, '
|
||||||
'isSystemDevice: $isSystemDevice, '
|
'isSystemDevice: $isSystemDevice, '
|
||||||
'timestamp: $timestamp, '
|
'timestamp: $timestamp, '
|
||||||
'manufacturerDataList: $manufacturerDataList';
|
'manufacturerDataList: $manufacturerDataList, '
|
||||||
|
'serviceData: $serviceData';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,15 @@ class BleUuidParser {
|
|||||||
return uuid.toLowerCase();
|
return uuid.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a string to a valid 128-bit UUID or return null if the string is null or invalid.
|
||||||
|
static String? stringOrNull(String uuid) {
|
||||||
|
try {
|
||||||
|
return string(uuid);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse an int number into a 128-bit UUID string.
|
/// Parse an int number into a 128-bit UUID string.
|
||||||
/// e.g. `0x1800` to `00001800-0000-1000-8000-00805f9b34fb`.
|
/// e.g. `0x1800` to `00001800-0000-1000-8000-00805f9b34fb`.
|
||||||
static String number(int short) {
|
static String number(int short) {
|
||||||
|
|||||||
@@ -141,7 +141,11 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> connect(String deviceId, {Duration? connectionTimeout, bool autoConnect = false}) async {
|
Future<void> connect(
|
||||||
|
String deviceId, {
|
||||||
|
Duration? connectionTimeout,
|
||||||
|
bool autoConnect = false,
|
||||||
|
}) async {
|
||||||
// Note: autoConnect is not directly supported on Linux platform
|
// Note: autoConnect is not directly supported on Linux platform
|
||||||
final device = _findDeviceById(deviceId);
|
final device = _findDeviceById(deviceId);
|
||||||
if (device.connected) {
|
if (device.connected) {
|
||||||
@@ -696,6 +700,17 @@ extension BlueZDeviceExtension on BlueZDevice {
|
|||||||
ManufacturerData(data.key.id, Uint8List.fromList(data.value)))
|
ManufacturerData(data.key.id, Uint8List.fromList(data.value)))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
|
Map<String, Uint8List> get serviceDataMap {
|
||||||
|
try {
|
||||||
|
return {
|
||||||
|
for (final entry in serviceData.entries)
|
||||||
|
entry.key.toString(): Uint8List.fromList(entry.value),
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
return <String, Uint8List>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BleDevice toBleDevice({bool? isSystemDevice}) {
|
BleDevice toBleDevice({bool? isSystemDevice}) {
|
||||||
return BleDevice(
|
return BleDevice(
|
||||||
name: name,
|
name: name,
|
||||||
@@ -705,6 +720,7 @@ extension BlueZDeviceExtension on BlueZDevice {
|
|||||||
isSystemDevice: isSystemDevice,
|
isSystemDevice: isSystemDevice,
|
||||||
services: uuids.map((e) => e.toString()).toList(),
|
services: uuids.map((e) => e.toString()).toList(),
|
||||||
manufacturerDataList: manufacturerDataList,
|
manufacturerDataList: manufacturerDataList,
|
||||||
|
serviceData: serviceDataMap,
|
||||||
timestamp: DateTime.now().millisecondsSinceEpoch,
|
timestamp: DateTime.now().millisecondsSinceEpoch,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ class UniversalBleScanResult {
|
|||||||
this.isPaired,
|
this.isPaired,
|
||||||
this.rssi,
|
this.rssi,
|
||||||
this.manufacturerDataList,
|
this.manufacturerDataList,
|
||||||
|
this.serviceData,
|
||||||
this.services,
|
this.services,
|
||||||
this.timestamp,
|
this.timestamp,
|
||||||
});
|
});
|
||||||
@@ -136,6 +137,8 @@ class UniversalBleScanResult {
|
|||||||
|
|
||||||
List<UniversalManufacturerData>? manufacturerDataList;
|
List<UniversalManufacturerData>? manufacturerDataList;
|
||||||
|
|
||||||
|
Map<String, Uint8List>? serviceData;
|
||||||
|
|
||||||
List<String>? services;
|
List<String>? services;
|
||||||
|
|
||||||
int? timestamp;
|
int? timestamp;
|
||||||
@@ -147,6 +150,7 @@ class UniversalBleScanResult {
|
|||||||
isPaired,
|
isPaired,
|
||||||
rssi,
|
rssi,
|
||||||
manufacturerDataList,
|
manufacturerDataList,
|
||||||
|
serviceData,
|
||||||
services,
|
services,
|
||||||
timestamp,
|
timestamp,
|
||||||
];
|
];
|
||||||
@@ -165,8 +169,10 @@ class UniversalBleScanResult {
|
|||||||
rssi: result[3] as int?,
|
rssi: result[3] as int?,
|
||||||
manufacturerDataList:
|
manufacturerDataList:
|
||||||
(result[4] as List<Object?>?)?.cast<UniversalManufacturerData>(),
|
(result[4] as List<Object?>?)?.cast<UniversalManufacturerData>(),
|
||||||
services: (result[5] as List<Object?>?)?.cast<String>(),
|
serviceData:
|
||||||
timestamp: result[6] as int?,
|
(result[5] as Map<Object?, Object?>?)?.cast<String, Uint8List>(),
|
||||||
|
services: (result[6] as List<Object?>?)?.cast<String>(),
|
||||||
|
timestamp: result[7] as int?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -294,6 +294,7 @@ extension _UniversalBleScanResultExtension on UniversalBleScanResult {
|
|||||||
?.map((e) => ManufacturerData(e.companyIdentifier, e.data))
|
?.map((e) => ManufacturerData(e.companyIdentifier, e.data))
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[],
|
[],
|
||||||
|
serviceData: serviceData ?? {},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,11 +134,15 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
|||||||
|
|
||||||
_deviceAdvertisementStreamList[device.id] =
|
_deviceAdvertisementStreamList[device.id] =
|
||||||
device.advertisements.listen((event) {
|
device.advertisements.listen((event) {
|
||||||
|
final serviceDataMap = event.serviceData.map(
|
||||||
|
(key, value) => MapEntry(key, value.buffer.asUint8List()),
|
||||||
|
);
|
||||||
updateScanResult(
|
updateScanResult(
|
||||||
device.toBleScanResult(
|
device.toBleScanResult(
|
||||||
rssi: event.rssi,
|
rssi: event.rssi,
|
||||||
manufacturerDataMap: event.manufacturerData,
|
manufacturerDataMap: event.manufacturerData,
|
||||||
services: event.uuids.toSet().toList(),
|
services: event.uuids.toSet().toList(),
|
||||||
|
serviceDataMap: serviceDataMap,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -519,6 +523,7 @@ extension _BluetoothDeviceExtension on BluetoothDevice {
|
|||||||
int? rssi,
|
int? rssi,
|
||||||
UnmodifiableMapView<int, ByteData>? manufacturerDataMap,
|
UnmodifiableMapView<int, ByteData>? manufacturerDataMap,
|
||||||
List<String> services = const [],
|
List<String> services = const [],
|
||||||
|
Map<String, Uint8List>? serviceDataMap,
|
||||||
}) {
|
}) {
|
||||||
return BleDevice(
|
return BleDevice(
|
||||||
name: name,
|
name: name,
|
||||||
@@ -526,6 +531,7 @@ extension _BluetoothDeviceExtension on BluetoothDevice {
|
|||||||
manufacturerDataList: manufacturerDataMap?.toManufacturerDataList() ?? [],
|
manufacturerDataList: manufacturerDataMap?.toManufacturerDataList() ?? [],
|
||||||
rssi: rssi,
|
rssi: rssi,
|
||||||
services: services,
|
services: services,
|
||||||
|
serviceData: serviceDataMap ?? {},
|
||||||
timestamp: DateTime.now().millisecondsSinceEpoch,
|
timestamp: DateTime.now().millisecondsSinceEpoch,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ class UniversalBleScanResult {
|
|||||||
final bool? isPaired;
|
final bool? isPaired;
|
||||||
final int? rssi;
|
final int? rssi;
|
||||||
final List<UniversalManufacturerData>? manufacturerDataList;
|
final List<UniversalManufacturerData>? manufacturerDataList;
|
||||||
|
final Map<String, Uint8List>? serviceData;
|
||||||
final List<String>? services;
|
final List<String>? services;
|
||||||
final int? timestamp;
|
final int? timestamp;
|
||||||
|
|
||||||
@@ -137,6 +138,7 @@ class UniversalBleScanResult {
|
|||||||
required this.isPaired,
|
required this.isPaired,
|
||||||
required this.rssi,
|
required this.rssi,
|
||||||
required this.manufacturerDataList,
|
required this.manufacturerDataList,
|
||||||
|
required this.serviceData,
|
||||||
required this.services,
|
required this.services,
|
||||||
required this.timestamp,
|
required this.timestamp,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ UniversalBleScanResult::UniversalBleScanResult(
|
|||||||
const bool* is_paired,
|
const bool* is_paired,
|
||||||
const int64_t* rssi,
|
const int64_t* rssi,
|
||||||
const EncodableList* manufacturer_data_list,
|
const EncodableList* manufacturer_data_list,
|
||||||
|
const EncodableMap* service_data,
|
||||||
const EncodableList* services,
|
const EncodableList* services,
|
||||||
const int64_t* timestamp)
|
const int64_t* timestamp)
|
||||||
: device_id_(device_id),
|
: device_id_(device_id),
|
||||||
@@ -46,6 +47,7 @@ UniversalBleScanResult::UniversalBleScanResult(
|
|||||||
is_paired_(is_paired ? std::optional<bool>(*is_paired) : std::nullopt),
|
is_paired_(is_paired ? std::optional<bool>(*is_paired) : std::nullopt),
|
||||||
rssi_(rssi ? std::optional<int64_t>(*rssi) : std::nullopt),
|
rssi_(rssi ? std::optional<int64_t>(*rssi) : std::nullopt),
|
||||||
manufacturer_data_list_(manufacturer_data_list ? std::optional<EncodableList>(*manufacturer_data_list) : std::nullopt),
|
manufacturer_data_list_(manufacturer_data_list ? std::optional<EncodableList>(*manufacturer_data_list) : std::nullopt),
|
||||||
|
service_data_(service_data ? std::optional<EncodableMap>(*service_data) : std::nullopt),
|
||||||
services_(services ? std::optional<EncodableList>(*services) : std::nullopt),
|
services_(services ? std::optional<EncodableList>(*services) : std::nullopt),
|
||||||
timestamp_(timestamp ? std::optional<int64_t>(*timestamp) : std::nullopt) {}
|
timestamp_(timestamp ? std::optional<int64_t>(*timestamp) : std::nullopt) {}
|
||||||
|
|
||||||
@@ -110,6 +112,19 @@ void UniversalBleScanResult::set_manufacturer_data_list(const EncodableList& val
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const EncodableMap* UniversalBleScanResult::service_data() const {
|
||||||
|
return service_data_ ? &(*service_data_) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UniversalBleScanResult::set_service_data(const EncodableMap* value_arg) {
|
||||||
|
service_data_ = value_arg ? std::optional<EncodableMap>(*value_arg) : std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UniversalBleScanResult::set_service_data(const EncodableMap& value_arg) {
|
||||||
|
service_data_ = value_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const EncodableList* UniversalBleScanResult::services() const {
|
const EncodableList* UniversalBleScanResult::services() const {
|
||||||
return services_ ? &(*services_) : nullptr;
|
return services_ ? &(*services_) : nullptr;
|
||||||
}
|
}
|
||||||
@@ -138,12 +153,13 @@ void UniversalBleScanResult::set_timestamp(int64_t value_arg) {
|
|||||||
|
|
||||||
EncodableList UniversalBleScanResult::ToEncodableList() const {
|
EncodableList UniversalBleScanResult::ToEncodableList() const {
|
||||||
EncodableList list;
|
EncodableList list;
|
||||||
list.reserve(7);
|
list.reserve(8);
|
||||||
list.push_back(EncodableValue(device_id_));
|
list.push_back(EncodableValue(device_id_));
|
||||||
list.push_back(name_ ? EncodableValue(*name_) : EncodableValue());
|
list.push_back(name_ ? EncodableValue(*name_) : EncodableValue());
|
||||||
list.push_back(is_paired_ ? EncodableValue(*is_paired_) : EncodableValue());
|
list.push_back(is_paired_ ? EncodableValue(*is_paired_) : EncodableValue());
|
||||||
list.push_back(rssi_ ? EncodableValue(*rssi_) : EncodableValue());
|
list.push_back(rssi_ ? EncodableValue(*rssi_) : EncodableValue());
|
||||||
list.push_back(manufacturer_data_list_ ? EncodableValue(*manufacturer_data_list_) : EncodableValue());
|
list.push_back(manufacturer_data_list_ ? EncodableValue(*manufacturer_data_list_) : EncodableValue());
|
||||||
|
list.push_back(service_data_ ? EncodableValue(*service_data_) : EncodableValue());
|
||||||
list.push_back(services_ ? EncodableValue(*services_) : EncodableValue());
|
list.push_back(services_ ? EncodableValue(*services_) : EncodableValue());
|
||||||
list.push_back(timestamp_ ? EncodableValue(*timestamp_) : EncodableValue());
|
list.push_back(timestamp_ ? EncodableValue(*timestamp_) : EncodableValue());
|
||||||
return list;
|
return list;
|
||||||
@@ -168,11 +184,15 @@ UniversalBleScanResult UniversalBleScanResult::FromEncodableList(const Encodable
|
|||||||
if (!encodable_manufacturer_data_list.IsNull()) {
|
if (!encodable_manufacturer_data_list.IsNull()) {
|
||||||
decoded.set_manufacturer_data_list(std::get<EncodableList>(encodable_manufacturer_data_list));
|
decoded.set_manufacturer_data_list(std::get<EncodableList>(encodable_manufacturer_data_list));
|
||||||
}
|
}
|
||||||
auto& encodable_services = list[5];
|
auto& encodable_service_data = list[5];
|
||||||
|
if (!encodable_service_data.IsNull()) {
|
||||||
|
decoded.set_service_data(std::get<EncodableMap>(encodable_service_data));
|
||||||
|
}
|
||||||
|
auto& encodable_services = list[6];
|
||||||
if (!encodable_services.IsNull()) {
|
if (!encodable_services.IsNull()) {
|
||||||
decoded.set_services(std::get<EncodableList>(encodable_services));
|
decoded.set_services(std::get<EncodableList>(encodable_services));
|
||||||
}
|
}
|
||||||
auto& encodable_timestamp = list[6];
|
auto& encodable_timestamp = list[7];
|
||||||
if (!encodable_timestamp.IsNull()) {
|
if (!encodable_timestamp.IsNull()) {
|
||||||
decoded.set_timestamp(std::get<int64_t>(encodable_timestamp));
|
decoded.set_timestamp(std::get<int64_t>(encodable_timestamp));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ class UniversalBleScanResult {
|
|||||||
const bool* is_paired,
|
const bool* is_paired,
|
||||||
const int64_t* rssi,
|
const int64_t* rssi,
|
||||||
const flutter::EncodableList* manufacturer_data_list,
|
const flutter::EncodableList* manufacturer_data_list,
|
||||||
|
const flutter::EncodableMap* service_data,
|
||||||
const flutter::EncodableList* services,
|
const flutter::EncodableList* services,
|
||||||
const int64_t* timestamp);
|
const int64_t* timestamp);
|
||||||
|
|
||||||
@@ -167,6 +168,10 @@ class UniversalBleScanResult {
|
|||||||
void set_manufacturer_data_list(const flutter::EncodableList* value_arg);
|
void set_manufacturer_data_list(const flutter::EncodableList* value_arg);
|
||||||
void set_manufacturer_data_list(const flutter::EncodableList& value_arg);
|
void set_manufacturer_data_list(const flutter::EncodableList& value_arg);
|
||||||
|
|
||||||
|
const flutter::EncodableMap* service_data() const;
|
||||||
|
void set_service_data(const flutter::EncodableMap* value_arg);
|
||||||
|
void set_service_data(const flutter::EncodableMap& value_arg);
|
||||||
|
|
||||||
const flutter::EncodableList* services() const;
|
const flutter::EncodableList* services() const;
|
||||||
void set_services(const flutter::EncodableList* value_arg);
|
void set_services(const flutter::EncodableList* value_arg);
|
||||||
void set_services(const flutter::EncodableList& value_arg);
|
void set_services(const flutter::EncodableList& value_arg);
|
||||||
@@ -186,6 +191,7 @@ class UniversalBleScanResult {
|
|||||||
std::optional<bool> is_paired_;
|
std::optional<bool> is_paired_;
|
||||||
std::optional<int64_t> rssi_;
|
std::optional<int64_t> rssi_;
|
||||||
std::optional<flutter::EncodableList> manufacturer_data_list_;
|
std::optional<flutter::EncodableList> manufacturer_data_list_;
|
||||||
|
std::optional<flutter::EncodableMap> service_data_;
|
||||||
std::optional<flutter::EncodableList> services_;
|
std::optional<flutter::EncodableList> services_;
|
||||||
std::optional<int64_t> timestamp_;
|
std::optional<int64_t> timestamp_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -119,7 +119,8 @@ void UniversalBlePlugin::DisableBluetooth(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<bool> UniversalBlePlugin::HasPermissions(bool with_android_fine_location) {
|
ErrorOr<bool>
|
||||||
|
UniversalBlePlugin::HasPermissions(bool with_android_fine_location) {
|
||||||
// Windows does not require runtime permissions for Bluetooth
|
// Windows does not require runtime permissions for Bluetooth
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -261,7 +262,8 @@ UniversalBlePlugin::SetLogLevel(const UniversalBleLogLevel &log_level) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<FlutterError>
|
std::optional<FlutterError>
|
||||||
UniversalBlePlugin::Connect(const std::string &device_id, const bool *auto_connect) {
|
UniversalBlePlugin::Connect(const std::string &device_id,
|
||||||
|
const bool *auto_connect) {
|
||||||
// Note: autoConnect is not directly supported on Windows platform
|
// Note: autoConnect is not directly supported on Windows platform
|
||||||
ConnectAsync(str_to_mac_address(device_id));
|
ConnectAsync(str_to_mac_address(device_id));
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@@ -455,8 +457,9 @@ void UniversalBlePlugin::RequestMtu(
|
|||||||
void UniversalBlePlugin::ReadRssi(
|
void UniversalBlePlugin::ReadRssi(
|
||||||
const std::string &device_id,
|
const std::string &device_id,
|
||||||
std::function<void(ErrorOr<int64_t> reply)> result) {
|
std::function<void(ErrorOr<int64_t> reply)> result) {
|
||||||
result(create_flutter_error(UniversalBleErrorCode::kNotImplemented,
|
result(
|
||||||
"readRssi is not implemented on Windows platform"));
|
create_flutter_error(UniversalBleErrorCode::kNotImplemented,
|
||||||
|
"readRssi is not implemented on Windows platform"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UniversalBlePlugin::IsPaired(
|
void UniversalBlePlugin::IsPaired(
|
||||||
@@ -669,6 +672,68 @@ void UniversalBlePlugin::PairingRequestedHandler(
|
|||||||
event_args.Accept(pin);
|
event_args.Accept(pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
UniversalBlePlugin::ExpandServiceUuid(const std::vector<uint8_t> &uuid_bytes,
|
||||||
|
uint8_t uuid_type) {
|
||||||
|
if (uuid_type ==
|
||||||
|
static_cast<uint8_t>(AdvertisementSectionType::ServiceData16BitUuids)) {
|
||||||
|
// 16-bit UUID: expand to full 128-bit format
|
||||||
|
if (uuid_bytes.size() >= 2) {
|
||||||
|
uint16_t uuid_16 = (uuid_bytes[1] << 8) | uuid_bytes[0];
|
||||||
|
char uuid_str[37];
|
||||||
|
sprintf_s(uuid_str, "0000%04x-0000-1000-8000-00805f9b34fb", uuid_16);
|
||||||
|
return std::string(uuid_str);
|
||||||
|
}
|
||||||
|
} else if (uuid_type ==
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
AdvertisementSectionType::ServiceData32BitUuids)) {
|
||||||
|
// 32-bit UUID: expand to full 128-bit format
|
||||||
|
if (uuid_bytes.size() >= 4) {
|
||||||
|
uint32_t uuid_32 = (uuid_bytes[3] << 24) | (uuid_bytes[2] << 16) |
|
||||||
|
(uuid_bytes[1] << 8) | uuid_bytes[0];
|
||||||
|
char uuid_str[37];
|
||||||
|
sprintf_s(uuid_str, "%08x-0000-1000-8000-00805f9b34fb", uuid_32);
|
||||||
|
return std::string(uuid_str);
|
||||||
|
}
|
||||||
|
} else if (uuid_type ==
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
AdvertisementSectionType::ServiceData128BitUuids)) {
|
||||||
|
// 128-bit UUID: parse with proper endianness handling
|
||||||
|
// BLE service data stores UUIDs in little-endian byte order
|
||||||
|
// guid_to_uuid reads: Data1/Data2/Data3 as big-endian (reverse), Data4 as
|
||||||
|
// little-endian (forward)
|
||||||
|
if (uuid_bytes.size() >= 16) {
|
||||||
|
guid uuid_guid{};
|
||||||
|
|
||||||
|
// Data1: bytes [0-3] - guid_to_uuid reads in reverse (big-endian), so
|
||||||
|
// store in reverse
|
||||||
|
uuid_guid.Data1 = static_cast<uint32_t>(uuid_bytes[3]) |
|
||||||
|
(static_cast<uint32_t>(uuid_bytes[2]) << 8) |
|
||||||
|
(static_cast<uint32_t>(uuid_bytes[1]) << 16) |
|
||||||
|
(static_cast<uint32_t>(uuid_bytes[0]) << 24);
|
||||||
|
|
||||||
|
// Data2: bytes [4-5] - guid_to_uuid reads in reverse (big-endian), so
|
||||||
|
// store in reverse
|
||||||
|
uuid_guid.Data2 = static_cast<uint16_t>(uuid_bytes[5]) |
|
||||||
|
(static_cast<uint16_t>(uuid_bytes[4]) << 8);
|
||||||
|
|
||||||
|
// Data3: bytes [6-7] - guid_to_uuid reads in reverse (big-endian), so
|
||||||
|
// store in reverse
|
||||||
|
uuid_guid.Data3 = static_cast<uint16_t>(uuid_bytes[7]) |
|
||||||
|
(static_cast<uint16_t>(uuid_bytes[6]) << 8);
|
||||||
|
|
||||||
|
// Data4: bytes [8-15] - guid_to_uuid reads in order (little-endian), so
|
||||||
|
// store in order
|
||||||
|
for (size_t i = 0; i < 8; i++) {
|
||||||
|
uuid_guid.Data4[i] = uuid_bytes[8 + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return guid_to_uuid(uuid_guid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
// Send device to callback channel
|
// Send device to callback channel
|
||||||
// if device is already discovered in deviceWatcher then merge the scan result
|
// if device is already discovered in deviceWatcher then merge the scan result
|
||||||
void UniversalBlePlugin::PushUniversalScanResult(
|
void UniversalBlePlugin::PushUniversalScanResult(
|
||||||
@@ -903,22 +968,75 @@ void UniversalBlePlugin::BluetoothLeWatcherReceived(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto service_data_map = flutter::EncodableMap();
|
||||||
auto data_section = args.Advertisement().DataSections();
|
auto data_section = args.Advertisement().DataSections();
|
||||||
for (auto &&data : data_section) {
|
for (auto &&data : data_section) {
|
||||||
auto data_bytes = to_bytevc(data.Data());
|
auto data_bytes = to_bytevc(data.Data());
|
||||||
|
auto data_type = data.DataType();
|
||||||
|
|
||||||
// Use CompleteName from dataType if localName is empty
|
// Use CompleteName from dataType if localName is empty
|
||||||
if (name.empty() &&
|
if (name.empty() &&
|
||||||
data.DataType() == static_cast<uint8_t>(
|
data_type == static_cast<uint8_t>(
|
||||||
AdvertisementSectionType::CompleteLocalName)) {
|
AdvertisementSectionType::CompleteLocalName)) {
|
||||||
name = std::string(data_bytes.begin(), data_bytes.end());
|
name = std::string(data_bytes.begin(), data_bytes.end());
|
||||||
}
|
}
|
||||||
// Use ShortenedLocalName from dataType if localName is empty
|
// Use ShortenedLocalName from dataType if localName is empty
|
||||||
else if (name.empty() &&
|
else if (name.empty() &&
|
||||||
data.DataType() ==
|
data_type == static_cast<uint8_t>(
|
||||||
static_cast<uint8_t>(
|
AdvertisementSectionType::ShortenedLocalName)) {
|
||||||
AdvertisementSectionType::ShortenedLocalName)) {
|
|
||||||
name = std::string(data_bytes.begin(), data_bytes.end());
|
name = std::string(data_bytes.begin(), data_bytes.end());
|
||||||
}
|
}
|
||||||
|
// Extract service data
|
||||||
|
else if (data_type ==
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
AdvertisementSectionType::ServiceData16BitUuids) ||
|
||||||
|
data_type ==
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
AdvertisementSectionType::ServiceData32BitUuids) ||
|
||||||
|
data_type ==
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
AdvertisementSectionType::ServiceData128BitUuids)) {
|
||||||
|
// Helper lambda to parse UUID and extract service data
|
||||||
|
auto parse_service_data =
|
||||||
|
[&](const std::vector<uint8_t> &bytes,
|
||||||
|
uint8_t type) -> std::pair<std::string, std::vector<uint8_t>> {
|
||||||
|
std::string uuid;
|
||||||
|
std::vector<uint8_t> data_payload;
|
||||||
|
size_t uuid_size = 0;
|
||||||
|
|
||||||
|
if (type == static_cast<uint8_t>(
|
||||||
|
AdvertisementSectionType::ServiceData16BitUuids)) {
|
||||||
|
uuid_size = 2;
|
||||||
|
} else if (type ==
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
AdvertisementSectionType::ServiceData32BitUuids)) {
|
||||||
|
uuid_size = 4;
|
||||||
|
} else if (type ==
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
AdvertisementSectionType::ServiceData128BitUuids)) {
|
||||||
|
uuid_size = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes.size() >= uuid_size) {
|
||||||
|
std::vector<uint8_t> uuid_bytes(bytes.begin(),
|
||||||
|
bytes.begin() + uuid_size);
|
||||||
|
uuid = ExpandServiceUuid(uuid_bytes, type);
|
||||||
|
if (bytes.size() > uuid_size) {
|
||||||
|
data_payload =
|
||||||
|
std::vector<uint8_t>(bytes.begin() + uuid_size, bytes.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {uuid, data_payload};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto [service_uuid, service_data_bytes] =
|
||||||
|
parse_service_data(data_bytes, data_type);
|
||||||
|
if (!service_uuid.empty()) {
|
||||||
|
service_data_map[service_uuid] =
|
||||||
|
flutter::EncodableValue(service_data_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!name.empty()) {
|
if (!name.empty()) {
|
||||||
@@ -938,6 +1056,11 @@ void UniversalBlePlugin::BluetoothLeWatcherReceived(
|
|||||||
services.push_back(guid_to_uuid(uuid));
|
services.push_back(guid_to_uuid(uuid));
|
||||||
universal_scan_result.set_services(services);
|
universal_scan_result.set_services(services);
|
||||||
|
|
||||||
|
// Add service data
|
||||||
|
if (!service_data_map.empty()) {
|
||||||
|
universal_scan_result.set_service_data(&service_data_map);
|
||||||
|
}
|
||||||
|
|
||||||
// check if this device already discovered in deviceWatcher
|
// check if this device already discovered in deviceWatcher
|
||||||
auto it = device_watcher_devices_.get(device_id);
|
auto it = device_watcher_devices_.get(device_id);
|
||||||
if (it.has_value()) {
|
if (it.has_value()) {
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ private:
|
|||||||
void DisposeDeviceWatcher();
|
void DisposeDeviceWatcher();
|
||||||
void PushUniversalScanResult(UniversalBleScanResult scan_result,
|
void PushUniversalScanResult(UniversalBleScanResult scan_result,
|
||||||
bool is_connectable);
|
bool is_connectable);
|
||||||
|
static std::string ExpandServiceUuid(const std::vector<uint8_t>& uuid_bytes,
|
||||||
|
uint8_t uuid_type);
|
||||||
void BluetoothLeWatcherReceived(
|
void BluetoothLeWatcherReceived(
|
||||||
const BluetoothLEAdvertisementWatcher &sender,
|
const BluetoothLEAdvertisementWatcher &sender,
|
||||||
const BluetoothLEAdvertisementReceivedEventArgs &args);
|
const BluetoothLEAdvertisementReceivedEventArgs &args);
|
||||||
|
|||||||
Reference in New Issue
Block a user