feat: 重构项目 2.0.0 (#6)
* feat: 重构项目 * feat: 添加 bluez_central_manager * feat: 联合插件 * feat: 拆分项目 * feat: 实现 linux 部分接口 * feat: 重新创建项目 * feat: 定义接口 * feat: 实现接入插件 * feat: 清空接入插件示例代码 * feat: 开发 linux 插件 * feat: 调整接口 * 临时提交 * feat: 实现 Android 接口 * fix: 修复 Android 问题 * fix: 移除多余文件 * feat: 重构项目 (#5) * fix: 移除多余的状态判断 * fix: 外围设备断开时检查是否存在未完成的操作 * feat: 尝试使用 win32 实现接口 * fix: 修复大小写问题 * feat: 实现 macOS 接口 * feat: 实现 macOS 接口 * fix:支持使用16位短字符串生成UUID * fix: 修复未清理已完成操作的问题 * fix: 规范命名 * 添加蓝牙使用描述 * fix: 更新 README.md
This commit is contained in:
30
bluetooth_low_energy_platform_interface/.gitignore
vendored
Normal file
30
bluetooth_low_energy_platform_interface/.gitignore
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
/pubspec.lock
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.packages
|
||||
build/
|
27
bluetooth_low_energy_platform_interface/.metadata
Normal file
27
bluetooth_low_energy_platform_interface/.metadata
Normal file
@ -0,0 +1,27 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled.
|
||||
|
||||
version:
|
||||
revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
channel: stable
|
||||
|
||||
project_type: plugin
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
|
||||
# User provided section
|
||||
|
||||
# List of Local paths (relative to this file) that should be
|
||||
# ignored by the migrate tool.
|
||||
#
|
||||
# Files that are not part of the templates will be ignored by default.
|
||||
unmanaged_files:
|
||||
- 'lib/main.dart'
|
||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
4
bluetooth_low_energy_platform_interface/CHANGELOG.md
Normal file
4
bluetooth_low_energy_platform_interface/CHANGELOG.md
Normal file
@ -0,0 +1,4 @@
|
||||
## 2.0.0
|
||||
|
||||
- Rewrite the whole project with federated plugins.
|
||||
- Support macOS and Linux.
|
21
bluetooth_low_energy_platform_interface/LICENSE
Normal file
21
bluetooth_low_energy_platform_interface/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 yanshouwang
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
26
bluetooth_low_energy_platform_interface/README.md
Normal file
26
bluetooth_low_energy_platform_interface/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
# bluetooth_low_energy_platform_interface
|
||||
|
||||
A common platform interface for the [`bluetooth_low_energy`][1] plugin.
|
||||
|
||||
This interface allows platform-specific implementations of the `bluetooth_low_energy`
|
||||
plugin, as well as the plugin itself, to ensure they are supporting the
|
||||
same interface.
|
||||
|
||||
# Usage
|
||||
|
||||
To implement a new platform-specific implementation of `bluetooth_low_energy`, extend
|
||||
[`CentralController`][2] with an implementation that performs the
|
||||
platform-specific behavior, and when you register your plugin, set the default
|
||||
`CentralController` by calling
|
||||
`CentralController.instance = MyCentralController()`.
|
||||
|
||||
# Note on breaking changes
|
||||
|
||||
Strongly prefer non-breaking changes (such as adding a method to the interface)
|
||||
over breaking changes for this package.
|
||||
|
||||
See https://flutter.dev/go/platform-interface-breaking-changes for a discussion
|
||||
on why a less-clean interface is preferable to a breaking change.
|
||||
|
||||
[1]: https://pub.dev/packages/bluetooth_low_energy
|
||||
[2]: lib/src/central_controller.dart
|
@ -0,0 +1,4 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
@ -0,0 +1,12 @@
|
||||
export 'src/errors.dart';
|
||||
export 'src/event_args.dart';
|
||||
export 'src/central_controller.dart';
|
||||
export 'src/central_state.dart';
|
||||
export 'src/peripheral.dart';
|
||||
export 'src/uuid.dart';
|
||||
export 'src/advertisement.dart';
|
||||
export 'src/gatt_service.dart';
|
||||
export 'src/gatt_characteristic.dart';
|
||||
export 'src/gatt_characteristic_property.dart';
|
||||
export 'src/gatt_characteristic_write_type.dart';
|
||||
export 'src/gatt_descriptor.dart';
|
@ -0,0 +1,17 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'uuid.dart';
|
||||
|
||||
class Advertisement {
|
||||
final String? name;
|
||||
final Map<int, Uint8List> manufacturerSpecificData;
|
||||
final List<UUID> serviceUUIDs;
|
||||
final Map<UUID, Uint8List> serviceData;
|
||||
|
||||
Advertisement({
|
||||
this.name,
|
||||
this.manufacturerSpecificData = const {},
|
||||
this.serviceUUIDs = const [],
|
||||
this.serviceData = const {},
|
||||
});
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||
|
||||
import 'central_state.dart';
|
||||
import 'event_args.dart';
|
||||
import 'gatt_characteristic.dart';
|
||||
import 'gatt_characteristic_write_type.dart';
|
||||
import 'gatt_descriptor.dart';
|
||||
import 'gatt_service.dart';
|
||||
import 'peripheral.dart';
|
||||
|
||||
abstract class CentralController extends PlatformInterface {
|
||||
/// Constructs a [CentralController].
|
||||
CentralController() : super(token: _token);
|
||||
|
||||
static final Object _token = Object();
|
||||
|
||||
static CentralController? _instance;
|
||||
|
||||
/// The default instance of [CentralController] to use.
|
||||
static CentralController get instance {
|
||||
final instance = _instance;
|
||||
if (instance == null) {
|
||||
const message =
|
||||
'`BluetoothLowEnergy` is not implemented on this platform.';
|
||||
throw UnimplementedError(message);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// Platform-specific implementations should set this with their own
|
||||
/// platform-specific class that extends [CentralController] when
|
||||
/// they register themselves.
|
||||
static set instance(CentralController instance) {
|
||||
PlatformInterface.verifyToken(instance, _token);
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
CentralState get state;
|
||||
Stream<CentralStateChangedEventArgs> get stateChanged;
|
||||
Stream<CentralDiscoveredEventArgs> get discovered;
|
||||
Stream<PeripheralStateChangedEventArgs> get peripheralStateChanged;
|
||||
Stream<GattCharacteristicValueChangedEventArgs>
|
||||
get characteristicValueChanged;
|
||||
|
||||
Future<void> setUp();
|
||||
Future<void> tearDown();
|
||||
Future<void> startDiscovery();
|
||||
Future<void> stopDiscovery();
|
||||
Future<void> connect(Peripheral peripheral);
|
||||
Future<void> disconnect(Peripheral peripheral);
|
||||
Future<void> discoverGATT(Peripheral peripheral);
|
||||
Future<List<GattService>> getServices(Peripheral peripheral);
|
||||
Future<List<GattCharacteristic>> getCharacteristics(GattService service);
|
||||
Future<List<GattDescriptor>> getDescriptors(
|
||||
GattCharacteristic characteristic,
|
||||
);
|
||||
Future<Uint8List> readCharacteristic(GattCharacteristic characteristic);
|
||||
Future<void> writeCharacteristic(
|
||||
GattCharacteristic characteristic, {
|
||||
required Uint8List value,
|
||||
required GattCharacteristicWriteType type,
|
||||
});
|
||||
Future<void> notifyCharacteristic(
|
||||
GattCharacteristic characteristic, {
|
||||
required bool state,
|
||||
});
|
||||
Future<Uint8List> readDescriptor(GattDescriptor descriptor);
|
||||
Future<void> writeDescriptor(
|
||||
GattDescriptor descriptor, {
|
||||
required Uint8List value,
|
||||
});
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
enum CentralState {
|
||||
unknown,
|
||||
unsupported,
|
||||
unauthorized,
|
||||
poweredOff,
|
||||
poweredOn,
|
||||
}
|
10
bluetooth_low_energy_platform_interface/lib/src/errors.dart
Normal file
10
bluetooth_low_energy_platform_interface/lib/src/errors.dart
Normal file
@ -0,0 +1,10 @@
|
||||
class BluetoothLowEnergyError extends Error {
|
||||
final String message;
|
||||
|
||||
BluetoothLowEnergyError(this.message);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'BluetoothLowEnergyError: $message';
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'advertisement.dart';
|
||||
import 'central_state.dart';
|
||||
import 'gatt_characteristic.dart';
|
||||
import 'peripheral.dart';
|
||||
|
||||
abstract class EventArgs {}
|
||||
|
||||
class CentralStateChangedEventArgs extends EventArgs {
|
||||
final CentralState state;
|
||||
|
||||
CentralStateChangedEventArgs(this.state);
|
||||
}
|
||||
|
||||
class CentralDiscoveredEventArgs extends EventArgs {
|
||||
final Peripheral peripheral;
|
||||
final int rssi;
|
||||
final Advertisement advertisement;
|
||||
|
||||
CentralDiscoveredEventArgs(this.peripheral, this.rssi, this.advertisement);
|
||||
}
|
||||
|
||||
class PeripheralStateChangedEventArgs extends EventArgs {
|
||||
final Peripheral peripheral;
|
||||
final bool state;
|
||||
|
||||
PeripheralStateChangedEventArgs(this.peripheral, this.state);
|
||||
}
|
||||
|
||||
class GattCharacteristicValueChangedEventArgs extends EventArgs {
|
||||
final GattCharacteristic characteristic;
|
||||
final Uint8List value;
|
||||
|
||||
GattCharacteristicValueChangedEventArgs(this.characteristic, this.value);
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import 'gatt_characteristic_property.dart';
|
||||
import 'uuid.dart';
|
||||
|
||||
class GattCharacteristic {
|
||||
final UUID uuid;
|
||||
final List<GattCharacteristicProperty> properties;
|
||||
|
||||
GattCharacteristic({
|
||||
required this.uuid,
|
||||
required this.properties,
|
||||
});
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
enum GattCharacteristicProperty {
|
||||
read,
|
||||
write,
|
||||
writeWithoutResponse,
|
||||
notify,
|
||||
indicate,
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
enum GattCharacteristicWriteType {
|
||||
// Write with response
|
||||
withResponse,
|
||||
// Write without response
|
||||
withoutResponse,
|
||||
// Write with response and waiting for confirmation
|
||||
// reliable,
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import 'uuid.dart';
|
||||
|
||||
class GattDescriptor {
|
||||
final UUID uuid;
|
||||
|
||||
GattDescriptor({
|
||||
required this.uuid,
|
||||
});
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import 'uuid.dart';
|
||||
|
||||
class GattService {
|
||||
final UUID uuid;
|
||||
|
||||
GattService({
|
||||
required this.uuid,
|
||||
});
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
import 'uuid.dart';
|
||||
|
||||
abstract class Peripheral {
|
||||
UUID get uuid;
|
||||
}
|
141
bluetooth_low_energy_platform_interface/lib/src/uuid.dart
Normal file
141
bluetooth_low_energy_platform_interface/lib/src/uuid.dart
Normal file
@ -0,0 +1,141 @@
|
||||
/// 128 bit universally unique identifier used in Bluetooth.
|
||||
class UUID {
|
||||
/// The value of the UUID in 16 bytes.
|
||||
final List<int> value;
|
||||
|
||||
/// True if the UUID is a short (16 or 32 bit) encoded UUID.
|
||||
bool get isShort =>
|
||||
value[4] == 0x00 &&
|
||||
value[5] == 0x00 &&
|
||||
value[6] == 0x10 &&
|
||||
value[7] == 0x00 &&
|
||||
value[8] == 0x80 &&
|
||||
value[9] == 0x00 &&
|
||||
value[10] == 0x00 &&
|
||||
value[11] == 0x80 &&
|
||||
value[12] == 0x5f &&
|
||||
value[13] == 0x9b &&
|
||||
value[14] == 0x34 &&
|
||||
value[15] == 0xfb;
|
||||
|
||||
/// Creates a new UUID from 16 bytes.
|
||||
UUID(Iterable<int> value) : value = value.toList() {
|
||||
if (value.length != 16) {
|
||||
throw const FormatException('Invalid length UUID');
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a new Bluetooth UUID from the short (16 or 32 bit) encoding.
|
||||
UUID.short(int shortValue)
|
||||
: value = [
|
||||
(shortValue >> 24) & 0xff,
|
||||
(shortValue >> 16) & 0xff,
|
||||
(shortValue >> 8) & 0xff,
|
||||
(shortValue >> 0) & 0xff,
|
||||
0x00,
|
||||
0x00,
|
||||
0x10,
|
||||
0x00,
|
||||
0x80,
|
||||
0x00,
|
||||
0x00,
|
||||
0x80,
|
||||
0x5f,
|
||||
0x9b,
|
||||
0x34,
|
||||
0xfb
|
||||
];
|
||||
|
||||
/// Creates a new UUID from the string format encoding (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx where xx is a hexadecimal number).
|
||||
factory UUID.fromString(String value) {
|
||||
if (value.length == 4) {
|
||||
try {
|
||||
final shortValue = int.parse(value, radix: 16);
|
||||
return UUID.short(shortValue);
|
||||
} catch (e) {
|
||||
throw const FormatException('Invalid UUID string');
|
||||
}
|
||||
}
|
||||
var groups = value.split('-');
|
||||
if (groups.length != 5 ||
|
||||
groups[0].length != 8 ||
|
||||
groups[1].length != 4 ||
|
||||
groups[2].length != 4 ||
|
||||
groups[3].length != 4 ||
|
||||
groups[4].length != 12) {
|
||||
throw const FormatException('Invalid UUID string');
|
||||
}
|
||||
int group0, group1, group2, group3, group4;
|
||||
try {
|
||||
group0 = int.parse(groups[0], radix: 16);
|
||||
group1 = int.parse(groups[1], radix: 16);
|
||||
group2 = int.parse(groups[2], radix: 16);
|
||||
group3 = int.parse(groups[3], radix: 16);
|
||||
group4 = int.parse(groups[4], radix: 16);
|
||||
} catch (e) {
|
||||
throw const FormatException('Invalid UUID string');
|
||||
}
|
||||
return UUID([
|
||||
(group0 >> 24) & 0xff,
|
||||
(group0 >> 16) & 0xff,
|
||||
(group0 >> 8) & 0xff,
|
||||
(group0 >> 0) & 0xff,
|
||||
(group1 >> 8) & 0xff,
|
||||
(group1 >> 0) & 0xff,
|
||||
(group2 >> 8) & 0xff,
|
||||
(group2 >> 0) & 0xff,
|
||||
(group3 >> 8) & 0xff,
|
||||
(group3 >> 0) & 0xff,
|
||||
(group4 >> 40) & 0xff,
|
||||
(group4 >> 32) & 0xff,
|
||||
(group4 >> 24) & 0xff,
|
||||
(group4 >> 16) & 0xff,
|
||||
(group4 >> 8) & 0xff,
|
||||
(group4 >> 0) & 0xff
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var v0 = value[0].toRadixString(16).padLeft(2, '0');
|
||||
var v1 = value[1].toRadixString(16).padLeft(2, '0');
|
||||
var v2 = value[2].toRadixString(16).padLeft(2, '0');
|
||||
var v3 = value[3].toRadixString(16).padLeft(2, '0');
|
||||
var v4 = value[4].toRadixString(16).padLeft(2, '0');
|
||||
var v5 = value[5].toRadixString(16).padLeft(2, '0');
|
||||
var v6 = value[6].toRadixString(16).padLeft(2, '0');
|
||||
var v7 = value[7].toRadixString(16).padLeft(2, '0');
|
||||
var v8 = value[8].toRadixString(16).padLeft(2, '0');
|
||||
var v9 = value[9].toRadixString(16).padLeft(2, '0');
|
||||
var v10 = value[10].toRadixString(16).padLeft(2, '0');
|
||||
var v11 = value[11].toRadixString(16).padLeft(2, '0');
|
||||
var v12 = value[12].toRadixString(16).padLeft(2, '0');
|
||||
var v13 = value[13].toRadixString(16).padLeft(2, '0');
|
||||
var v14 = value[14].toRadixString(16).padLeft(2, '0');
|
||||
var v15 = value[15].toRadixString(16).padLeft(2, '0');
|
||||
return '$v0$v1$v2$v3-$v4$v5-$v6$v7-$v8$v9-$v10$v11$v12$v13$v14$v15';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(other) =>
|
||||
other is UUID &&
|
||||
other.value[0] == value[0] &&
|
||||
other.value[1] == value[1] &&
|
||||
other.value[2] == value[2] &&
|
||||
other.value[3] == value[3] &&
|
||||
other.value[4] == value[4] &&
|
||||
other.value[5] == value[5] &&
|
||||
other.value[6] == value[6] &&
|
||||
other.value[7] == value[7] &&
|
||||
other.value[8] == value[8] &&
|
||||
other.value[9] == value[9] &&
|
||||
other.value[10] == value[10] &&
|
||||
other.value[11] == value[11] &&
|
||||
other.value[12] == value[12] &&
|
||||
other.value[13] == value[13] &&
|
||||
other.value[14] == value[14] &&
|
||||
other.value[15] == value[15];
|
||||
|
||||
@override
|
||||
int get hashCode => value.fold(17, (prev, value) => 37 * prev + value);
|
||||
}
|
18
bluetooth_low_energy_platform_interface/pubspec.yaml
Normal file
18
bluetooth_low_energy_platform_interface/pubspec.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
name: bluetooth_low_energy_platform_interface
|
||||
description: A common platform interface for the bluetooth_low_energy plugin.
|
||||
version: 2.0.0
|
||||
homepage: https://github.com/yanshouwang/bluetooth_low_energy
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
flutter: ">=3.3.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
plugin_platform_interface: ^2.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.0
|
@ -0,0 +1 @@
|
||||
|
Reference in New Issue
Block a user