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:
Mr剑侠客
2023-08-17 17:49:26 +08:00
committed by GitHub
parent 3abe9d5b3d
commit d1726b52fa
371 changed files with 15666 additions and 15993 deletions

View 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/

View 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'

View File

@ -0,0 +1,4 @@
## 2.0.0
- Rewrite the whole project with federated plugins.
- Support macOS and Linux.

View 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.

View 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

View File

@ -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

View File

@ -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';

View File

@ -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 {},
});
}

View File

@ -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,
});
}

View File

@ -0,0 +1,7 @@
enum CentralState {
unknown,
unsupported,
unauthorized,
poweredOff,
poweredOn,
}

View File

@ -0,0 +1,10 @@
class BluetoothLowEnergyError extends Error {
final String message;
BluetoothLowEnergyError(this.message);
@override
String toString() {
return 'BluetoothLowEnergyError: $message';
}
}

View File

@ -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);
}

View File

@ -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,
});
}

View File

@ -0,0 +1,7 @@
enum GattCharacteristicProperty {
read,
write,
writeWithoutResponse,
notify,
indicate,
}

View File

@ -0,0 +1,8 @@
enum GattCharacteristicWriteType {
// Write with response
withResponse,
// Write without response
withoutResponse,
// Write with response and waiting for confirmation
// reliable,
}

View File

@ -0,0 +1,9 @@
import 'uuid.dart';
class GattDescriptor {
final UUID uuid;
GattDescriptor({
required this.uuid,
});
}

View File

@ -0,0 +1,9 @@
import 'uuid.dart';
class GattService {
final UUID uuid;
GattService({
required this.uuid,
});
}

View File

@ -0,0 +1,5 @@
import 'uuid.dart';
abstract class Peripheral {
UUID get uuid;
}

View 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);
}

View 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