提交蓝牙插件及封装

This commit is contained in:
魏少阳 2023-07-26 09:27:43 +08:00
parent 681ed316bc
commit 32b7f4cb52
16 changed files with 896 additions and 11 deletions

View File

@ -1,5 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.star_lock"> package="com.example.star_lock"
xmlns:tools="http://schemas.android.com/tools">
<!-- The INTERNET permission is required for development. Specifically, <!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
@ -8,4 +9,12 @@
<uses-permission android:name="android.permission.WRITE_CONTACTS"/> <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
tools:remove="android:usesPermissionFlags"
tools:targetApi="s" />
</manifest> </manifest>

View File

@ -1,6 +1,7 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
# platform :ios, '11.0' # platform :ios, '11.0'
#use_modular_headers!
use_frameworks! :linkage => :static
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'

View File

@ -11,6 +11,12 @@ PODS:
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- Protobuf (3.23.4)
- reactive_ble_mobile (0.0.1):
- Flutter
- Protobuf (~> 3.5)
- SwiftProtobuf (~> 1.0)
- SwiftProtobuf (1.22.0)
- url_launcher_ios (0.0.1): - url_launcher_ios (0.0.1):
- Flutter - Flutter
@ -21,8 +27,14 @@ DEPENDENCIES:
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- reactive_ble_mobile (from `.symlinks/plugins/reactive_ble_mobile/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS:
trunk:
- Protobuf
- SwiftProtobuf
EXTERNAL SOURCES: EXTERNAL SOURCES:
device_info_plus: device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios" :path: ".symlinks/plugins/device_info_plus/ios"
@ -36,6 +48,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/package_info_plus/ios" :path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation: path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin" :path: ".symlinks/plugins/path_provider_foundation/darwin"
reactive_ble_mobile:
:path: ".symlinks/plugins/reactive_ble_mobile/ios"
url_launcher_ios: url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios" :path: ".symlinks/plugins/url_launcher_ios/ios"
@ -45,9 +59,12 @@ SPEC CHECKSUMS:
flutter_native_contact_picker: bd430ba0fbf82768bb50c2c52a69a65759a8f907 flutter_native_contact_picker: bd430ba0fbf82768bb50c2c52a69a65759a8f907
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8 path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
Protobuf: c6bc59bbab3d38a71c67f62d7cb7ca8f8ea4eca1
reactive_ble_mobile: 9ce6723d37ccf701dbffd202d487f23f5de03b4c
SwiftProtobuf: 40bd808372cb8706108f22d28f8ab4a6b9bc6989
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
PODFILE CHECKSUM: 663715e941f9adb426e33bf9376914006f9ea95b PODFILE CHECKSUM: 2f695eae20a86ca77f41095e9bd74ba52bd6304c
COCOAPODS: 1.12.1 COCOAPODS: 1.12.1

View File

@ -9,7 +9,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3ED61D98CC08F93BC18EEFD0 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B7537A79A618D0BBB434A17B /* libPods-Runner.a */; }; 3EF1E85D6F1EE0C0DCF8449F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09D8B2FA2B26BA5BFF31AB2A /* Pods_Runner.framework */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
@ -31,6 +31,7 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
09D8B2FA2B26BA5BFF31AB2A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
@ -46,7 +47,6 @@
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
99F6494C6B1A24363CCC6D32 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; }; 99F6494C6B1A24363CCC6D32 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
B7537A79A618D0BBB434A17B /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
BDB5B400176768766E85D5EB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; }; BDB5B400176768766E85D5EB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
DC20461C9C4624BEB2DCD779 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; }; DC20461C9C4624BEB2DCD779 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@ -56,7 +56,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
3ED61D98CC08F93BC18EEFD0 /* libPods-Runner.a in Frameworks */, 3EF1E85D6F1EE0C0DCF8449F /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -76,7 +76,7 @@
9304F75C378DB3447BB2408C /* Frameworks */ = { 9304F75C378DB3447BB2408C /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
B7537A79A618D0BBB434A17B /* libPods-Runner.a */, 09D8B2FA2B26BA5BFF31AB2A /* Pods_Runner.framework */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@ -349,6 +349,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 7NLFRKNVY3; DEVELOPMENT_TEAM = 7NLFRKNVY3;
@ -475,6 +476,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 7NLFRKNVY3; DEVELOPMENT_TEAM = 7NLFRKNVY3;
@ -494,6 +496,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 7NLFRKNVY3; DEVELOPMENT_TEAM = 7NLFRKNVY3;

View File

@ -14,6 +14,10 @@
</array> </array>
<key>NSContactsUsageDescription</key> <key>NSContactsUsageDescription</key>
<string>Reason we need access to the contact list</string> <string>Reason we need access to the contact list</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>The app uses bluetooth to find, connect and transfer data between different devices</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>The app uses bluetooth to find, connect and transfer data between different devices</string>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>

View File

@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:star_lock/tools/app_manager.dart'; import 'package:star_lock/tools/app_manager.dart';
import 'package:star_lock/tools/device_info_service.dart'; import 'package:star_lock/tools/device_info_service.dart';
import 'package:star_lock/tools/platform_info_services.dart'; import 'package:star_lock/tools/platform_info_services.dart';
import 'package:star_lock/tools/reactiveBlueTool/getx_ble.dart';
import 'package:star_lock/tools/store_service.dart'; import 'package:star_lock/tools/store_service.dart';
import 'package:star_lock/translations/app_dept.dart'; import 'package:star_lock/translations/app_dept.dart';
import 'package:star_lock/translations/trans_lib.dart'; import 'package:star_lock/translations/trans_lib.dart';
@ -19,6 +19,8 @@ void main() async {
// //
await _initTranslation(); await _initTranslation();
GetxBle();
runApp(MyApp()); runApp(MyApp());
} }

View File

@ -47,7 +47,8 @@ class _UnlockQRCodePageState extends State<UnlockQRCodePage> {
// data:'二维码', // data:'二维码',
// size:300, // size:300,
// ), // ),
QrImage(data: 'www.baidu.com', size: 300.w), // QrImage(data: 'www.baidu.com', size: 300.w),
QrImageView(data: 'www.baidu.com', size: 300.w),
SizedBox(height: 50.w,), SizedBox(height: 50.w,),
SubmitBtn(btnName: TranslationLoader.lanKeys!.share!.tr, SubmitBtn(btnName: TranslationLoader.lanKeys!.share!.tr,
borderRadius: 20.w, borderRadius: 20.w,

View File

@ -1,4 +1,7 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:star_lock/app_settings/app_colors.dart'; import 'package:star_lock/app_settings/app_colors.dart';
@ -7,6 +10,7 @@ import 'package:star_lock/mine/mineSet/mineSet_page.dart';
import '../../appRouters.dart'; import '../../appRouters.dart';
import '../../baseWidget.dart'; import '../../baseWidget.dart';
import '../../mine/mine_page.dart'; import '../../mine/mine_page.dart';
import '../../tools/reactiveBlueTool/getx_ble.dart';
import '../../tools/titleAppBar.dart'; import '../../tools/titleAppBar.dart';
import '../../translations/trans_lib.dart'; import '../../translations/trans_lib.dart';
@ -18,6 +22,26 @@ class StarLockMain extends StatefulWidget {
} }
class _StarLockMainState extends State<StarLockMain> with BaseWidget{ class _StarLockMainState extends State<StarLockMain> with BaseWidget{
// final logic = Get.put(GetxBle());
StreamSubscription<DiscoveredDevice>? _streamSubscription;
StreamSubscription<ConnectionStateUpdate>? _connectionStreamSubscription;
final flutterReactiveBle = FlutterReactiveBle();
List<DiscoveredDevice> deviceList = [];
@override
void setState(VoidCallback fn) {
// TODO: implement setState
super.setState(fn);
// BleScanner.to.startScan([
//
// ]);
GetxBle.call.scanner.startScan([]);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(

View File

@ -0,0 +1,65 @@
import 'dart:async';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:get/get.dart';
class BleDeviceConnector extends GetxController {
BleDeviceConnector({
required FlutterReactiveBle ble,
required void Function(String message) logMessage,
}) : _ble = ble,
_logMessage = logMessage {
rxBleConnectionState.bindStream(_deviceConnectionController.stream);
}
final FlutterReactiveBle _ble;
final void Function(String message) _logMessage;
final rxBleConnectionState = Rx<ConnectionStateUpdate>(
const ConnectionStateUpdate(
deviceId: "",
connectionState: DeviceConnectionState.disconnected,
failure: null));
final _deviceConnectionController = StreamController<ConnectionStateUpdate>();
late StreamSubscription<ConnectionStateUpdate> _connection;
Future<void> connect(String deviceMAC) async {
_logMessage('Start connecting to $deviceMAC');
_connection = _ble.connectToDevice(id: deviceMAC).listen(
(update) {
_logMessage(
'ConnectionState for device $deviceMAC : ${update.connectionState}');
_deviceConnectionController.add(update);
},
onError: (Object e) =>
_logMessage('Connecting to device $deviceMAC resulted in error $e'),
);
}
Future<void> disconnect(String deviceMAC) async {
try {
_logMessage('disconnecting to device: $deviceMAC');
await _connection.cancel();
} on Exception catch (e, _) {
_logMessage("Error disconnecting from a device: $e");
} finally {
// Since [_connection] subscription is terminated, the "disconnected" state cannot be received and propagated
_deviceConnectionController.add(
ConnectionStateUpdate(
deviceId: deviceMAC,
connectionState: DeviceConnectionState.disconnected,
failure: null,
),
);
}
}
@override
Future<void> onClose() async {
rxBleConnectionState.close();
await _deviceConnectionController.close();
super.onClose();
}
}

View File

@ -0,0 +1,82 @@
import 'dart:async';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:get/get.dart';
class BleDeviceInteractor extends GetxController {
BleDeviceInteractor({
required FlutterReactiveBle ble,
required void Function(String message) logMessage,
}) : _ble = ble,
_logMessage = logMessage;
final FlutterReactiveBle _ble;
final void Function(String message) _logMessage;
Future<List<DiscoveredService>> discoverServices(String deviceId) async {
try {
_logMessage('Start discovering services for: $deviceId');
final result = await _ble.discoverServices(deviceId);
_logMessage('Discovering services finished');
return result;
} on Exception catch (e) {
_logMessage('Error occurred when discovering services: $e');
rethrow;
}
}
Future<List<int>> readCharacteristic(
QualifiedCharacteristic characteristic) async {
try {
final result = await _ble.readCharacteristic(characteristic);
_logMessage('Read ${characteristic.characteristicId}: value = $result');
return result;
} on Exception catch (e, s) {
_logMessage(
'Error occurred when reading ${characteristic.characteristicId} : $e',
);
// ignore: avoid_print
print(s);
rethrow;
}
}
Future<void> writeCharacteristicWithResponse(
QualifiedCharacteristic characteristic, List<int> value) async {
try {
_logMessage(
'Write with response value : $value to ${characteristic.characteristicId}');
await _ble.writeCharacteristicWithResponse(characteristic, value: value);
} on Exception catch (e, s) {
_logMessage(
'Error occurred when writing ${characteristic.characteristicId} : $e',
);
// ignore: avoid_print
print(s);
rethrow;
}
}
Future<void> writeCharacteristicWithoutResponse(
QualifiedCharacteristic characteristic, List<int> value) async {
try {
await _ble.writeCharacteristicWithoutResponse(characteristic,
value: value);
_logMessage(
'Write without response value: $value to ${characteristic.characteristicId}');
} on Exception catch (e, s) {
_logMessage(
'Error occurred when writing ${characteristic.characteristicId} : $e',
);
// ignore: avoid_print
print(s);
rethrow;
}
}
Stream<List<int>> subScribeToCharacteristic(
QualifiedCharacteristic characteristic) {
_logMessage('Subscribing to: ${characteristic.characteristicId} ');
return _ble.subscribeToCharacteristic(characteristic);
}
}

View File

@ -0,0 +1,28 @@
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:get/get.dart';
class BleLogger extends GetxController {
BleLogger({
required FlutterReactiveBle ble,
}) : _ble = ble;
final FlutterReactiveBle _ble;
final Rx<List<String>> rxMessages = Rx<List<String>>([]);
final RxBool rxVerboseLogging = false.obs;
void addToLog(String message) {
final now = DateTime.now();
final formattedDate = '${now.year}-${now.month}-${now.day} ${now.hour}:${now.minute}:${now.second}';
rxMessages.value.add('$formattedDate - $message');
}
void clearLogs() => rxMessages.value.clear();
void verboseLoggingUpdate() {
if (rxVerboseLogging.value) {
_ble.logLevel = LogLevel.verbose;
} else {
_ble.logLevel = LogLevel.none;
}
}
}

View File

@ -0,0 +1,114 @@
import 'dart:async';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:get/get.dart';
import 'package:meta/meta.dart';
///
class BleScanner extends GetxController {
BleScanner({
required FlutterReactiveBle ble,
required void Function(String message) logMessage,
}) : _ble = ble,
_logMessage = logMessage {
rxBleScannerState.bindStream(_stateStreamController.stream);
}
// static BleScanner get to => Get.find<BleScanner>();
final FlutterReactiveBle _ble;
/// FlutterReactiveBle
final void Function(String message) _logMessage;
///
final StreamController<BleScannerState> _stateStreamController =
StreamController();
StreamSubscription? _subscription;
/// 使 Getx Rx
final rxBleScannerState = Rx<BleScannerState>(
const BleScannerState(discoveredDevices: [], scanIsInProgress: false));
final _devices = <DiscoveredDevice>[];
///
void startScan(List<Uuid> serviceIds) {
_logMessage('Start ble discovery');
_devices.clear();
_subscription?.cancel();
_subscription = _ble.scanForDevices(withServices: serviceIds).listen((device) {
final knownDeviceIndex = _devices.indexWhere((d) => d.id == device.id);
if (knownDeviceIndex >= 0) {
_devices[knownDeviceIndex] = device;
} else {
// if (device.name.toLowerCase().contains((filter.name ?? "".toLowerCase()))) {
// if (device.id.contains((filter.mac ?? ""))) {
// if (device.rssi >= (filter.rssi ?? -100)) {
_devices.add(device);
// }
// }
// }
}
_pushState();
}, onError: (Object e) => _logMessage('Device scan fails with error: $e'));
_pushState();
}
///
void _pushState() {
_stateStreamController.add(
BleScannerState(
discoveredDevices: _devices,
scanIsInProgress: _subscription != null,
),
);
}
///
Future<void> stopScan() async {
_logMessage('Stop ble discovery');
await _subscription?.cancel();
_subscription = null;
_pushState();
}
/// GetxController
@override
Future<void> onClose() async {
rxBleScannerState.close();
await _stateStreamController.close();
super.onClose();
}
}
///
@immutable
class BleScannerState {
const BleScannerState({
required this.discoveredDevices,
required this.scanIsInProgress,
});
final List<DiscoveredDevice> discoveredDevices;
final bool scanIsInProgress;
}
///
class BleScannerFilter {
String? name;
String? mac;
List<Uuid>? serviceId;
int? rssi;
BleScannerFilter({
this.name,
this.mac,
this.serviceId,
this.rssi,
});
}

View File

@ -0,0 +1,485 @@
class BleSigGattUuids {
static const Map serviceUuids = {
"1800": "Generic Access",
"1811": "Alert Notification Service",
"1815": "Automation IO",
"180F": "Battery Service",
"1810": "Blood Pressure",
"181B": "Body Composition",
"181E": "Bond Management Service",
"181F": "Continuous Glucose Monitoring",
"1805": "Current Time Service",
"1818": "Cycling Power",
"1816": "Cycling Speed and Cadence",
"180A": "Device Information",
"181A": "Environmental Sensing",
"1826": "Fitness Machine",
"1801": "Generic Attribute",
"1808": "Glucose",
"1809": "Health Thermometer",
"180D": "Heart Rate",
"1823": "HTTP Proxy",
"1812": "Human Interface Device",
"1802": "Immediate Alert",
"1821": "Indoor Positioning",
"183A": "Insulin Delivery",
"1820": "Internet Protocol Support Service",
"1803": "Link Loss",
"1819": "Location and Navigation",
"1827": "Mesh Provisioning Service",
"1828": "Mesh Proxy Service",
"1807": "Next DST Change Service",
"1825": "Object Transfer Service",
"180E": "Phone Alert Status Service",
"1822": "Pulse Oximeter Service",
"1829": "Reconnection Configuration",
"1806": "Reference Time Update Service",
"1814": "Running Speed and Cadence",
"1813": "Scan Parameters",
"1824": "Transport Discovery",
"1804": "Tx Power",
"181C": "User Data",
"181D": "Weight Scale",
"183B": "Binary Sensor",
"183C": "Emergency Configuration",
"183E": "Physical Activity Monitor",
"1843": "Audio Input Control",
"1844": "Volume Control",
"1845": "Volume Offset Control",
"1846": "Coordinated Set Identification",
"1847": "Device Time",
"1848": "Media Control",
"1849": "Generic Media Control",
"184A": "Constant Tone Extension",
"184B": "Telephone Bearer",
"184C": "Generic Telephone Bearer",
"184D": "Microphone Control",
"184E": "Audio Stream Control",
"184F": "Broadcast Audio Scan",
"1850": "Published Audio Capabilities",
"1851": "Published Audio Data",
"1852": "Broadcast Audio Announcement",
"1853": "Common Audio",
"1854": "Hearing Access",
"1855": "TMAS"
};
static const Map characteristicUuids = {
"2A7E": "Aerobic Heart Rate Lower Limit",
"2A84": "Aerobic Heart Rate Upper Limit",
"2A7F": "Aerobic Threshold",
"2A80": "Age",
"2A5A": "Aggregate",
"2A43": "Alert Category ID",
"2A42": "Alert Category ID Bit Mask",
"2A06": "Alert Level",
"2A44": "Alert Notification Control Point",
"2A3F": "Alert Status",
"2AB3": "Altitude",
"2A81": "Anaerobic Heart Rate Lower Limit",
"2A82": "Anaerobic Heart Rate Upper Limit",
"2A83": "Anaerobic Threshold",
"2A58": "Analog",
"2A59": "Analog Output",
"2A73": "Apparent Wind Direction",
"2A72": "Apparent Wind Speed",
"2A01": "Appearance",
"2AA3": "Barometric Pressure Trend",
"2A19": "Battery Level",
"2A1B": "Battery Level State",
"2A1A": "Battery Power State",
"2A49": "Blood Pressure Feature",
"2A35": "Blood Pressure Measurement",
"2A9B": "Body Composition Feature",
"2A9C": "Body Composition Measurement",
"2A38": "Body Sensor Location",
"2AA4": "Bond Management Control Point",
"2AA5": "Bond Management Features",
"2A22": "Boot Keyboard Input Report",
"2A32": "Boot Keyboard Output Report",
"2A33": "Boot Mouse Input Report",
"2AA6": "Central Address Resolution",
"2AA8": "CGM Feature",
"2AA7": "CGM Measurement",
"2AAB": "CGM Session Run Time",
"2AAA": "CGM Session Start Time",
"2AAC": "CGM Specific Ops Control Point",
"2AA9": "CGM Status",
"2ACE": "Cross Trainer Data",
"2A5C": "CSC Feature",
"2A5B": "CSC Measurement",
"2A2B": "Current Time",
"2A66": "Cycling Power Control Point",
"2A65": "Cycling Power Feature",
"2A63": "Cycling Power Measurement",
"2A64": "Cycling Power Vector",
"2A99": "Database Change Increment",
"2A85": "Date of Birth",
"2A86": "Date of Threshold Assessment",
"2A08": "Date Time",
"2A0A": "Day Date Time",
"2A09": "Day of Week",
"2A7D": "Descriptor Value Changed",
"2A00": "Device Name",
"2A7B": "Dew Point",
"2A56": "Digital",
"2A57": "Digital Output",
"2A0D": "DST Offset",
"2A6C": "Elevation",
"2A87": "Email Address",
"2A0B": "Exact Time 100",
"2A0C": "Exact Time 256",
"2A88": "Fat Burn Heart Rate Lower Limit",
"2A89": "Fat Burn Heart Rate Upper Limit",
"2A26": "Firmware Revision String",
"2A8A": "First Name",
"2AD9": "Fitness Machine Control Point",
"2ACC": "Fitness Machine Feature",
"2ADA": "Fitness Machine Status",
"2A8B": "Five Zone Heart Rate Limits",
"2AB2": "Floor Number",
"2A8C": "Gender",
"2A51": "Glucose Feature",
"2A18": "Glucose Measurement",
"2A34": "Glucose Measurement Context",
"2A74": "Gust Factor",
"2A27": "Hardware Revision String",
"2A39": "Heart Rate Control Point",
"2A8D": "Heart Rate Max",
"2A37": "Heart Rate Measurement",
"2A7A": "Heat Index",
"2A8E": "Height",
"2A4C": "HID Control Point",
"2A4A": "HID Information",
"2A8F": "Hip Circumference",
"2ABA": "HTTP Control Point",
"2AB9": "HTTP Entity Body",
"2AB7": "HTTP Headers",
"2AB8": "HTTP Status Code",
"2ABB": "HTTPS Security",
"2A6F": "Humidity",
"2B22": "IDD Annunciation Status",
"2B25": "IDD Command Control Point",
"2B26": "IDD Command Data",
"2B23": "IDD Features",
"2B28": "IDD History Data",
"2B27": "IDD Record Access Control Point",
"2B21": "IDD Status",
"2B20": "IDD Status Changed",
"2B24": "IDD Status Reader Control Point",
"2A2A": "IEEE 11073-20601 Regulatory Certification Data List",
"2AD2": "Indoor Bike Data",
"2AAD": "Indoor Positioning Configuration",
"2A36": "Intermediate Cuff Pressure",
"2A1E": "Intermediate Temperature",
"2A77": "Irradiance",
"2AA2": "Language",
"2A90": "Last Name",
"2AAE": "Latitude",
"2A6B": "LN Control Point",
"2A6A": "LN Feature",
"2AB1": "Local East Coordinate",
"2AB0": "Local North Coordinate",
"2A0F": "Local Time Information",
"2A67": "Location and Speed Characteristic",
"2AB5": "Location Name",
"2AAF": "Longitude",
"2A2C": "Magnetic Declination",
"2AA0": "Magnetic Flux Density - 2D",
"2AA1": "Magnetic Flux Density - 3D",
"2A29": "Manufacturer Name String",
"2A91": "Maximum Recommended Heart Rate",
"2A21": "Measurement Interval",
"2A24": "Model Number String",
"2A68": "Navigation",
"2A3E": "Network Availability",
"2A46": "New Alert",
"2AC5": "Object Action Control Point",
"2AC8": "Object Changed",
"2AC1": "Object First-Created",
"2AC3": "Object ID",
"2AC2": "Object Last-Modified",
"2AC6": "Object List Control Point",
"2AC7": "Object List Filter",
"2ABE": "Object Name",
"2AC4": "Object Properties",
"2AC0": "Object Size",
"2ABF": "Object Type",
"2ABD": "OTS Feature",
"2A04": "Peripheral Preferred Connection Parameters",
"2A02": "Peripheral Privacy Flag",
"2A5F": "PLX Continuous Measurement Characteristic",
"2A60": "PLX Features",
"2A5E": "PLX Spot-Check Measurement",
"2A50": "PnP ID",
"2A75": "Pollen Concentration",
"2A2F": "Position 2D",
"2A30": "Position 3D",
"2A69": "Position Quality",
"2A6D": "Pressure",
"2A4E": "Protocol Mode",
"2A62": "Pulse Oximetry Control Point",
"2A78": "Rainfall",
"2B1D": "RC Feature",
"2B1E": "RC Settings",
"2A03": "Reconnection Address",
"2B1F": "Reconnection Configuration Control Point",
"2A52": "Record Access Control Point",
"2A14": "Reference Time Information",
"2A3A": "Removable",
"2A4D": "Report",
"2A4B": "Report Map",
"2AC9": "Resolvable Private Address Only",
"2A92": "Resting Heart Rate",
"2A40": "Ringer Control point",
"2A41": "Ringer Setting",
"2AD1": "Rower Data",
"2A54": "RSC Feature",
"2A53": "RSC Measurement",
"2A55": "SC Control Point",
"2A4F": "Scan Interval Window",
"2A31": "Scan Refresh",
"2A3C": "Scientific Temperature Celsius",
"2A10": "Secondary Time Zone",
"2A5D": "Sensor Location",
"2A05": "Service Changed",
"2A0E": "Time Zone",
"2A11": "Time with DST",
"2A12": "Time Accuracy",
"2A13": "Time Source",
"2A15": "Time Broadcast",
"2A16": "Time Update Control Point",
"2A17": "Time Update State",
"2A25": "Serial Number String",
"2A3B": "Service Required",
"2A28": "Software Revision String",
"2A93": "Sport Type for Aerobic and Anaerobic Thresholds",
"2AD0": "Stair Climber Data",
"2ACF": "Step Climber Data",
"2A3D": "String",
"2AD7": "Supported Heart Rate Range",
"2AD5": "Supported Inclination Range",
"2A47": "Supported New Alert Category",
"2AD8": "Supported Power Range",
"2AD6": "Supported Resistance Level Range",
"2AD4": "Supported Speed Range",
"2A48": "Supported Unread Alert Category",
"2A23": "System ID",
"2ABC": "TDS Control Point",
"2A6E": "Temperature",
"2A1F": "Temperature Celsius",
"2A20": "Temperature Fahrenheit",
"2A1C": "Temperature Measurement",
"2A1D": "Temperature Type",
"2A94": "Three Zone Heart Rate Limits",
"2A70": "True Wind Speed",
"2A71": "True Wind Direction",
"2A95": "Two Zone Heart Rate Limit",
"2A07": "Tx Power Level",
"2AB4": "Uncertainty",
"2A45": "Unread Alert Status",
"2AB6": "URI",
"2A9F": "User Control Point",
"2A9A": "User Index",
"2A76": "UV Index",
"2A79": "Wind Chill",
"2A96": "VO2 Max",
"2A97": "Waist Circumference",
"2A98": "Weight",
"2A9D": "Weight Measurement",
"2A9E": "Weight Scale Feature",
"2ACD": "Treadmill Data",
"2AD3": "Training Status",
"2AE0": "Average Current",
"2AE1": "Average Voltage",
"2AE2": "Boolean",
"2AE3": "Chromatic Distance From Planckian",
"2AE4": "Chromaticity Coordinates",
"2AE5": "Chromaticity In CCT And Duv Values",
"2AE6": "Chromaticity Tolerance",
"2AE7": "CIE 13.3-1995 Color Rendering Index",
"2AE8": "Coefficient",
"2AE9": "Correlated Color Temperature",
"2AEA": "Count 16",
"2AEB": "Count 24",
"2AEC": "Country Code",
"2AED": "Date UTC",
"2AEE": "Electric Current",
"2AEF": "Electric Current Range",
"2AF0": "Electric Current Specification",
"2AF1": "Electric Current Statistics",
"2AF2": "Energy",
"2AF3": "Energy In A Period Of Day",
"2AF4": "Event Statistics",
"2AF5": "Fixed String 16",
"2AF6": "Fixed String 24",
"2AF7": "Fixed String 36",
"2AF8": "Fixed String 8",
"2AF9": "Generic Level",
"2AFA": "Global Trade Item Number",
"2AFB": "Illuminance",
"2AFC": "Luminous Efficacy",
"2AFD": "Luminous Energy",
"2AFE": "Luminous Exposure",
"2AFF": "Luminous Flux",
"2B00": "Luminous Flux Range",
"2B01": "Luminous Intensity",
"2B02": "B02 Mass Flow",
"2B03": "Perceived Lightness",
"2B04": "Percentage 8",
"2B05": "Power",
"2B06": "Power Specification",
"2B07": "Relative Runtime In A Current Range",
"2B08": "Relative Runtime In A Generic Level Range",
"2B09": "Relative Value In A Voltage Range",
"2B0A": "Relative Value In An Illuminance Range",
"2B0B": "Relative Value In A Period Of Day",
"2B0C": "Relative Value In A Temperature Range",
"2B0D": "Temperature 8",
"2B0E": "Temperature 8 In A Period Of Day",
"2B0F": "Temperature 8 Statistics",
"2B10": "Temperature Range",
"2B11": "Temperature Statistics",
"2B12": "Time Decihour 8",
"2B13": "Time Exponential 8",
"2B14": "Time Hour 24",
"2B15": "Time Millisecond 24",
"2B16": "Time Second 16",
"2B17": "Time Second 8",
"2B18": "Voltage",
"2B19": "Voltage Specification",
"2B1A": "Volume Flow",
"2B1B": "Volume Flow",
"2B1C": "Volume Flow In A Period Of Day",
"2B29": "Client Supported Features",
"2B2A": "Database Hash",
"2B2B": "BSS Control Point",
"2B2C": "BSS Response",
"2B2D": "Emergency ID",
"2B2E": "Emergency Text",
"2B34": "Enhanced Blood Pressure Measurement",
"2B35": "Enhanced Intermediate Cuff Pressure",
"2B36": "Blood Pressure Record",
"2B38": "BR-EDR Handover Data",
"2B39": "Bluetooth SIG Data",
"2B3A": "Server Supported Features",
"2B3B": "Physical Activity Monitor Features",
"2B3C": "General Activity Instantaneous Data",
"2B3D": "General Activity Summary Data",
"2B3E": "CardioRespiratory Activity Instantaneous Data",
"2B3F": "CardioRespiratory Activity Summary Data",
"2B40": "Step Counter Activity Summary Data",
"2B41": "Sleep Activity Instantaneous Data",
"2B42": "Sleep Activity Summary Data",
"2B43": "Physical Activity Monitor Control Point",
"2B44": "Activity Current Session",
"2B45": "Physical Activity Session Descriptor",
"2B46": "Preferred Units",
"2B47": "High Resolution Height",
"2B48": "Middle Name",
"2B49": "Stride Length",
"2B4A": "Handedness",
"2B4B": "Device Wearing Position",
"2B4C": "Four Zone Heart Rate Limits",
"2B4D": "High Intensity Exercise Threshold",
"2B4E": "Activity Goal",
"2B4F": "Sedentary Interval Notification",
"2B50": "Caloric Intake",
"2B51": "TMAP Role",
"2B77": "Audio Input State",
"2B78": "Audio Input Control Point",
"2B79": "Audio Input Type",
"2B7A": "Audio Input Status",
"2B7B": "Audio Input Control Point",
"2B7C": "Audio Input Description",
"2B7D": "Volume State",
"2B7E": "Volume Control Point",
"2B7F": "Volume Flags",
"2B80": "Volume Offset State",
"2B81": "Audio Location",
"2B82": "Volume Offset Control Point",
"2B83": "Audio Output State",
"2B84": "Set Identity Resolving Key",
"2B85": "Coordinated Set Size",
"2B86": "Set Member Lock",
"2B87": "Set Member Rank",
"2B8E": "Device Time Feature",
"2B8F": "Device Time Parameters",
"2B90": "Device Time",
"2B91": "Device Time Control Point",
"2B92": "Time Change Log Data",
"2B93": "Media Player Name",
"2B94": "Media Player Icon Object ID",
"2B95": "Media Player Icon URL",
"2B96": "Track Changed",
"2B97": "Track Title",
"2B98": "Track Duration",
"2B99": "Track Position",
"2B9A": "Playback Speed",
"2B9B": "Seeking Speed",
"2B9C": "Current Track Segments Object ID",
"2B9D": "Current Track Object ID",
"2B9E": "Next Track Object ID",
"2B9F": "Parent Group Object ID",
"2BA0": "Current Group Object ID",
"2BA1": "Playing Order",
"2BA2": "Playing Orders Supported",
"2BA3": "Media State",
"2BA4": "Media Control Point",
"2BA5": "Media Control Point Opcodes Supported",
"2BA6": "Search Results Object ID",
"2BA7": "Search Control Point",
"2BA9": "Media Player Icon Object Type",
"2BAA": "Track Segments Object Type",
"2BAB": "Track Object Type",
"2BAC": "Group Object Type",
"2BAD": "Constant Tone Extension Enable",
"2BAE": "Advertising Constant Tone Extension Minimum Length",
"2BAF": "Advertising Constant Tone Extension Minimum Transmit Count",
"2BB0": "Advertising Constant Tone Extension Transmit Duration",
"2BB1": "Advertising Constant Tone Extension Interval",
"2BB2": "Advertising Constant Tone Extension PHY",
"2BB3": "Bearer Provider Name",
"2BB4": "Bearer UCI",
"2BB5": "Bearer Technology",
"2BB6": "Bearer URI Schemes Supported List",
"2BB7": "Bearer Signal Strength",
"2BB8": "Bearer Signal Strength Reporting Interval",
"2BB9": "Bearer List Current Calls",
"2BBA": "Content Control ID",
"2BBB": "Status Flags",
"2BBC": "Incoming Call Target Bearer URI",
"2BBD": "Call State",
"2BBE": "Call Control Point",
"2BBF": "Call Control Point Optional Opcodes",
"2BC0": "Termination Reason",
"2BC1": "Incoming Call",
"2BC2": "Call Friendly Name",
"2BC3": "Mute",
"2BC4": "Sink ASE",
"2BC5": "Source ASE",
"2BC6": "ASE Control Point",
"2BC7": "Broadcast Audio Scan Control Point",
"2BC8": "Broadcast Receive State",
"2BC9": "Sink PAC",
"2BCA": "Sink Audio Locations",
"2BCB": "Source PAC",
"2BCC": "Source Audio Locations",
"2BCD": "Available Audio Contexts",
"2BCE": "Supported Audio Contexts",
"2BCF": "Ammonia Concentration",
"2BD0": "Carbon Monoxide Concentration",
"2BD1": "Nitrogen Dioxide Concentration",
"2BD2": "Nitrogen Dioxide Concentration",
"2BD3": "Non-Methane Volatile Organic Compounds Concentration",
"2BD4": "Ozone Concentration",
"2BD5": "Particulate Matter - PM1 Concentration",
"2BD6": "Particulate Matter - PM2.5 Concentration",
"2BD7": "Particulate Matter - PM10 Concentration",
"2BD8": "Sulfur Dioxide Concentration",
"2BD9": "Sulfur Hexafluoride Concentration",
"2BDA": "Hearing Aid Features",
"2BDB": "Hearing Aid Preset Control Point",
"2BDC": "Hearing Aid Preset",
};
}

View File

@ -0,0 +1,12 @@
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:get/get.dart';
class BleStatusMonitor extends GetxController {
BleStatusMonitor(this._ble) {
rxBleStatus.bindStream(_ble.statusStream);
}
final FlutterReactiveBle _ble;
final Rx<BleStatus> rxBleStatus = BleStatus.unknown.obs;
}

View File

@ -0,0 +1,34 @@
library getx_ble;
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'ble_device_connector.dart';
import 'ble_device_interactor.dart';
import 'ble_logger.dart';
import 'ble_scanner.dart';
import 'package:get/get.dart';
import 'ble_status_monitor.dart';
export 'ble_device_connector.dart';
export 'ble_device_interactor.dart';
export 'ble_logger.dart';
export 'ble_scanner.dart';
export 'ble_status_monitor.dart';
class GetxBle extends GetxController {
static GetxBle get call => Get.find<GetxBle>();
final ble = FlutterReactiveBle();
late final BleLogger bleLogger;
late final BleStatusMonitor bleStatusMonitor;
late final BleScanner scanner;
late final BleDeviceConnector connector;
late final BleDeviceInteractor interactor;
GetxBle() {
bleLogger = BleLogger(ble: ble);
bleStatusMonitor = BleStatusMonitor(ble);
scanner = BleScanner(ble: ble, logMessage: bleLogger.addToLog);
connector = BleDeviceConnector(ble: ble, logMessage: bleLogger.addToLog);
interactor = BleDeviceInteractor(ble: ble, logMessage: bleLogger.addToLog);
}
}

View File

@ -57,7 +57,7 @@ dependencies:
#底部弹出选择器 #底部弹出选择器
flutter_picker: ^2.1.0 flutter_picker: ^2.1.0
#生成二维码 #生成二维码
qr_flutter: ^4.0.0 qr_flutter: ^4.1.0
#底部选择 #底部选择
flutter_pickers: ^2.1.9 flutter_pickers: ^2.1.9
#万年历 #万年历
@ -66,6 +66,10 @@ dependencies:
image_picker: ^1.0.1 image_picker: ^1.0.1
#跳转到外部 #跳转到外部
url_launcher: ^6.1.12 url_launcher: ^6.1.12
#蓝牙
flutter_reactive_ble: ^5.1.1
# flutter_blue_plus: ^1.10.5
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter