Files
bluetooth_low_energy/test/bluetooth_low_energy_test.dart
iAMD 6bc1a364fb Android 平台开发 (#1)
* 修复 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 拆分
2021-07-01 17:35:54 +08:00

472 lines
15 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);
if (call.method == proto.MessageCategory.BLUETOOTH_AVAILABLE.name) {
return true;
} else if (call.method == proto.MessageCategory.BLUETOOTH_STATE.name) {
return true;
} else if (call.method ==
proto.MessageCategory.CENTRAL_START_DISCOVERY.name) {
return null;
} else if (call.method ==
proto.MessageCategory.CENTRAL_STOP_DISCOVERY.name) {
return null;
} else if (call.method == proto.MessageCategory.CENTRAL_CONNECT.name) {
final descriptors = [
proto.GattDescriptor(
id: 4000,
uuid: '2900',
),
];
final characteristics = [
proto.GattCharacteristic(
id: 3000,
uuid: '2A00',
descriptors: descriptors,
canRead: true,
canWrite: true,
canWriteWithoutResponse: true,
canNotify: true,
),
];
final services = [
proto.GattService(
id: 2000,
uuid: '1800',
characteristics: characteristics,
),
];
final gatt = proto.GATT(
id: 1000,
mtu: 23,
services: services,
);
return gatt.writeToBuffer();
} else if (call.method == proto.MessageCategory.GATT_DISCONNECT.name) {
return null;
} else if (call.method ==
proto.MessageCategory.GATT_CHARACTERISTIC_READ.name) {
return [0x01, 0x02, 0x03, 0x04, 0x05];
} else if (call.method ==
proto.MessageCategory.GATT_CHARACTERISTIC_WRITE.name) {
return null;
} else if (call.method ==
proto.MessageCategory.GATT_CHARACTERISTIC_NOTIFY.name) {
return null;
} else if (call.method ==
proto.MessageCategory.GATT_DESCRIPTOR_READ.name) {
return [0x05, 0x04, 0x03, 0x02, 0x01];
} else if (call.method ==
proto.MessageCategory.GATT_DESCRIPTOR_WRITE.name) {
return null;
} else {
throw UnimplementedError();
}
});
event.setMockMethodCallHandler((call) async {
switch (call.method) {
case 'listen':
final state = proto.Message(
category: proto.MessageCategory.BLUETOOTH_STATE,
state: false,
).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(
address: 'aa:bb:cc:dd:ee:ff',
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.ConnectionLost(
id: 1000,
errorCode: 19,
),
).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(
id: 3000,
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_AVAILABLE}',
() async {
final actual = await central.available;
expect(actual, true);
expect(
calls,
[
isMethodCall(
proto.MessageCategory.BLUETOOTH_AVAILABLE.name,
arguments: null,
),
],
);
},
);
test(
'${proto.MessageCategory.BLUETOOTH_STATE}',
() async {
final actual = await central.state;
expect(actual, true);
expect(
calls,
[
isMethodCall(
proto.MessageCategory.BLUETOOTH_STATE.name,
arguments: null,
),
],
);
},
);
test(
'${proto.MessageCategory.BLUETOOTH_STATE} EVENT',
() async {
final actual = await central.stateChanged.first;
expect(actual, false);
},
);
test(
'${proto.MessageCategory.CENTRAL_START_DISCOVERY}',
() async {
final services = [UUID('1800'), UUID('1801')];
await central.startDiscovery(services: services);
expect(
calls,
[
isMethodCall(
proto.MessageCategory.CENTRAL_START_DISCOVERY.name,
arguments: proto.StartDiscoveryArguments(
services: services.map((uuid) => uuid.name),
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.CENTRAL_STOP_DISCOVERY}',
() async {
await central.stopDiscovery();
expect(
calls,
[
isMethodCall(
proto.MessageCategory.CENTRAL_STOP_DISCOVERY.name,
arguments: null,
),
],
);
},
);
test(
'${proto.MessageCategory.CENTRAL_DISCOVERED} EVENT',
() async {
final actual = await central.discovered.first;
final address = MAC('aa:bb:cc:dd:ee:ff');
expect(actual.address, address);
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 address = MAC('aa:bb:cc:dd:ee:ff');
final actual = await central.connect(address);
expect(actual.mtu, 23);
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(
proto.MessageCategory.CENTRAL_CONNECT.name,
arguments: proto.ConnectArguments(
address: address.name,
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_DISCONNECT}',
() async {
final address = MAC('aa:bb:cc:dd:ee:ff');
final gatt = await central.connect(address);
await gatt.disconnect();
expect(
calls,
[
isMethodCall(
proto.MessageCategory.CENTRAL_CONNECT.name,
arguments: proto.ConnectArguments(
address: address.name,
).writeToBuffer(),
),
isMethodCall(
proto.MessageCategory.GATT_DISCONNECT.name,
arguments: proto.GattDisconnectArguments(
address: address.name,
id: 1000,
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_CONNECTION_LOST}',
() async {
final address = MAC('aa:bb:cc:dd:ee:ff');
final gatt = await central.connect(address);
final actual = await gatt.connectionLost.first;
expect(actual, 19);
},
);
test(
'${proto.MessageCategory.GATT_CHARACTERISTIC_READ}',
() async {
final address = MAC('aa:bb:cc:dd:ee:ff');
final gatt = await central.connect(address);
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(
proto.MessageCategory.CENTRAL_CONNECT.name,
arguments: proto.ConnectArguments(
address: address.name,
).writeToBuffer(),
),
isMethodCall(
proto.MessageCategory.GATT_CHARACTERISTIC_READ.name,
arguments: proto.GattCharacteristicReadArguments(
address: address.name,
serviceUuid: service.uuid.name,
uuid: characteristic.uuid.name,
id: 3000,
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_CHARACTERISTIC_WRITE}',
() async {
final address = MAC('aa:bb:cc:dd:ee:ff');
final gatt = await central.connect(address);
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(
proto.MessageCategory.CENTRAL_CONNECT.name,
arguments: proto.ConnectArguments(
address: address.name,
).writeToBuffer(),
),
isMethodCall(
proto.MessageCategory.GATT_CHARACTERISTIC_WRITE.name,
arguments: proto.GattCharacteristicWriteArguments(
address: address.name,
serviceUuid: service.uuid.name,
uuid: characteristic.uuid.name,
id: 3000,
value: value,
withoutResponse: true,
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_CHARACTERISTIC_NOTIFY}',
() async {
final address = MAC('aa:bb:cc:dd:ee:ff');
final gatt = await central.connect(address);
final service = gatt.services.values.first;
final characteristic = service.characteristics.values.first;
await characteristic.notify(true);
expect(
calls,
[
isMethodCall(
proto.MessageCategory.CENTRAL_CONNECT.name,
arguments: proto.ConnectArguments(
address: address.name,
).writeToBuffer(),
),
isMethodCall(
proto.MessageCategory.GATT_CHARACTERISTIC_NOTIFY.name,
arguments: proto.GattCharacteristicNotifyArguments(
address: address.name,
serviceUuid: service.uuid.name,
uuid: characteristic.uuid.name,
id: 3000,
state: true,
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_CHARACTERISTIC_NOTIFY} EVENT',
() async {
final address = MAC('aa:bb:cc:dd:ee:ff');
final gatt = await central.connect(address);
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]);
},
);
test(
'${proto.MessageCategory.GATT_DESCRIPTOR_READ}',
() async {
final address = MAC('aa:bb:cc:dd:ee:ff');
final gatt = await central.connect(address);
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(
proto.MessageCategory.CENTRAL_CONNECT.name,
arguments: proto.ConnectArguments(
address: address.name,
).writeToBuffer(),
),
isMethodCall(
proto.MessageCategory.GATT_DESCRIPTOR_READ.name,
arguments: proto.GattDescriptorReadArguments(
address: address.name,
serviceUuid: service.uuid.name,
characteristicUuid: characteristic.uuid.name,
uuid: descriptor.uuid.name,
id: 4000,
).writeToBuffer(),
),
],
);
},
);
test(
'${proto.MessageCategory.GATT_DESCRIPTOR_WRITE}',
() async {
final address = MAC('aa:bb:cc:dd:ee:ff');
final gatt = await central.connect(address);
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(
proto.MessageCategory.CENTRAL_CONNECT.name,
arguments: proto.ConnectArguments(
address: address.name,
).writeToBuffer(),
),
isMethodCall(
proto.MessageCategory.GATT_DESCRIPTOR_WRITE.name,
arguments: proto.GattDescriptorWriteArguments(
address: address.name,
serviceUuid: service.uuid.name,
characteristicUuid: characteristic.uuid.name,
uuid: descriptor.uuid.name,
id: 4000,
value: value,
).writeToBuffer(),
),
],
);
},
);
}