Files
bluetooth_low_energy/test/bluetooth_low_energy_test.dart
iAMD fc35f74488 iOS 平台实现 (#2)
* 修复 UUID 创建失败的问题

* 移除 scanning 属性

* 临时提交

* CentralManager 开发 & 示例项目开发

* CentralManager 开发 & 示例项目开发

* android 插件生命周期监听

* 修改 API

* 示例程序开发

* 修改字体,添加 API,解决后台问题

* Central#connect API

* 蓝牙连接部分开发

* 蓝牙连接部分开发

* 解决一些问题

* 解决一些问题

* Connect API 优化

* 添加 API

* example 开发

* API 基本完成

* 消息重命名

* API 修改,Android 实现

* 删除多余代码

* 删除多余文件

* 解决 descriptor 自动生成报错的问题

* 还原 Kotlin 版本,广播处理代码迁移至 dart 端

* Kotlin 版本升至 1.5.20

* 解决特征值通知没有在主线程触发的问题,优化代码

* 引入哈希值,避免对象销毁后继续使用

* 使用下拉刷新代替搜索按钮

* 解决由于热重载和蓝牙关闭产生的问题

* 更新插件信息

* 更新 README 和 CHANGELOG

* 更新许可证

* 添加注释

* 添加注释,central 拆分

* dartfmt -w .

* flutter build ios --no-codesign

* API 重构

* 添加 connectable 属性

* Android 8.0 之前无法获取 connectable 属性

* 解决合并错误

* 解决连接时可能引发异常的一个问题,iOS 开发

* API 修改,TODO: iOS 哈希值为 64 位无法用 Int32 表示

* iOS 开发

* iOS 开发完成,使用 UUID 实现对象映射

* 更新版本记录和文档
2021-07-15 20:18:49 +08:00

521 lines
16 KiB
Dart

import 'package:bluetooth_low_energy/bluetooth_low_energy.dart';
import 'package:bluetooth_low_energy/src/util.dart' as util;
import 'package:bluetooth_low_energy/src/message.pb.dart' as proto;
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
final method = MethodChannel('${util.method.name}');
final event = MethodChannel('${util.event.name}');
final calls = <MethodCall>[];
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() {
calls.clear();
method.setMockMethodCallHandler((call) async {
calls.add(call);
final message = proto.Message.fromBuffer(call.arguments);
switch (message.category) {
case proto.MessageCategory.BLUETOOTH_STATE:
return proto.BluetoothState.POWERED_ON.value;
case proto.MessageCategory.CENTRAL_START_DISCOVERY:
return null;
case proto.MessageCategory.CENTRAL_STOP_DISCOVERY:
return null;
case proto.MessageCategory.CENTRAL_CONNECT:
final descriptors = [
proto.GattDescriptor(
key: '0',
uuid: '2900',
),
];
final characteristics = [
proto.GattCharacteristic(
key: '0',
uuid: '2A00',
descriptors: descriptors,
canRead: true,
canWrite: true,
canWriteWithoutResponse: true,
canNotify: true,
),
];
final services = [
proto.GattService(
key: '0',
uuid: '1800',
characteristics: characteristics,
),
];
final gatt = proto.GATT(
key: '0',
maximumWriteLength: 20,
services: services,
);
return gatt.writeToBuffer();
case proto.MessageCategory.GATT_DISCONNECT:
return null;
case proto.MessageCategory.GATT_CHARACTERISTIC_READ:
return [0x01, 0x02, 0x03, 0x04, 0x05];
case proto.MessageCategory.GATT_CHARACTERISTIC_WRITE:
return null;
case proto.MessageCategory.GATT_CHARACTERISTIC_NOTIFY:
return null;
case proto.MessageCategory.GATT_DESCRIPTOR_READ:
return [0x05, 0x04, 0x03, 0x02, 0x01];
case proto.MessageCategory.GATT_DESCRIPTOR_WRITE:
return null;
default:
throw UnimplementedError();
}
});
event.setMockMethodCallHandler((call) async {
switch (call.method) {
case 'listen':
final state = proto.Message(
category: proto.MessageCategory.BLUETOOTH_STATE,
state: proto.BluetoothState.POWERED_OFF,
).writeToBuffer();
await ServicesBinding.instance!.defaultBinaryMessenger
.handlePlatformMessage(
event.name,
event.codec.encodeSuccessEnvelope(state),
(data) {},
);
final discovery = proto.Message(
category: proto.MessageCategory.CENTRAL_DISCOVERED,
discovery: proto.Discovery(
uuid: 'AABB',
rssi: -50,
advertisements: [0x07, 0xff, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa],
),
).writeToBuffer();
await ServicesBinding.instance!.defaultBinaryMessenger
.handlePlatformMessage(
event.name,
event.codec.encodeSuccessEnvelope(discovery),
(data) {},
);
final connectionLost = proto.Message(
category: proto.MessageCategory.GATT_CONNECTION_LOST,
connectionLost: proto.GattConnectionLost(
key: '0',
error: 'Connection lost.',
),
).writeToBuffer();
await ServicesBinding.instance!.defaultBinaryMessenger
.handlePlatformMessage(
event.name,
event.codec.encodeSuccessEnvelope(connectionLost),
(data) {},
);
final characteristicValue = proto.Message(
category: proto.MessageCategory.GATT_CHARACTERISTIC_NOTIFY,
characteristicValue: proto.GattCharacteristicValue(
gattKey: '0',
serviceKey: '0',
key: '0',
value: [0x0A, 0x0B, 0x0C, 0x0D, 0x0E],
),
).writeToBuffer();
await ServicesBinding.instance!.defaultBinaryMessenger
.handlePlatformMessage(
event.name,
event.codec.encodeSuccessEnvelope(characteristicValue),
(data) {},
);
break;
case 'cancel':
return null;
default:
throw UnimplementedError();
}
});
});
tearDown(() {
method.setMockMethodCallHandler(null);
event.setMockMethodCallHandler(null);
});
test(
'${proto.MessageCategory.BLUETOOTH_STATE}',
() async {
final actual = await central.state;
expect(actual, BluetoothState.poweredOn);
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.BLUETOOTH_STATE,
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.BLUETOOTH_STATE} EVENT',
() async {
final actual = await central.stateChanged.first;
expect(actual, BluetoothState.poweredOff);
},
);
test(
'${proto.MessageCategory.CENTRAL_START_DISCOVERY}',
() async {
final services = [UUID('1800'), UUID('1801')];
await central.startDiscovery(services: services);
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.CENTRAL_START_DISCOVERY,
startDiscoveryArguments: proto.StartDiscoveryArguments(
services: services.map((uuid) => uuid.name),
),
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.CENTRAL_STOP_DISCOVERY}',
() async {
await central.stopDiscovery();
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.CENTRAL_STOP_DISCOVERY,
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.CENTRAL_DISCOVERED} EVENT',
() async {
final actual = await central.discovered.first;
final uuid = UUID('AABB');
expect(actual.uuid, uuid);
final rssi = -50;
expect(actual.rssi, rssi);
final advertisements = {
0xff: [0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa],
};
expect(actual.advertisements, advertisements);
},
);
test(
'${proto.MessageCategory.CENTRAL_CONNECT}',
() async {
final uuid = UUID('AABB');
final actual = await central.connect(uuid);
expect(actual.maximumWriteLength, 20);
expect(actual.services.length, 1);
final service = actual.services.values.first;
expect(service.uuid, UUID('1800'));
expect(service.characteristics.length, 1);
final characteristic = service.characteristics.values.first;
expect(characteristic.uuid, UUID('2A00'));
expect(characteristic.descriptors.length, 1);
expect(characteristic.canRead, true);
expect(characteristic.canWrite, true);
expect(characteristic.canWriteWithoutResponse, true);
expect(characteristic.canNotify, true);
final descriptor = characteristic.descriptors.values.first;
expect(descriptor.uuid, UUID('2900'));
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.CENTRAL_CONNECT,
connectArguments: proto.ConnectArguments(
uuid: uuid.name,
),
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_DISCONNECT}',
() async {
final uuid = UUID('AABB');
final gatt = await central.connect(uuid);
await gatt.disconnect();
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.CENTRAL_CONNECT,
connectArguments: proto.ConnectArguments(
uuid: uuid.name,
),
).writeToBuffer(),
),
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.GATT_DISCONNECT,
disconnectArguments: proto.GattDisconnectArguments(key: '0'),
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_CONNECTION_LOST}',
() async {
final uuid = UUID('AABB');
final gatt = await central.connect(uuid);
final actual = await gatt.connectionLost.first;
final matcher = Exception('Connection lost.');
expect('$actual', '$matcher');
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.CENTRAL_CONNECT,
connectArguments: proto.ConnectArguments(
uuid: uuid.name,
),
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_CHARACTERISTIC_READ}',
() async {
final uuid = UUID('AABB');
final gatt = await central.connect(uuid);
final service = gatt.services.values.first;
final characteristic = service.characteristics.values.first;
final actual = await characteristic.read();
expect(actual, [0x01, 0x02, 0x03, 0x04, 0x05]);
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.CENTRAL_CONNECT,
connectArguments: proto.ConnectArguments(
uuid: uuid.name,
),
).writeToBuffer(),
),
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.GATT_CHARACTERISTIC_READ,
characteristicReadArguments:
proto.GattCharacteristicReadArguments(
gattKey: '0',
serviceKey: '0',
key: '0',
),
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_CHARACTERISTIC_WRITE}',
() async {
final uuid = UUID('AABB');
final gatt = await central.connect(uuid);
final service = gatt.services.values.first;
final characteristic = service.characteristics.values.first;
final value = [0x01, 0x02, 0x03, 0x04, 0x05];
await characteristic.write(value, withoutResponse: true);
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.CENTRAL_CONNECT,
connectArguments: proto.ConnectArguments(
uuid: uuid.name,
),
).writeToBuffer(),
),
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.GATT_CHARACTERISTIC_WRITE,
characteristicWriteArguments:
proto.GattCharacteristicWriteArguments(
gattKey: '0',
serviceKey: '0',
key: '0',
value: value,
withoutResponse: true,
),
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_CHARACTERISTIC_NOTIFY}',
() async {
final uuid = UUID('AABB');
final gatt = await central.connect(uuid);
final service = gatt.services.values.first;
final characteristic = service.characteristics.values.first;
await characteristic.notify(true);
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.CENTRAL_CONNECT,
connectArguments: proto.ConnectArguments(
uuid: uuid.name,
),
).writeToBuffer(),
),
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.GATT_CHARACTERISTIC_NOTIFY,
characteristicNotifyArguments:
proto.GattCharacteristicNotifyArguments(
gattKey: '0',
serviceKey: '0',
key: '0',
state: true,
),
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_CHARACTERISTIC_NOTIFY} EVENT',
() async {
final uuid = UUID('AABB');
final gatt = await central.connect(uuid);
final service = gatt.services.values.first;
final characteristic = service.characteristics.values.first;
final value = await characteristic.valueChanged.first;
expect(value, [0x0A, 0x0B, 0x0C, 0x0D, 0x0E]);
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.CENTRAL_CONNECT,
connectArguments: proto.ConnectArguments(
uuid: uuid.name,
),
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_DESCRIPTOR_READ}',
() async {
final uuid = UUID('AABB');
final gatt = await central.connect(uuid);
final service = gatt.services.values.first;
final characteristic = service.characteristics.values.first;
final descriptor = characteristic.descriptors.values.first;
final actual = await descriptor.read();
expect(actual, [0x05, 0x04, 0x03, 0x02, 0x01]);
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.CENTRAL_CONNECT,
connectArguments: proto.ConnectArguments(
uuid: uuid.name,
),
).writeToBuffer(),
),
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.GATT_DESCRIPTOR_READ,
descriptorReadArguments: proto.GattDescriptorReadArguments(
gattKey: '0',
serviceKey: '0',
characteristicKey: '0',
key: '0',
),
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_DESCRIPTOR_WRITE}',
() async {
final uuid = UUID('AABB');
final gatt = await central.connect(uuid);
final service = gatt.services.values.first;
final characteristic = service.characteristics.values.first;
final descriptor = characteristic.descriptors.values.first;
final value = [0x01, 0x02, 0x03, 0x04, 0x05];
await descriptor.write(value);
expect(
calls,
[
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.CENTRAL_CONNECT,
connectArguments: proto.ConnectArguments(
uuid: uuid.name,
),
).writeToBuffer(),
),
isMethodCall(
'',
arguments: proto.Message(
category: proto.MessageCategory.GATT_DESCRIPTOR_WRITE,
descriptorWriteArguments: proto.GattDescriptorWriteArguments(
gattKey: '0',
serviceKey: '0',
characteristicKey: '0',
key: '0',
value: value,
),
).writeToBuffer(),
),
],
);
},
);
}