From 689b1fb0458f5935fc96846678efbeab6176d656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mr=E5=89=91=E4=BE=A0=E5=AE=A2?= Date: Fri, 18 Aug 2023 18:24:24 +0800 Subject: [PATCH] 2.0.1 (#10) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 修复 iOS 和 macOS 断开后 GATT 被清理导致操作无法完成的问题 * fix: 调整 GATT 缓存 * fix: 修改 iOS 蓝牙使用描述 * fix: 修复无法通过设备地址生成 UUID 的问题,修复由于 bluez 未重写 hashCode 和 equals 导致无法比较缓存实例的问题 * fix: 修改版本信息 * fix: 修复BUG * fix: 调整示例程序 * fix: 优化代码 * fix: 修改版本号 * fix: 更新 REDEME.md * fix: 更新依赖项 * fix: 项目调整 --------- Co-authored-by: jetson2 --- bluetooth_low_energy/CHANGELOG.md | 6 + bluetooth_low_energy/README.md | 2 +- .../example/ios/Runner/Info.plist | 2 +- bluetooth_low_energy/example/lib/main.dart | 9 +- bluetooth_low_energy/example/pubspec.lock | 26 +-- bluetooth_low_energy/ios/.gitignore | 38 ---- bluetooth_low_energy/ios/Assets/.gitkeep | 0 .../Classes/BluetoothLowEnergyPlugin.swift | 19 -- bluetooth_low_energy/linux/CMakeLists.txt | 94 ---------- .../linux/bluetooth_low_energy_plugin.cc | 76 -------- .../bluetooth_low_energy_plugin_private.h | 10 - .../bluetooth_low_energy_plugin.h | 26 --- .../test/bluetooth_low_energy_plugin_test.cc | 31 --- .../Classes/BluetoothLowEnergyPlugin.swift | 19 -- bluetooth_low_energy/pubspec.yaml | 14 +- bluetooth_low_energy/windows/.gitignore | 17 -- bluetooth_low_energy/windows/CMakeLists.txt | 96 ---------- bluetooth_low_energy_android/CHANGELOG.md | 6 + .../bluetooth_low_energy/MyApi.g.kt | 43 +++-- .../MyCentralController.kt | 152 ++++++++------- .../lib/src/my_api.g.dart | 20 +- .../lib/src/my_central_controller.dart | 77 ++++---- bluetooth_low_energy_android/my_api.dart | 15 +- bluetooth_low_energy_android/pubspec.yaml | 4 +- bluetooth_low_energy_ios/CHANGELOG.md | 6 + .../ios/Classes/MyApi.g.swift | 43 +++-- .../ios/Classes/MyCentralController.swift | 176 ++++++++++-------- .../ios/bluetooth_low_energy.podspec | 0 .../ios/bluetooth_low_energy_ios.podspec | 23 --- .../lib/src/my_api.g.dart | 20 +- .../lib/src/my_central_controller.dart | 77 ++++---- bluetooth_low_energy_ios/my_api.dart | 15 +- bluetooth_low_energy_ios/pubspec.yaml | 4 +- bluetooth_low_energy_linux/CHANGELOG.md | 6 + .../lib/src/my_bluez.dart | 3 +- .../lib/src/my_central_controller.dart | 116 ++++++------ .../lib/src/my_event_args.dart | 9 + bluetooth_low_energy_linux/pubspec.yaml | 4 +- bluetooth_low_energy_macos/CHANGELOG.md | 6 + .../lib/src/my_api.g.dart | 20 +- .../lib/src/my_central_controller.dart | 77 ++++---- .../macos/Classes/MyApi.g.swift | 43 +++-- .../macos/Classes/MyCentralController.swift | 176 ++++++++++-------- .../macos/bluetooth_low_energy.podspec | 0 .../macos/bluetooth_low_energy_macos.podspec | 23 --- bluetooth_low_energy_macos/my_api.dart | 15 +- bluetooth_low_energy_macos/pubspec.yaml | 4 +- .../CHANGELOG.md | 6 + .../pubspec.yaml | 2 +- bluetooth_low_energy_windows/CHANGELOG.md | 6 + bluetooth_low_energy_windows/pubspec.yaml | 6 +- .../windows/CMakeLists.txt | 57 +++++- .../windows/bluetooth_low_energy_plugin.cpp | 0 .../windows/bluetooth_low_energy_plugin.h | 0 .../bluetooth_low_energy_plugin_c_api.cpp | 0 .../bluetooth_low_energy_windows_plugin.cpp | 59 ------ .../bluetooth_low_energy_windows_plugin.h | 32 ---- ...etooth_low_energy_windows_plugin_c_api.cpp | 12 -- .../bluetooth_low_energy_plugin_c_api.h | 0 ...luetooth_low_energy_windows_plugin_c_api.h | 23 --- .../test/bluetooth_low_energy_plugin_test.cpp | 0 61 files changed, 734 insertions(+), 1137 deletions(-) delete mode 100644 bluetooth_low_energy/ios/.gitignore delete mode 100644 bluetooth_low_energy/ios/Assets/.gitkeep delete mode 100644 bluetooth_low_energy/ios/Classes/BluetoothLowEnergyPlugin.swift delete mode 100644 bluetooth_low_energy/linux/CMakeLists.txt delete mode 100644 bluetooth_low_energy/linux/bluetooth_low_energy_plugin.cc delete mode 100644 bluetooth_low_energy/linux/bluetooth_low_energy_plugin_private.h delete mode 100644 bluetooth_low_energy/linux/include/bluetooth_low_energy/bluetooth_low_energy_plugin.h delete mode 100644 bluetooth_low_energy/linux/test/bluetooth_low_energy_plugin_test.cc delete mode 100644 bluetooth_low_energy/macos/Classes/BluetoothLowEnergyPlugin.swift delete mode 100644 bluetooth_low_energy/windows/.gitignore delete mode 100644 bluetooth_low_energy/windows/CMakeLists.txt rename {bluetooth_low_energy => bluetooth_low_energy_ios}/ios/bluetooth_low_energy.podspec (100%) delete mode 100644 bluetooth_low_energy_ios/ios/bluetooth_low_energy_ios.podspec create mode 100644 bluetooth_low_energy_linux/lib/src/my_event_args.dart rename {bluetooth_low_energy => bluetooth_low_energy_macos}/macos/bluetooth_low_energy.podspec (100%) delete mode 100644 bluetooth_low_energy_macos/macos/bluetooth_low_energy_macos.podspec rename {bluetooth_low_energy => bluetooth_low_energy_windows}/windows/bluetooth_low_energy_plugin.cpp (100%) rename {bluetooth_low_energy => bluetooth_low_energy_windows}/windows/bluetooth_low_energy_plugin.h (100%) rename {bluetooth_low_energy => bluetooth_low_energy_windows}/windows/bluetooth_low_energy_plugin_c_api.cpp (100%) delete mode 100644 bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin.cpp delete mode 100644 bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin.h delete mode 100644 bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin_c_api.cpp rename {bluetooth_low_energy => bluetooth_low_energy_windows}/windows/include/bluetooth_low_energy/bluetooth_low_energy_plugin_c_api.h (100%) delete mode 100644 bluetooth_low_energy_windows/windows/include/bluetooth_low_energy_windows/bluetooth_low_energy_windows_plugin_c_api.h rename {bluetooth_low_energy => bluetooth_low_energy_windows}/windows/test/bluetooth_low_energy_plugin_test.cpp (100%) diff --git a/bluetooth_low_energy/CHANGELOG.md b/bluetooth_low_energy/CHANGELOG.md index e252a4a..f461cce 100644 --- a/bluetooth_low_energy/CHANGELOG.md +++ b/bluetooth_low_energy/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.0.1 + +- Fix the issue that GATTs is cleared after peripheral disconnected on iOS and macOS. +- Fix the issue that create UUID form peripheral's address failed on Linux. +- Fix the issue that instance match failed on Linux. + ## 2.0.0 - Rewrite the whole project with federated plugins. diff --git a/bluetooth_low_energy/README.md b/bluetooth_low_energy/README.md index e95ee9c..16dc072 100644 --- a/bluetooth_low_energy/README.md +++ b/bluetooth_low_energy/README.md @@ -40,7 +40,7 @@ According to Apple's [documents](https://developer.apple.com/documentation/coreb ### Linux -Not tested yet, if you occured any problems, file an issue to let me know about it, i will fix it as soon as possible. +Not tested enough, if you occured any problems, file an issue to let me know about it, i will fix it as soon as possible. ### Windows diff --git a/bluetooth_low_energy/example/ios/Runner/Info.plist b/bluetooth_low_energy/example/ios/Runner/Info.plist index b1c75cf..099b7ea 100644 --- a/bluetooth_low_energy/example/ios/Runner/Info.plist +++ b/bluetooth_low_energy/example/ios/Runner/Info.plist @@ -27,7 +27,7 @@ LSRequiresIPhoneOS NSBluetoothAlwaysUsageDescription - Hello Bluetooth Low Energy! + Hello Bluetooth LowEnergy! UIApplicationSupportsIndirectInputEvents UILaunchStoryboardName diff --git a/bluetooth_low_energy/example/lib/main.dart b/bluetooth_low_energy/example/lib/main.dart index 9ffe287..b5617b6 100644 --- a/bluetooth_low_energy/example/lib/main.dart +++ b/bluetooth_low_energy/example/lib/main.dart @@ -162,9 +162,10 @@ class _HomeViewState extends State { return ValueListenableBuilder( valueListenable: discoveredEventArgs, builder: (context, discoveredEventArgs, child) { - final items = discoveredEventArgs - .where((eventArgs) => eventArgs.advertisement.name != null) - .toList(); + // final items = discoveredEventArgs + // .where((eventArgs) => eventArgs.advertisement.name != null) + // .toList(); + final items = discoveredEventArgs; return ListView.separated( itemBuilder: (context, i) { final theme = Theme.of(context); @@ -248,7 +249,7 @@ class _HomeViewState extends State { }, ); }, - title: Text(name ?? ''), + title: Text(name ?? 'N/A'), subtitle: Text( '$uuid', style: theme.textTheme.bodySmall, diff --git a/bluetooth_low_energy/example/pubspec.lock b/bluetooth_low_energy/example/pubspec.lock index af017ae..0cc4c43 100644 --- a/bluetooth_low_energy/example/pubspec.lock +++ b/bluetooth_low_energy/example/pubspec.lock @@ -23,55 +23,55 @@ packages: path: ".." relative: true source: path - version: "2.0.0" + version: "2.0.1" bluetooth_low_energy_android: dependency: transitive description: name: bluetooth_low_energy_android - sha256: f2a91728df49d52a77af9c8fb294a7afc173e2ce94abb6f9586949827b88a320 + sha256: e4a14243be6b4556836a734e53e813a1c5f4f6c8e380ca49ebf8d02e5b3f37dc url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" bluetooth_low_energy_ios: dependency: transitive description: name: bluetooth_low_energy_ios - sha256: bf940f40321d1c3284957dbf7ff15587b4851bd722858798d77314d8f188b94f + sha256: "38401d8e50d6f96b3e63f2c7e6fc32d6a1ae7d99dc60520fcb4162eb39ba2dd4" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" bluetooth_low_energy_linux: dependency: transitive description: name: bluetooth_low_energy_linux - sha256: ff162bbf375240a615ee3539484438742c3c334c5ac6750db27a1e458cce8135 + sha256: c88363e296ecb3a4b936e6d02f21214cf4e894d694c9996b523811b65e2d0eb0 url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" bluetooth_low_energy_macos: dependency: transitive description: name: bluetooth_low_energy_macos - sha256: "0e454bde70f8d26a78156a2ffc7193c174f7bd04f8ff52eabfd21385fdcb22f9" + sha256: b816568cc943d419bb395fbeb4b7aad66295c5e25e2f5b3e06532394dc27522e url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" bluetooth_low_energy_platform_interface: dependency: transitive description: name: bluetooth_low_energy_platform_interface - sha256: e07eb812e320cb167a2b9a59417fe1e632d23b031595dd8a9b72069243045900 + sha256: "090b642fa738c04e899c4f4a78e88fa43a7dfa7f5b99f1c882cadad10a68e8fb" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" bluetooth_low_energy_windows: dependency: transitive description: name: bluetooth_low_energy_windows - sha256: "6f28d9d7ce35e795207428f2c493a16759cbee34a74e9b254a29672dc8385205" + sha256: ddd66c36811ad3fd347efaaba132e7bb27cdc446afc3e8cd3880c5f26a0d3b54 url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" bluez: dependency: transitive description: diff --git a/bluetooth_low_energy/ios/.gitignore b/bluetooth_low_energy/ios/.gitignore deleted file mode 100644 index 0c88507..0000000 --- a/bluetooth_low_energy/ios/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -.idea/ -.vagrant/ -.sconsign.dblite -.svn/ - -.DS_Store -*.swp -profile - -DerivedData/ -build/ -GeneratedPluginRegistrant.h -GeneratedPluginRegistrant.m - -.generated/ - -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 - -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 - -xcuserdata - -*.moved-aside - -*.pyc -*sync/ -Icon? -.tags* - -/Flutter/Generated.xcconfig -/Flutter/ephemeral/ -/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/bluetooth_low_energy/ios/Assets/.gitkeep b/bluetooth_low_energy/ios/Assets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/bluetooth_low_energy/ios/Classes/BluetoothLowEnergyPlugin.swift b/bluetooth_low_energy/ios/Classes/BluetoothLowEnergyPlugin.swift deleted file mode 100644 index dbbf6d0..0000000 --- a/bluetooth_low_energy/ios/Classes/BluetoothLowEnergyPlugin.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Flutter -import UIKit - -public class BluetoothLowEnergyPlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "bluetooth_low_energy", binaryMessenger: registrar.messenger()) - let instance = BluetoothLowEnergyPlugin() - registrar.addMethodCallDelegate(instance, channel: channel) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - switch call.method { - case "getPlatformVersion": - result("iOS " + UIDevice.current.systemVersion) - default: - result(FlutterMethodNotImplemented) - } - } -} diff --git a/bluetooth_low_energy/linux/CMakeLists.txt b/bluetooth_low_energy/linux/CMakeLists.txt deleted file mode 100644 index 1230a30..0000000 --- a/bluetooth_low_energy/linux/CMakeLists.txt +++ /dev/null @@ -1,94 +0,0 @@ -# The Flutter tooling requires that developers have CMake 3.10 or later -# installed. You should not increase this version, as doing so will cause -# the plugin to fail to compile for some customers of the plugin. -cmake_minimum_required(VERSION 3.10) - -# Project-level configuration. -set(PROJECT_NAME "bluetooth_low_energy") -project(${PROJECT_NAME} LANGUAGES CXX) - -# This value is used when generating builds using this plugin, so it must -# not be changed. -set(PLUGIN_NAME "bluetooth_low_energy_plugin") - -# Any new source files that you add to the plugin should be added here. -list(APPEND PLUGIN_SOURCES - "bluetooth_low_energy_plugin.cc" -) - -# Define the plugin library target. Its name must not be changed (see comment -# on PLUGIN_NAME above). -add_library(${PLUGIN_NAME} SHARED - ${PLUGIN_SOURCES} -) - -# Apply a standard set of build settings that are configured in the -# application-level CMakeLists.txt. This can be removed for plugins that want -# full control over build settings. -apply_standard_settings(${PLUGIN_NAME}) - -# Symbols are hidden by default to reduce the chance of accidental conflicts -# between plugins. This should not be removed; any symbols that should be -# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. -set_target_properties(${PLUGIN_NAME} PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) - -# Source include directories and library dependencies. Add any plugin-specific -# dependencies here. -target_include_directories(${PLUGIN_NAME} INTERFACE - "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) -target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) - -# List of absolute paths to libraries that should be bundled with the plugin. -# This list could contain prebuilt libraries, or libraries created by an -# external build triggered from this build file. -set(bluetooth_low_energy_bundled_libraries - "" - PARENT_SCOPE -) - -# === Tests === -# These unit tests can be run from a terminal after building the example. - -# Only enable test builds when building the example (which sets this variable) -# so that plugin clients aren't building the tests. -if (${include_${PROJECT_NAME}_tests}) -if(${CMAKE_VERSION} VERSION_LESS "3.11.0") -message("Unit tests require CMake 3.11.0 or later") -else() -set(TEST_RUNNER "${PROJECT_NAME}_test") -enable_testing() - -# Add the Google Test dependency. -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/release-1.11.0.zip -) -# Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -# Disable install commands for gtest so it doesn't end up in the bundle. -set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE) - -FetchContent_MakeAvailable(googletest) - -# The plugin's exported API is not very useful for unit testing, so build the -# sources directly into the test binary rather than using the shared library. -add_executable(${TEST_RUNNER} - test/bluetooth_low_energy_plugin_test.cc - ${PLUGIN_SOURCES} -) -apply_standard_settings(${TEST_RUNNER}) -target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") -target_link_libraries(${TEST_RUNNER} PRIVATE flutter) -target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::GTK) -target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock) - -# Enable automatic test discovery. -include(GoogleTest) -gtest_discover_tests(${TEST_RUNNER}) - -endif() # CMake version check -endif() # include_${PROJECT_NAME}_tests \ No newline at end of file diff --git a/bluetooth_low_energy/linux/bluetooth_low_energy_plugin.cc b/bluetooth_low_energy/linux/bluetooth_low_energy_plugin.cc deleted file mode 100644 index b4a8c4a..0000000 --- a/bluetooth_low_energy/linux/bluetooth_low_energy_plugin.cc +++ /dev/null @@ -1,76 +0,0 @@ -#include "include/bluetooth_low_energy/bluetooth_low_energy_plugin.h" - -#include -#include -#include - -#include - -#include "bluetooth_low_energy_plugin_private.h" - -#define BLUETOOTH_LOW_ENERGY_PLUGIN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), bluetooth_low_energy_plugin_get_type(), \ - BluetoothLowEnergyPlugin)) - -struct _BluetoothLowEnergyPlugin { - GObject parent_instance; -}; - -G_DEFINE_TYPE(BluetoothLowEnergyPlugin, bluetooth_low_energy_plugin, g_object_get_type()) - -// Called when a method call is received from Flutter. -static void bluetooth_low_energy_plugin_handle_method_call( - BluetoothLowEnergyPlugin* self, - FlMethodCall* method_call) { - g_autoptr(FlMethodResponse) response = nullptr; - - const gchar* method = fl_method_call_get_name(method_call); - - if (strcmp(method, "getPlatformVersion") == 0) { - response = get_platform_version(); - } else { - response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); - } - - fl_method_call_respond(method_call, response, nullptr); -} - -FlMethodResponse* get_platform_version() { - struct utsname uname_data = {}; - uname(&uname_data); - g_autofree gchar *version = g_strdup_printf("Linux %s", uname_data.version); - g_autoptr(FlValue) result = fl_value_new_string(version); - return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); -} - -static void bluetooth_low_energy_plugin_dispose(GObject* object) { - G_OBJECT_CLASS(bluetooth_low_energy_plugin_parent_class)->dispose(object); -} - -static void bluetooth_low_energy_plugin_class_init(BluetoothLowEnergyPluginClass* klass) { - G_OBJECT_CLASS(klass)->dispose = bluetooth_low_energy_plugin_dispose; -} - -static void bluetooth_low_energy_plugin_init(BluetoothLowEnergyPlugin* self) {} - -static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call, - gpointer user_data) { - BluetoothLowEnergyPlugin* plugin = BLUETOOTH_LOW_ENERGY_PLUGIN(user_data); - bluetooth_low_energy_plugin_handle_method_call(plugin, method_call); -} - -void bluetooth_low_energy_plugin_register_with_registrar(FlPluginRegistrar* registrar) { - BluetoothLowEnergyPlugin* plugin = BLUETOOTH_LOW_ENERGY_PLUGIN( - g_object_new(bluetooth_low_energy_plugin_get_type(), nullptr)); - - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(FlMethodChannel) channel = - fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), - "bluetooth_low_energy", - FL_METHOD_CODEC(codec)); - fl_method_channel_set_method_call_handler(channel, method_call_cb, - g_object_ref(plugin), - g_object_unref); - - g_object_unref(plugin); -} diff --git a/bluetooth_low_energy/linux/bluetooth_low_energy_plugin_private.h b/bluetooth_low_energy/linux/bluetooth_low_energy_plugin_private.h deleted file mode 100644 index ed272ce..0000000 --- a/bluetooth_low_energy/linux/bluetooth_low_energy_plugin_private.h +++ /dev/null @@ -1,10 +0,0 @@ -#include - -#include "include/bluetooth_low_energy/bluetooth_low_energy_plugin.h" - -// This file exposes some plugin internals for unit testing. See -// https://github.com/flutter/flutter/issues/88724 for current limitations -// in the unit-testable API. - -// Handles the getPlatformVersion method call. -FlMethodResponse *get_platform_version(); diff --git a/bluetooth_low_energy/linux/include/bluetooth_low_energy/bluetooth_low_energy_plugin.h b/bluetooth_low_energy/linux/include/bluetooth_low_energy/bluetooth_low_energy_plugin.h deleted file mode 100644 index 55ef70c..0000000 --- a/bluetooth_low_energy/linux/include/bluetooth_low_energy/bluetooth_low_energy_plugin.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_PLUGIN_H_ -#define FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_PLUGIN_H_ - -#include - -G_BEGIN_DECLS - -#ifdef FLUTTER_PLUGIN_IMPL -#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) -#else -#define FLUTTER_PLUGIN_EXPORT -#endif - -typedef struct _BluetoothLowEnergyPlugin BluetoothLowEnergyPlugin; -typedef struct { - GObjectClass parent_class; -} BluetoothLowEnergyPluginClass; - -FLUTTER_PLUGIN_EXPORT GType bluetooth_low_energy_plugin_get_type(); - -FLUTTER_PLUGIN_EXPORT void bluetooth_low_energy_plugin_register_with_registrar( - FlPluginRegistrar* registrar); - -G_END_DECLS - -#endif // FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_PLUGIN_H_ diff --git a/bluetooth_low_energy/linux/test/bluetooth_low_energy_plugin_test.cc b/bluetooth_low_energy/linux/test/bluetooth_low_energy_plugin_test.cc deleted file mode 100644 index 82160d1..0000000 --- a/bluetooth_low_energy/linux/test/bluetooth_low_energy_plugin_test.cc +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include - -#include "include/bluetooth_low_energy/bluetooth_low_energy_plugin.h" -#include "bluetooth_low_energy_plugin_private.h" - -// This demonstrates a simple unit test of the C portion of this plugin's -// implementation. -// -// Once you have built the plugin's example app, you can run these tests -// from the command line. For instance, for a plugin called my_plugin -// built for x64 debug, run: -// $ build/linux/x64/debug/plugins/my_plugin/my_plugin_test - -namespace bluetooth_low_energy { -namespace test { - -TEST(BluetoothLowEnergyPlugin, GetPlatformVersion) { - g_autoptr(FlMethodResponse) response = get_platform_version(); - ASSERT_NE(response, nullptr); - ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - FlValue* result = fl_method_success_response_get_result( - FL_METHOD_SUCCESS_RESPONSE(response)); - ASSERT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_STRING); - // The full string varies, so just validate that it has the right format. - EXPECT_THAT(fl_value_get_string(result), testing::StartsWith("Linux ")); -} - -} // namespace test -} // namespace bluetooth_low_energy diff --git a/bluetooth_low_energy/macos/Classes/BluetoothLowEnergyPlugin.swift b/bluetooth_low_energy/macos/Classes/BluetoothLowEnergyPlugin.swift deleted file mode 100644 index c836587..0000000 --- a/bluetooth_low_energy/macos/Classes/BluetoothLowEnergyPlugin.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Cocoa -import FlutterMacOS - -public class BluetoothLowEnergyPlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "bluetooth_low_energy", binaryMessenger: registrar.messenger) - let instance = BluetoothLowEnergyPlugin() - registrar.addMethodCallDelegate(instance, channel: channel) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - switch call.method { - case "getPlatformVersion": - result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString) - default: - result(FlutterMethodNotImplemented) - } - } -} diff --git a/bluetooth_low_energy/pubspec.yaml b/bluetooth_low_energy/pubspec.yaml index 80fedec..96354dd 100644 --- a/bluetooth_low_energy/pubspec.yaml +++ b/bluetooth_low_energy/pubspec.yaml @@ -1,6 +1,6 @@ name: bluetooth_low_energy description: A Flutter plugin for controlling the bluetooth low energy. -version: 2.0.0 +version: 2.0.1 homepage: https://github.com/yanshouwang/bluetooth_low_energy environment: @@ -10,12 +10,12 @@ environment: dependencies: flutter: sdk: flutter - bluetooth_low_energy_platform_interface: ^2.0.0 - bluetooth_low_energy_android: ^2.0.0 - bluetooth_low_energy_ios: ^2.0.0 - bluetooth_low_energy_macos: ^2.0.0 - bluetooth_low_energy_linux: ^2.0.0 - bluetooth_low_energy_windows: ^2.0.0 + bluetooth_low_energy_platform_interface: ^2.0.1 + bluetooth_low_energy_android: ^2.0.1 + bluetooth_low_energy_ios: ^2.0.1 + bluetooth_low_energy_macos: ^2.0.1 + bluetooth_low_energy_linux: ^2.0.1 + bluetooth_low_energy_windows: ^2.0.1 dev_dependencies: flutter_test: diff --git a/bluetooth_low_energy/windows/.gitignore b/bluetooth_low_energy/windows/.gitignore deleted file mode 100644 index b3eb2be..0000000 --- a/bluetooth_low_energy/windows/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -flutter/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ diff --git a/bluetooth_low_energy/windows/CMakeLists.txt b/bluetooth_low_energy/windows/CMakeLists.txt deleted file mode 100644 index 13df83f..0000000 --- a/bluetooth_low_energy/windows/CMakeLists.txt +++ /dev/null @@ -1,96 +0,0 @@ -# The Flutter tooling requires that developers have a version of Visual Studio -# installed that includes CMake 3.14 or later. You should not increase this -# version, as doing so will cause the plugin to fail to compile for some -# customers of the plugin. -cmake_minimum_required(VERSION 3.14) - -# Project-level configuration. -set(PROJECT_NAME "bluetooth_low_energy") -project(${PROJECT_NAME} LANGUAGES CXX) - -# This value is used when generating builds using this plugin, so it must -# not be changed -set(PLUGIN_NAME "bluetooth_low_energy_plugin") - -# Any new source files that you add to the plugin should be added here. -list(APPEND PLUGIN_SOURCES - "bluetooth_low_energy_plugin.cpp" - "bluetooth_low_energy_plugin.h" -) - -# Define the plugin library target. Its name must not be changed (see comment -# on PLUGIN_NAME above). -add_library(${PLUGIN_NAME} SHARED - "include/bluetooth_low_energy/bluetooth_low_energy_plugin_c_api.h" - "bluetooth_low_energy_plugin_c_api.cpp" - ${PLUGIN_SOURCES} -) - -# Apply a standard set of build settings that are configured in the -# application-level CMakeLists.txt. This can be removed for plugins that want -# full control over build settings. -apply_standard_settings(${PLUGIN_NAME}) - -# Symbols are hidden by default to reduce the chance of accidental conflicts -# between plugins. This should not be removed; any symbols that should be -# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. -set_target_properties(${PLUGIN_NAME} PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) - -# Source include directories and library dependencies. Add any plugin-specific -# dependencies here. -target_include_directories(${PLUGIN_NAME} INTERFACE - "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) - -# List of absolute paths to libraries that should be bundled with the plugin. -# This list could contain prebuilt libraries, or libraries created by an -# external build triggered from this build file. -set(bluetooth_low_energy_bundled_libraries - "" - PARENT_SCOPE -) - -# === Tests === -# These unit tests can be run from a terminal after building the example, or -# from Visual Studio after opening the generated solution file. - -# Only enable test builds when building the example (which sets this variable) -# so that plugin clients aren't building the tests. -if (${include_${PROJECT_NAME}_tests}) -set(TEST_RUNNER "${PROJECT_NAME}_test") -enable_testing() - -# Add the Google Test dependency. -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/release-1.11.0.zip -) -# Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -# Disable install commands for gtest so it doesn't end up in the bundle. -set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE) -FetchContent_MakeAvailable(googletest) - -# The plugin's C API is not very useful for unit testing, so build the sources -# directly into the test binary rather than using the DLL. -add_executable(${TEST_RUNNER} - test/bluetooth_low_energy_plugin_test.cpp - ${PLUGIN_SOURCES} -) -apply_standard_settings(${TEST_RUNNER}) -target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") -target_link_libraries(${TEST_RUNNER} PRIVATE flutter_wrapper_plugin) -target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock) -# flutter_wrapper_plugin has link dependencies on the Flutter DLL. -add_custom_command(TARGET ${TEST_RUNNER} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${FLUTTER_LIBRARY}" $ -) - -# Enable automatic test discovery. -include(GoogleTest) -gtest_discover_tests(${TEST_RUNNER}) -endif() diff --git a/bluetooth_low_energy_android/CHANGELOG.md b/bluetooth_low_energy_android/CHANGELOG.md index e510273..367297e 100644 --- a/bluetooth_low_energy_android/CHANGELOG.md +++ b/bluetooth_low_energy_android/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.0.1 + +- Fix the issue that GATTs is cleared after peripheral disconnected on iOS and macOS. +- Fix the issue that create UUID form peripheral's address failed on Linux. +- Fix the issue that instance match failed on Linux. + ## 2.0.0 - Rewrite the whole project with federated plugins. diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy/MyApi.g.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy/MyApi.g.kt index b2d1ebd..3e9a484 100644 --- a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy/MyApi.g.kt +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy/MyApi.g.kt @@ -282,11 +282,11 @@ interface MyCentralControllerHostApi { fun getServices(myPeripheralKey: Long): List fun getCharacteristics(myServiceKey: Long): List fun getDescriptors(myCharacteristicKey: Long): List - fun readCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, callback: (Result) -> Unit) - fun writeCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, value: ByteArray, myTypeNumber: Long, callback: (Result) -> Unit) - fun notifyCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, state: Boolean, callback: (Result) -> Unit) - fun readDescriptor(myPeripheralKey: Long, myDescriptorKey: Long, callback: (Result) -> Unit) - fun writeDescriptor(myPeripheralKey: Long, myDescriptorKey: Long, value: ByteArray, callback: (Result) -> Unit) + fun readCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, callback: (Result) -> Unit) + fun writeCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, value: ByteArray, myTypeNumber: Long, callback: (Result) -> Unit) + fun notifyCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, state: Boolean, callback: (Result) -> Unit) + fun readDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, callback: (Result) -> Unit) + fun writeDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, value: ByteArray, callback: (Result) -> Unit) companion object { /** The codec used by MyCentralControllerHostApi. */ @@ -482,8 +482,9 @@ interface MyCentralControllerHostApi { channel.setMessageHandler { message, reply -> val args = message as List val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - val myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } - api.readCharacteristic(myPeripheralKeyArg, myCharacteristicKeyArg) { result: Result -> + val myServiceKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val myCharacteristicKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long } + api.readCharacteristic(myPeripheralKeyArg, myServiceKeyArg, myCharacteristicKeyArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -503,10 +504,11 @@ interface MyCentralControllerHostApi { channel.setMessageHandler { message, reply -> val args = message as List val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - val myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val valueArg = args[2] as ByteArray - val myTypeNumberArg = args[3].let { if (it is Int) it.toLong() else it as Long } - api.writeCharacteristic(myPeripheralKeyArg, myCharacteristicKeyArg, valueArg, myTypeNumberArg) { result: Result -> + val myServiceKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val myCharacteristicKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long } + val valueArg = args[3] as ByteArray + val myTypeNumberArg = args[4].let { if (it is Int) it.toLong() else it as Long } + api.writeCharacteristic(myPeripheralKeyArg, myServiceKeyArg, myCharacteristicKeyArg, valueArg, myTypeNumberArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -525,9 +527,10 @@ interface MyCentralControllerHostApi { channel.setMessageHandler { message, reply -> val args = message as List val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - val myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val stateArg = args[2] as Boolean - api.notifyCharacteristic(myPeripheralKeyArg, myCharacteristicKeyArg, stateArg) { result: Result -> + val myServiceKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val myCharacteristicKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long } + val stateArg = args[3] as Boolean + api.notifyCharacteristic(myPeripheralKeyArg, myServiceKeyArg, myCharacteristicKeyArg, stateArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -546,8 +549,9 @@ interface MyCentralControllerHostApi { channel.setMessageHandler { message, reply -> val args = message as List val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - val myDescriptorKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } - api.readDescriptor(myPeripheralKeyArg, myDescriptorKeyArg) { result: Result -> + val myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val myDescriptorKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long } + api.readDescriptor(myPeripheralKeyArg, myCharacteristicKeyArg, myDescriptorKeyArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -567,9 +571,10 @@ interface MyCentralControllerHostApi { channel.setMessageHandler { message, reply -> val args = message as List val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - val myDescriptorKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val valueArg = args[2] as ByteArray - api.writeDescriptor(myPeripheralKeyArg, myDescriptorKeyArg, valueArg) { result: Result -> + val myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val myDescriptorKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long } + val valueArg = args[3] as ByteArray + api.writeDescriptor(myPeripheralKeyArg, myCharacteristicKeyArg, myDescriptorKeyArg, valueArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy/MyCentralController.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy/MyCentralController.kt index 3dc32e7..0f9129f 100644 --- a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy/MyCentralController.kt +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy/MyCentralController.kt @@ -27,7 +27,8 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM companion object { // const val DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xff.toByte() private const val REQUEST_CODE = 443 -// private val UUID_HEART_RATE_MEASUREMENT = UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb") + + // private val UUID_HEART_RATE_MEASUREMENT = UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb") private val UUID_CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") } @@ -44,11 +45,11 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM private val myScanCallback = MyScanCallback(this) private val myGattCallback = MyBluetoothGattCallback(this, executor) - private val devices = mutableMapOf() - private val gatts = mutableMapOf() - private val services = mutableMapOf() - private val characteristics = mutableMapOf() - private val descriptors = mutableMapOf() + private val cachedDevices = mutableMapOf() + private val cachedGATTs = mutableMapOf() + private val cachedServices = mutableMapOf>() + private val cachedCharacteristics = mutableMapOf>() + private val cachedDescriptors = mutableMapOf>() private var registered = false private var discovering = false @@ -95,14 +96,14 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM if (discovering) { stopDiscovery() } - for (gatt in gatts.values) { + for (gatt in cachedGATTs.values) { gatt.disconnect() } - devices.clear() - gatts.clear() - services.clear() - characteristics.clear() - descriptors.clear() + cachedDevices.clear() + cachedGATTs.clear() + cachedServices.clear() + cachedCharacteristics.clear() + cachedDescriptors.clear() } private fun register() { @@ -148,9 +149,9 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM if (unfinishedCallback != null) { throw IllegalStateException() } - val device = devices[deviceKey] as BluetoothDevice + val device = cachedDevices[deviceKey] as BluetoothDevice val autoConnect = false - gatts[deviceKey] = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + cachedGATTs[deviceKey] = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val transport = BluetoothDevice.TRANSPORT_LE device.connectGatt(context, autoConnect, myGattCallback, transport) } else { @@ -169,7 +170,7 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM if (unfinishedCallback != null) { throw IllegalStateException() } - val gatt = gatts[deviceKey] as BluetoothGatt + val gatt = cachedGATTs[deviceKey] as BluetoothGatt gatt.disconnect() disconnectCallbacks[deviceKey] = callback } catch (e: Throwable) { @@ -184,7 +185,7 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM if (unfinishedCallback != null) { throw IllegalStateException() } - val gatt = gatts[deviceKey] as BluetoothGatt + val gatt = cachedGATTs[deviceKey] as BluetoothGatt val discovering = gatt.discoverServices() if (!discovering) { throw IllegalStateException() @@ -197,53 +198,35 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM override fun getServices(myPeripheralKey: Long): List { val deviceKey = myPeripheralKey.toInt() - val gatt = gatts[deviceKey] as BluetoothGatt - val services = gatt.services - return services.map { service -> - val serviceKey = service.hashCode() - if (this.services[serviceKey] == null) { - this.services[serviceKey] = service - } - return@map service.toMyArgs() - } + val services = cachedServices[deviceKey] ?: throw IllegalStateException() + return services.values.map { service -> service.toMyArgs() } } override fun getCharacteristics(myServiceKey: Long): List { val serviceKey = myServiceKey.toInt() - val service = services[serviceKey] as BluetoothGattService - val characteristics = service.characteristics - return characteristics.map { characteristic -> - val characteristicKey = characteristic.hashCode() - if (this.characteristics[characteristicKey] == null) { - this.characteristics[characteristicKey] = characteristic - } - return@map characteristic.toMyArgs() - } + val characteristics = cachedCharacteristics[serviceKey] ?: throw IllegalStateException() + return characteristics.values.map { characteristic -> characteristic.toMyArgs() } } override fun getDescriptors(myCharacteristicKey: Long): List { val characteristicKey = myCharacteristicKey.toInt() - val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic - val descriptors = characteristic.descriptors - return descriptors.map { descriptor -> - val descriptorKey = descriptor.hashCode() - if (this.descriptors[descriptorKey] == null) { - this.descriptors[descriptorKey] = descriptor - } - return@map descriptor.toMyArgs() - } + val descriptors = cachedDescriptors[characteristicKey] ?: throw IllegalStateException() + return descriptors.values.map { descriptor -> descriptor.toMyArgs() } } - override fun readCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, callback: (Result) -> Unit) { + override fun readCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, callback: (Result) -> Unit) { try { val deviceKey = myPeripheralKey.toInt() + val gatt = cachedGATTs[deviceKey] as BluetoothGatt + val serviceKey = myServiceKey.toInt() + val characteristics = cachedCharacteristics[serviceKey] + ?: throw IllegalArgumentException() val characteristicKey = myCharacteristicKey.toInt() + val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic val unfinishedCallback = readCharacteristicCallbacks[characteristicKey] if (unfinishedCallback != null) { throw IllegalStateException() } - val gatt = gatts[deviceKey] as BluetoothGatt - val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic val reading = gatt.readCharacteristic(characteristic) if (!reading) { throw IllegalStateException() @@ -254,16 +237,19 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM } } - override fun writeCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, value: ByteArray, myTypeNumber: Long, callback: (Result) -> Unit) { + override fun writeCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, value: ByteArray, myTypeNumber: Long, callback: (Result) -> Unit) { try { val deviceKey = myPeripheralKey.toInt() + val gatt = cachedGATTs[deviceKey] as BluetoothGatt + val serviceKey = myServiceKey.toInt() + val characteristics = cachedCharacteristics[serviceKey] + ?: throw IllegalArgumentException() val characteristicKey = myCharacteristicKey.toInt() + val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic val unfinishedCallback = writeCharacteristicCallbacks[characteristicKey] if (unfinishedCallback != null) { throw IllegalStateException() } - val gatt = gatts[deviceKey] as BluetoothGatt - val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic val myTypeArgs = myTypeNumber.toMyGattCharacteristicTypeArgs() val writeType = myTypeArgs.toType() characteristic.value = value @@ -278,11 +264,14 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM } } - override fun notifyCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, state: Boolean, callback: (Result) -> Unit) { + override fun notifyCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, state: Boolean, callback: (Result) -> Unit) { try { val deviceKey = myPeripheralKey.toInt() + val gatt = cachedGATTs[deviceKey] as BluetoothGatt + val serviceKey = myServiceKey.toInt() + val characteristics = cachedCharacteristics[serviceKey] + ?: throw IllegalArgumentException() val characteristicKey = myCharacteristicKey.toInt() - val gatt = gatts[deviceKey] as BluetoothGatt val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic val notifying = gatt.setCharacteristicNotification(characteristic, state) if (!notifying) { @@ -314,16 +303,19 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM } } - override fun readDescriptor(myPeripheralKey: Long, myDescriptorKey: Long, callback: (Result) -> Unit) { + override fun readDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, callback: (Result) -> Unit) { try { val deviceKey = myPeripheralKey.toInt() + val gatt = cachedGATTs[deviceKey] as BluetoothGatt + val characteristicKey = myCharacteristicKey.toInt() + val descriptors = cachedDescriptors[characteristicKey] + ?: throw IllegalArgumentException() val descriptorKey = myDescriptorKey.toInt() + val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor val unfinishedCallback = readDescriptorCallbacks[descriptorKey] if (unfinishedCallback != null) { throw IllegalStateException() } - val gatt = gatts[deviceKey] as BluetoothGatt - val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor val reading = gatt.readDescriptor(descriptor) if (!reading) { throw IllegalStateException() @@ -334,16 +326,19 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM } } - override fun writeDescriptor(myPeripheralKey: Long, myDescriptorKey: Long, value: ByteArray, callback: (Result) -> Unit) { + override fun writeDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, value: ByteArray, callback: (Result) -> Unit) { try { val deviceKey = myPeripheralKey.toInt() + val gatt = cachedGATTs[deviceKey] as BluetoothGatt + val characteristicKey = myCharacteristicKey.toInt() + val descriptors = cachedDescriptors[characteristicKey] + ?: throw IllegalArgumentException() val descriptorKey = myDescriptorKey.toInt() + val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor val unfinishedCallback = writeDescriptorCallbacks[descriptorKey] if (unfinishedCallback != null) { throw IllegalStateException() } - val gatt = gatts[deviceKey] as BluetoothGatt - val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor descriptor.value = value val writing = gatt.writeDescriptor(descriptor) if (!writing) { @@ -407,9 +402,7 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM fun onScanResult(result: ScanResult) { val device = result.device val deviceKey = device.hashCode() - if (devices[deviceKey] == null) { - devices[deviceKey] = device - } + cachedDevices[deviceKey] = device val myPeripheralArgs = device.toMyArgs() val rssi = result.rssi.toLong() val myAdvertisementArgs = result.myAdvertisementArgs @@ -422,27 +415,28 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM val myPeripheralKey = deviceKey.toLong() if (newState != BluetoothProfile.STATE_CONNECTED) { gatt.close() - gatts.remove(deviceKey) + cachedGATTs.remove(deviceKey) val error = IllegalStateException("GATT is disconnected with status: $status") val discoverGattCallback = discoverGattCallbacks.remove(deviceKey) if (discoverGattCallback != null) { discoverGattCallback(Result.failure(error)) } - for (service in gatt.services) { - for (characteristic in service.characteristics) { - val characteristicKey = characteristic.hashCode() - val readCharacteristicCallback = readCharacteristicCallbacks.remove(characteristicKey) - val writeCharacteristicCallback = writeCharacteristicCallbacks.remove(characteristicKey) + val services = cachedServices[deviceKey] ?: emptyMap() + for (service in services) { + val characteristics = cachedCharacteristics[service.key] ?: emptyMap() + for (characteristic in characteristics) { + val readCharacteristicCallback = readCharacteristicCallbacks.remove(characteristic.key) + val writeCharacteristicCallback = writeCharacteristicCallbacks.remove(characteristic.key) if (readCharacteristicCallback != null) { readCharacteristicCallback(Result.failure(error)) } if (writeCharacteristicCallback != null) { writeCharacteristicCallback(Result.failure(error)) } - for (descriptor in characteristic.descriptors) { - val descriptorKey = descriptor.hashCode() - val readDescriptorCallback = readDescriptorCallbacks.remove(descriptorKey) - val writeDescriptorCallback = writeDescriptorCallbacks.remove(descriptorKey) + val descriptors = cachedDescriptors[characteristic.key] ?: emptyMap() + for (descriptor in descriptors) { + val readDescriptorCallback = readDescriptorCallbacks.remove(descriptor.key) + val writeDescriptorCallback = writeDescriptorCallbacks.remove(descriptor.key) if (readDescriptorCallback != null) { readDescriptorCallback(Result.failure(error)) } @@ -490,6 +484,24 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM val deviceKey = device.hashCode() val callback = discoverGattCallbacks.remove(deviceKey) ?: return if (status == BluetoothGatt.GATT_SUCCESS) { + val cachedServices = mutableMapOf() + for (service in gatt.services) { + val serviceKey = service.hashCode() + cachedServices[serviceKey] = service + val cachedCharacteristics = mutableMapOf() + for (characteristic in service.characteristics) { + val characteristicKey = characteristic.hashCode() + cachedCharacteristics[characteristicKey] = characteristic + val cachedDescriptors = mutableMapOf() + for (descriptor in characteristic.descriptors) { + val descriptorKey = descriptor.hashCode() + cachedDescriptors[descriptorKey] = descriptor + } + this.cachedDescriptors[characteristicKey] = cachedDescriptors + } + this.cachedCharacteristics[serviceKey] = cachedCharacteristics + } + this.cachedServices[deviceKey] = cachedServices callback(Result.success(Unit)) } else { val error = IllegalStateException("Discover GATT failed with status: $status") diff --git a/bluetooth_low_energy_android/lib/src/my_api.g.dart b/bluetooth_low_energy_android/lib/src/my_api.g.dart index 63d43d9..03e0d35 100644 --- a/bluetooth_low_energy_android/lib/src/my_api.g.dart +++ b/bluetooth_low_energy_android/lib/src/my_api.g.dart @@ -483,12 +483,12 @@ class MyCentralControllerHostApi { } } - Future readCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey) async { + Future readCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey]) as List?; + await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -510,12 +510,12 @@ class MyCentralControllerHostApi { } } - Future writeCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async { + Future writeCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List?; + await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -532,12 +532,12 @@ class MyCentralControllerHostApi { } } - Future notifyCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, bool arg_state) async { + Future notifyCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, bool arg_state) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.notifyCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_state]) as List?; + await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_state]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -554,12 +554,12 @@ class MyCentralControllerHostApi { } } - Future readDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey) async { + Future readDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readDescriptor', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myDescriptorKey]) as List?; + await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -581,12 +581,12 @@ class MyCentralControllerHostApi { } } - Future writeDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey, Uint8List arg_value) async { + Future writeDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey, Uint8List arg_value) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeDescriptor', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myDescriptorKey, arg_value]) as List?; + await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey, arg_value]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', diff --git a/bluetooth_low_energy_android/lib/src/my_central_controller.dart b/bluetooth_low_energy_android/lib/src/my_central_controller.dart index ba60583..0cc0b51 100644 --- a/bluetooth_low_energy_android/lib/src/my_central_controller.dart +++ b/bluetooth_low_energy_android/lib/src/my_central_controller.dart @@ -126,18 +126,16 @@ class MyCentralController extends CentralController await _throwWithoutState(CentralState.poweredOn); final myPeripheral = peripheral as MyPeripheral; final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode); - return myServiceArgses - .cast() - .map( - (myServiceArgs) => _myServices.putIfAbsent( - myServiceArgs.key, - () => MyGattService.fromMyArgs( - myPeripheral, - myServiceArgs, - ), - ), - ) - .toList(); + return myServiceArgses.cast().map( + (myServiceArgs) { + final myService = MyGattService.fromMyArgs( + myPeripheral, + myServiceArgs, + ); + _myServices[myService.hashCode] = myService; + return myService; + }, + ).toList(); } @override @@ -149,18 +147,16 @@ class MyCentralController extends CentralController final myCharactersiticArgses = await _myApi.getCharacteristics( myService.hashCode, ); - return myCharactersiticArgses - .cast() - .map( - (myCharacteristicArgs) => _myCharacteristics.putIfAbsent( - myCharacteristicArgs.key, - () => MyGattCharacteristic.fromMyArgs( - myService, - myCharacteristicArgs, - ), - ), - ) - .toList(); + return myCharactersiticArgses.cast().map( + (myCharacteristicArgs) { + final myCharacteristic = MyGattCharacteristic.fromMyArgs( + myService, + myCharacteristicArgs, + ); + _myCharacteristics[myCharacteristic.hashCode] = myCharacteristic; + return myCharacteristic; + }, + ).toList(); } @override @@ -172,18 +168,16 @@ class MyCentralController extends CentralController final myDescriptorArgses = await _myApi.getDescriptors( myCharacteristic.hashCode, ); - return myDescriptorArgses - .cast() - .map( - (myDescriptorArgs) => _myDescriptors.putIfAbsent( - myDescriptorArgs.key, - () => MyGattDescriptor.fromMyArgs( - myCharacteristic, - myDescriptorArgs, - ), - ), - ) - .toList(); + return myDescriptorArgses.cast().map( + (myDescriptorArgs) { + final myDescriptor = MyGattDescriptor.fromMyArgs( + myCharacteristic, + myDescriptorArgs, + ); + _myDescriptors[myDescriptor.hashCode] = myDescriptor; + return myDescriptor; + }, + ).toList(); } @override @@ -195,6 +189,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; final value = await _myApi.readCharacteristic( myPeripheral.hashCode, + myService.hashCode, myCharacteristic.hashCode, ); return value; @@ -214,6 +209,7 @@ class MyCentralController extends CentralController final typeNumber = typeArgs.index; await _myApi.writeCharacteristic( myPeripheral.hashCode, + myService.hashCode, myCharacteristic.hashCode, value, typeNumber, @@ -231,6 +227,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; await _myApi.notifyCharacteristic( myPeripheral.hashCode, + myService.hashCode, myCharacteristic.hashCode, state, ); @@ -245,6 +242,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; final value = await _myApi.readDescriptor( myPeripheral.hashCode, + myCharacteristic.hashCode, myDescriptor.hashCode, ); return value; @@ -262,6 +260,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; await _myApi.writeDescriptor( myPeripheral.hashCode, + myCharacteristic.hashCode, myDescriptor.hashCode, value, ); @@ -285,10 +284,8 @@ class MyCentralController extends CentralController int rssi, MyAdvertisementArgs myAdvertisementArgs, ) { - final myPeripheral = _myPeripherals.putIfAbsent( - myPeripheralArgs.key, - () => MyPeripheral.fromMyArgs(myPeripheralArgs), - ); + final myPeripheral = MyPeripheral.fromMyArgs(myPeripheralArgs); + _myPeripherals[myPeripheral.hashCode] = myPeripheral; final advertisement = myAdvertisementArgs.toAdvertisement(); final eventArgs = CentralDiscoveredEventArgs( myPeripheral, diff --git a/bluetooth_low_energy_android/my_api.dart b/bluetooth_low_energy_android/my_api.dart index 6a42a40..be0c80e 100644 --- a/bluetooth_low_energy_android/my_api.dart +++ b/bluetooth_low_energy_android/my_api.dart @@ -29,10 +29,15 @@ abstract class MyCentralControllerHostApi { List getCharacteristics(int myServiceKey); List getDescriptors(int myCharacteristicKey); @async - Uint8List readCharacteristic(int myPeripheralKey, int myCharacteristicKey); + Uint8List readCharacteristic( + int myPeripheralKey, + int myServiceKey, + int myCharacteristicKey, + ); @async void writeCharacteristic( int myPeripheralKey, + int myServiceKey, int myCharacteristicKey, Uint8List value, int myTypeNumber, @@ -40,14 +45,20 @@ abstract class MyCentralControllerHostApi { @async void notifyCharacteristic( int myPeripheralKey, + int myServiceKey, int myCharacteristicKey, bool state, ); @async - Uint8List readDescriptor(int myPeripheralKey, int myDescriptorKey); + Uint8List readDescriptor( + int myPeripheralKey, + int myCharacteristicKey, + int myDescriptorKey, + ); @async void writeDescriptor( int myPeripheralKey, + int myCharacteristicKey, int myDescriptorKey, Uint8List value, ); diff --git a/bluetooth_low_energy_android/pubspec.yaml b/bluetooth_low_energy_android/pubspec.yaml index 065b533..40d1a75 100644 --- a/bluetooth_low_energy_android/pubspec.yaml +++ b/bluetooth_low_energy_android/pubspec.yaml @@ -1,6 +1,6 @@ name: bluetooth_low_energy_android description: Android implementation of the bluetooth_low_energy plugin. -version: 2.0.0 +version: 2.0.1 homepage: https://github.com/yanshouwang/bluetooth_low_energy environment: @@ -10,7 +10,7 @@ environment: dependencies: flutter: sdk: flutter - bluetooth_low_energy_platform_interface: ^2.0.0 + bluetooth_low_energy_platform_interface: ^2.0.1 dev_dependencies: flutter_test: diff --git a/bluetooth_low_energy_ios/CHANGELOG.md b/bluetooth_low_energy_ios/CHANGELOG.md index e510273..367297e 100644 --- a/bluetooth_low_energy_ios/CHANGELOG.md +++ b/bluetooth_low_energy_ios/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.0.1 + +- Fix the issue that GATTs is cleared after peripheral disconnected on iOS and macOS. +- Fix the issue that create UUID form peripheral's address failed on Linux. +- Fix the issue that instance match failed on Linux. + ## 2.0.0 - Rewrite the whole project with federated plugins. diff --git a/bluetooth_low_energy_ios/ios/Classes/MyApi.g.swift b/bluetooth_low_energy_ios/ios/Classes/MyApi.g.swift index e5754e5..f3b4093 100644 --- a/bluetooth_low_energy_ios/ios/Classes/MyApi.g.swift +++ b/bluetooth_low_energy_ios/ios/Classes/MyApi.g.swift @@ -258,11 +258,11 @@ protocol MyCentralControllerHostApi { func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] - func readCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result) -> Void) - func writeCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result) -> Void) - func notifyCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result) -> Void) - func readDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result) -> Void) - func writeDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result) -> Void) + func readCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result) -> Void) + func writeCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result) -> Void) + func notifyCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result) -> Void) + func readDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result) -> Void) + func writeDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result) -> Void) } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. @@ -426,8 +426,9 @@ class MyCentralControllerHostApiSetup { readCharacteristicChannel.setMessageHandler { message, reply in let args = message as! [Any?] let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - api.readCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg) { result in + let myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + api.readCharacteristic(myPeripheralKey: myPeripheralKeyArg, myServiceKey: myServiceKeyArg, myCharacteristicKey: myCharacteristicKeyArg) { result in switch result { case .success(let res): reply(wrapResult(res)) @@ -444,10 +445,11 @@ class MyCentralControllerHostApiSetup { writeCharacteristicChannel.setMessageHandler { message, reply in let args = message as! [Any?] let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - let valueArg = args[2] as! FlutterStandardTypedData - let myTypeNumberArg = args[3] is Int64 ? args[3] as! Int64 : Int64(args[3] as! Int32) - api.writeCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, value: valueArg, myTypeNumber: myTypeNumberArg) { result in + let myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + let valueArg = args[3] as! FlutterStandardTypedData + let myTypeNumberArg = args[4] is Int64 ? args[4] as! Int64 : Int64(args[4] as! Int32) + api.writeCharacteristic(myPeripheralKey: myPeripheralKeyArg, myServiceKey: myServiceKeyArg, myCharacteristicKey: myCharacteristicKeyArg, value: valueArg, myTypeNumber: myTypeNumberArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -464,9 +466,10 @@ class MyCentralControllerHostApiSetup { notifyCharacteristicChannel.setMessageHandler { message, reply in let args = message as! [Any?] let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - let stateArg = args[2] as! Bool - api.notifyCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, state: stateArg) { result in + let myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + let stateArg = args[3] as! Bool + api.notifyCharacteristic(myPeripheralKey: myPeripheralKeyArg, myServiceKey: myServiceKeyArg, myCharacteristicKey: myCharacteristicKeyArg, state: stateArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -483,8 +486,9 @@ class MyCentralControllerHostApiSetup { readDescriptorChannel.setMessageHandler { message, reply in let args = message as! [Any?] let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myDescriptorKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - api.readDescriptor(myPeripheralKey: myPeripheralKeyArg, myDescriptorKey: myDescriptorKeyArg) { result in + let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let myDescriptorKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + api.readDescriptor(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, myDescriptorKey: myDescriptorKeyArg) { result in switch result { case .success(let res): reply(wrapResult(res)) @@ -501,9 +505,10 @@ class MyCentralControllerHostApiSetup { writeDescriptorChannel.setMessageHandler { message, reply in let args = message as! [Any?] let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myDescriptorKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - let valueArg = args[2] as! FlutterStandardTypedData - api.writeDescriptor(myPeripheralKey: myPeripheralKeyArg, myDescriptorKey: myDescriptorKeyArg, value: valueArg) { result in + let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let myDescriptorKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + let valueArg = args[3] as! FlutterStandardTypedData + api.writeDescriptor(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, myDescriptorKey: myDescriptorKeyArg, value: valueArg) { result in switch result { case .success: reply(wrapResult(nil)) diff --git a/bluetooth_low_energy_ios/ios/Classes/MyCentralController.swift b/bluetooth_low_energy_ios/ios/Classes/MyCentralController.swift index 8aa06a1..13533ee 100644 --- a/bluetooth_low_energy_ios/ios/Classes/MyCentralController.swift +++ b/bluetooth_low_energy_ios/ios/Classes/MyCentralController.swift @@ -19,10 +19,10 @@ class MyCentralController: MyCentralControllerHostApi { private lazy var myPeripheralDelegate = MyPeripheralDelegate(self) private let centralManager = CBCentralManager() - private var peripherals = [Int: CBPeripheral]() - private var services = [Int: CBService]() - private var characteristics = [Int: CBCharacteristic]() - private var descriptors = [Int: CBDescriptor]() + private var cachedPeripherals = [Int: CBPeripheral]() + private var cachedServices = [Int: [Int: CBService]]() + private var cachedCharacteristics = [Int: [Int: CBCharacteristic]]() + private var cachedDescriptors = [Int: [Int: CBDescriptor]]() var setUpCompletion: ((Result) -> Void)? var connectCompletions = [Int: (Result) -> Void]() @@ -61,16 +61,16 @@ class MyCentralController: MyCentralControllerHostApi { if(centralManager.isScanning) { centralManager.stopScan() } - for peripheral in peripherals.values { + for peripheral in cachedPeripherals.values { peripheral.delegate = nil if peripheral.state != .disconnected { centralManager.cancelPeripheralConnection(peripheral) } } - peripherals.removeAll() - services.removeAll() - characteristics.removeAll() - descriptors.removeAll() + cachedPeripherals.removeAll() + cachedServices.removeAll() + cachedCharacteristics.removeAll() + cachedDescriptors.removeAll() } func startDiscovery() throws { @@ -89,7 +89,7 @@ class MyCentralController: MyCentralControllerHostApi { if unfinishedCompletion != nil { throw MyError.illegalState } - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { throw MyError.illegalArgument } centralManager.connect(peripheral) @@ -106,7 +106,7 @@ class MyCentralController: MyCentralControllerHostApi { if unfinishedCompletion != nil { throw MyError.illegalState } - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { throw MyError.illegalArgument } centralManager.cancelPeripheralConnection(peripheral) @@ -123,7 +123,7 @@ class MyCentralController: MyCentralControllerHostApi { if unfinishedCompletion != nil { throw MyError.illegalState } - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { throw MyError.illegalArgument } peripheral.discoverServices(nil) @@ -135,53 +135,42 @@ class MyCentralController: MyCentralControllerHostApi { func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let services = cachedServices[peripheralKey] else { throw MyError.illegalArgument } - let services = peripheral.services ?? [] - return services.map { service in - let serviceKey = service.hash - if self.services[serviceKey] == nil { - self.services[serviceKey] = service - } + return services.map { (key, service) in return service.toMyArgs() } } func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] { let serviceKey = Int(myServiceKey) - guard let service = services[serviceKey] else { + guard let characteristics = cachedCharacteristics[serviceKey] else { throw MyError.illegalArgument } - let characteristics = service.characteristics ?? [] - return characteristics.map { characteristic in - let characteristicKey = characteristic.hash - if self.characteristics[characteristicKey] == nil { - self.characteristics[characteristicKey] = characteristic - } + return characteristics.map { (key, characteristic) in return characteristic.toMyArgs() } } func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] { let characteristicKey = Int(myCharacteristicKey) - guard let characteristic = characteristics[characteristicKey] else { + guard let descriptors = cachedDescriptors[characteristicKey] else { throw MyError.illegalArgument } - let descritors = characteristic.descriptors ?? [] - return descritors.map { descriptor in - let descriptorKey = descriptor.hash - if self.descriptors[descriptorKey] == nil { - self.descriptors[descriptorKey] = descriptor - } + return descriptors.map { (key, descriptor) in return descriptor.toMyArgs() } } - func readCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result) -> Void) { + func readCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result) -> Void) { do { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { + throw MyError.illegalArgument + } + let serviceKey = Int(myServiceKey) + guard let characteristics = cachedCharacteristics[serviceKey] else { throw MyError.illegalArgument } let characteristicKey = Int(myCharacteristicKey) @@ -199,10 +188,14 @@ class MyCentralController: MyCentralControllerHostApi { } } - func writeCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result) -> Void) { + func writeCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result) -> Void) { do { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { + throw MyError.illegalArgument + } + let serviceKey = Int(myServiceKey) + guard let characteristics = cachedCharacteristics[serviceKey] else { throw MyError.illegalArgument } let characteristicKey = Int(myCharacteristicKey) @@ -226,10 +219,14 @@ class MyCentralController: MyCentralControllerHostApi { } } - func notifyCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result) -> Void) { + func notifyCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result) -> Void) { do { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { + throw MyError.illegalArgument + } + let serviceKey = Int(myServiceKey) + guard let characteristics = cachedCharacteristics[serviceKey] else { throw MyError.illegalArgument } let characteristicKey = Int(myCharacteristicKey) @@ -247,10 +244,14 @@ class MyCentralController: MyCentralControllerHostApi { } } - func readDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result) -> Void) { + func readDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result) -> Void) { do { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { + throw MyError.illegalArgument + } + let characteristicKey = Int(myCharacteristicKey) + guard let descriptors = cachedDescriptors[characteristicKey] else { throw MyError.illegalArgument } let descriptorKey = Int(myDescriptorKey) @@ -268,10 +269,14 @@ class MyCentralController: MyCentralControllerHostApi { } } - func writeDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result) -> Void) { + func writeDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result) -> Void) { do { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { + throw MyError.illegalArgument + } + let characteristicKey = Int(myCharacteristicKey) + guard let descriptors = cachedDescriptors[characteristicKey] else { throw MyError.illegalArgument } let descriptorKey = Int(myDescriptorKey) @@ -307,9 +312,9 @@ class MyCentralController: MyCentralControllerHostApi { func didDiscover(_ peripheral: CBPeripheral, _ advertisementData: [String : Any], _ rssiNumber: NSNumber) { let peripheralKey = peripheral.hash - if peripherals[peripheralKey] == nil { + if cachedPeripherals[peripheralKey] == nil { peripheral.delegate = myPeripheralDelegate - peripherals[peripheralKey] = peripheral + cachedPeripherals[peripheralKey] = peripheral } let myPeripheralArgs = peripheral.toMyArgs() let rssi = rssiNumber.int64Value @@ -368,26 +373,24 @@ class MyCentralController: MyCentralControllerHostApi { let myPeripheralKey = Int64(peripheralKey) let discoverGattCompletion = discoverGattCompletions.removeValue(forKey: peripheralKey) if discoverGattCompletion != nil { - discoverGattCompletion!(.failure(error ?? MyError.illegalState)) + didDiscoverGATT(peripheral, error ?? MyError.unknown) } - let services = peripheral.services ?? [] + let services = cachedServices[peripheralKey] ?? [:] for service in services { - let characteristics = service.characteristics ?? [] + let characteristics = cachedCharacteristics[service.key] ?? [:] for characteristic in characteristics { - let characteristicKey = characteristic.hash - let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristicKey) - let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristicKey) + let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristic.key) + let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristic.key) if readCharacteristicCompletion != nil { readCharacteristicCompletion!(.failure(MyError.illegalState)) } if writeCharacteristicCompletion != nil { writeCharacteristicCompletion!(.failure(MyError.illegalState)) } - let descriptors = characteristic.descriptors ?? [] + let descriptors = cachedDescriptors[characteristic.key] ?? [:] for descriptor in descriptors { - let descriptorKey = descriptor.hash - let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptorKey) - let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptorKey) + let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptor.key) + let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptor.key) if readDescriptorCompletion != nil { readDescriptorCompletion!(.failure(MyError.illegalState)) } @@ -411,37 +414,28 @@ class MyCentralController: MyCentralControllerHostApi { func didDiscoverServices(_ peripheral: CBPeripheral, _ error: Error?) { let peripheralKey = peripheral.hash - guard let completion = discoverGattCompletions[peripheralKey] else { - return - } if error == nil { var services = peripheral.services ?? [] if services.isEmpty { - discoverGattCompletions.removeValue(forKey: peripheralKey) - completion(.success(())) + didDiscoverGATT(peripheral, error) } else { let service = services.removeFirst() unfinishedServices[peripheralKey] = services peripheral.discoverCharacteristics(nil, for: service) } } else { - discoverGattCompletions.removeValue(forKey: peripheralKey) - completion(.failure(error!)) + didDiscoverGATT(peripheral, error) } } func didDiscoverCharacteristics(_ peripheral: CBPeripheral, _ service: CBService, _ error: Error?) { let peripheralKey = peripheral.hash - guard let completion = discoverGattCompletions[peripheralKey] else { - return - } if error == nil { var characteristics = service.characteristics ?? [] if characteristics.isEmpty { var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? [] if services.isEmpty { - discoverGattCompletions.removeValue(forKey: peripheralKey) - completion(.success(())) + didDiscoverGATT(peripheral, error) } else { let service = services.removeFirst() unfinishedServices[peripheralKey] = services @@ -453,24 +447,18 @@ class MyCentralController: MyCentralControllerHostApi { peripheral.discoverDescriptors(for: characteristic) } } else { - discoverGattCompletions.removeValue(forKey: peripheralKey) - unfinishedServices.removeValue(forKey: peripheralKey) - completion(.failure(error!)) + didDiscoverGATT(peripheral, error) } } func didDiscoverDescriptors(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic, _ error: Error?) { let peripheralKey = peripheral.hash - guard let completion = discoverGattCompletions[peripheralKey] else { - return - } if error == nil { var characteristics = unfinishedCharacteristics.removeValue(forKey: peripheralKey) ?? [] if (characteristics.isEmpty) { var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? [] if services.isEmpty { - discoverGattCompletions.removeValue(forKey: peripheralKey) - completion(.success(())) + didDiscoverGATT(peripheral, error) } else { let service = services.removeFirst() unfinishedServices[peripheralKey] = services @@ -482,9 +470,41 @@ class MyCentralController: MyCentralControllerHostApi { peripheral.discoverDescriptors(for: characteristic) } } else { - discoverGattCompletions.removeValue(forKey: peripheralKey) - unfinishedServices.removeValue(forKey: peripheralKey) - unfinishedCharacteristics.removeValue(forKey: peripheralKey) + didDiscoverGATT(peripheral, error) + } + } + + private func didDiscoverGATT(_ peripheral: CBPeripheral, _ error: Error?) { + let peripheralKey = peripheral.hash + unfinishedServices.removeValue(forKey: peripheralKey) + unfinishedCharacteristics.removeValue(forKey: peripheralKey) + guard let completion = discoverGattCompletions.removeValue(forKey: peripheralKey) else { + return + } + if error == nil { + let services = peripheral.services ?? [] + var cachedServices = [Int: CBService]() + for service in services { + let serviceKey = service.hash + cachedServices[serviceKey] = service + let characteristics = service.characteristics ?? [] + var cachedCharacteristics = [Int: CBCharacteristic]() + for characteristic in characteristics { + let characteristicKey = characteristic.hash + cachedCharacteristics[characteristicKey] = characteristic + let descriptors = characteristic.descriptors ?? [] + var cachedDescriptors = [Int: CBDescriptor]() + for descriptor in descriptors { + let descriptorKey = descriptor.hash + cachedDescriptors[descriptorKey] = descriptor + } + self.cachedDescriptors[characteristicKey] = cachedDescriptors + } + self.cachedCharacteristics[serviceKey] = cachedCharacteristics + } + self.cachedServices[peripheralKey] = cachedServices + completion(.success(())) + } else { completion(.failure(error!)) } } diff --git a/bluetooth_low_energy/ios/bluetooth_low_energy.podspec b/bluetooth_low_energy_ios/ios/bluetooth_low_energy.podspec similarity index 100% rename from bluetooth_low_energy/ios/bluetooth_low_energy.podspec rename to bluetooth_low_energy_ios/ios/bluetooth_low_energy.podspec diff --git a/bluetooth_low_energy_ios/ios/bluetooth_low_energy_ios.podspec b/bluetooth_low_energy_ios/ios/bluetooth_low_energy_ios.podspec deleted file mode 100644 index 398e1e1..0000000 --- a/bluetooth_low_energy_ios/ios/bluetooth_low_energy_ios.podspec +++ /dev/null @@ -1,23 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint bluetooth_low_energy_ios.podspec` to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'bluetooth_low_energy_ios' - s.version = '0.0.1' - s.summary = 'A new Flutter plugin project.' - s.description = <<-DESC -A new Flutter plugin project. - DESC - s.homepage = 'http://example.com' - s.license = { :file => '../LICENSE' } - s.author = { 'Your Company' => 'email@example.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.dependency 'Flutter' - s.platform = :ios, '9.0' - - # Flutter.framework does not contain a i386 slice. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } - s.swift_version = '5.0' -end diff --git a/bluetooth_low_energy_ios/lib/src/my_api.g.dart b/bluetooth_low_energy_ios/lib/src/my_api.g.dart index a0717a6..0603491 100644 --- a/bluetooth_low_energy_ios/lib/src/my_api.g.dart +++ b/bluetooth_low_energy_ios/lib/src/my_api.g.dart @@ -483,12 +483,12 @@ class MyCentralControllerHostApi { } } - Future readCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey) async { + Future readCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.readCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey]) as List?; + await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -510,12 +510,12 @@ class MyCentralControllerHostApi { } } - Future writeCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async { + Future writeCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.writeCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List?; + await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -532,12 +532,12 @@ class MyCentralControllerHostApi { } } - Future notifyCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, bool arg_state) async { + Future notifyCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, bool arg_state) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.notifyCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_state]) as List?; + await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_state]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -554,12 +554,12 @@ class MyCentralControllerHostApi { } } - Future readDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey) async { + Future readDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.readDescriptor', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myDescriptorKey]) as List?; + await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -581,12 +581,12 @@ class MyCentralControllerHostApi { } } - Future writeDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey, Uint8List arg_value) async { + Future writeDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey, Uint8List arg_value) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.writeDescriptor', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myDescriptorKey, arg_value]) as List?; + await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey, arg_value]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', diff --git a/bluetooth_low_energy_ios/lib/src/my_central_controller.dart b/bluetooth_low_energy_ios/lib/src/my_central_controller.dart index 6444c3a..b717308 100644 --- a/bluetooth_low_energy_ios/lib/src/my_central_controller.dart +++ b/bluetooth_low_energy_ios/lib/src/my_central_controller.dart @@ -126,18 +126,16 @@ class MyCentralController extends CentralController await _throwWithoutState(CentralState.poweredOn); final myPeripheral = peripheral as MyPeripheral; final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode); - return myServiceArgses - .cast() - .map( - (myServiceArgs) => _myServices.putIfAbsent( - myServiceArgs.key, - () => MyGattService.fromMyArgs( - myPeripheral, - myServiceArgs, - ), - ), - ) - .toList(); + return myServiceArgses.cast().map( + (myServiceArgs) { + final myService = MyGattService.fromMyArgs( + myPeripheral, + myServiceArgs, + ); + _myServices[myService.hashCode] = myService; + return myService; + }, + ).toList(); } @override @@ -149,18 +147,16 @@ class MyCentralController extends CentralController final myCharactersiticArgses = await _myApi.getCharacteristics( myService.hashCode, ); - return myCharactersiticArgses - .cast() - .map( - (myCharacteristicArgs) => _myCharacteristics.putIfAbsent( - myCharacteristicArgs.key, - () => MyGattCharacteristic.fromMyArgs( - myService, - myCharacteristicArgs, - ), - ), - ) - .toList(); + return myCharactersiticArgses.cast().map( + (myCharacteristicArgs) { + final myCharacteristic = MyGattCharacteristic.fromMyArgs( + myService, + myCharacteristicArgs, + ); + _myCharacteristics[myCharacteristic.hashCode] = myCharacteristic; + return myCharacteristic; + }, + ).toList(); } @override @@ -172,18 +168,16 @@ class MyCentralController extends CentralController final myDescriptorArgses = await _myApi.getDescriptors( myCharacteristic.hashCode, ); - return myDescriptorArgses - .cast() - .map( - (myDescriptorArgs) => _myDescriptors.putIfAbsent( - myDescriptorArgs.key, - () => MyGattDescriptor.fromMyArgs( - myCharacteristic, - myDescriptorArgs, - ), - ), - ) - .toList(); + return myDescriptorArgses.cast().map( + (myDescriptorArgs) { + final myDescriptor = MyGattDescriptor.fromMyArgs( + myCharacteristic, + myDescriptorArgs, + ); + _myDescriptors[myDescriptor.hashCode] = myDescriptor; + return myDescriptor; + }, + ).toList(); } @override @@ -196,6 +190,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; final value = await _myApi.readCharacteristic( myPeripheral.hashCode, + myService.hashCode, myCharacteristic.hashCode, ); return value; @@ -215,6 +210,7 @@ class MyCentralController extends CentralController final typeNumber = typeArgs.index; await _myApi.writeCharacteristic( myPeripheral.hashCode, + myService.hashCode, myCharacteristic.hashCode, value, typeNumber, @@ -232,6 +228,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; await _myApi.notifyCharacteristic( myPeripheral.hashCode, + myService.hashCode, myCharacteristic.hashCode, state, ); @@ -246,6 +243,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; final value = await _myApi.readDescriptor( myPeripheral.hashCode, + myCharacteristic.hashCode, myDescriptor.hashCode, ); return value; @@ -263,6 +261,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; await _myApi.writeDescriptor( myPeripheral.hashCode, + myCharacteristic.hashCode, myDescriptor.hashCode, value, ); @@ -286,10 +285,8 @@ class MyCentralController extends CentralController int rssi, MyAdvertisementArgs myAdvertisementArgs, ) { - final myPeripheral = _myPeripherals.putIfAbsent( - myPeripheralArgs.key, - () => MyPeripheral.fromMyArgs(myPeripheralArgs), - ); + final myPeripheral = MyPeripheral.fromMyArgs(myPeripheralArgs); + _myPeripherals[myPeripheral.hashCode] = myPeripheral; final advertisement = myAdvertisementArgs.toAdvertisement(); final eventArgs = CentralDiscoveredEventArgs( myPeripheral, diff --git a/bluetooth_low_energy_ios/my_api.dart b/bluetooth_low_energy_ios/my_api.dart index ad48f71..b54cbb1 100644 --- a/bluetooth_low_energy_ios/my_api.dart +++ b/bluetooth_low_energy_ios/my_api.dart @@ -25,10 +25,15 @@ abstract class MyCentralControllerHostApi { List getCharacteristics(int myServiceKey); List getDescriptors(int myCharacteristicKey); @async - Uint8List readCharacteristic(int myPeripheralKey, int myCharacteristicKey); + Uint8List readCharacteristic( + int myPeripheralKey, + int myServiceKey, + int myCharacteristicKey, + ); @async void writeCharacteristic( int myPeripheralKey, + int myServiceKey, int myCharacteristicKey, Uint8List value, int myTypeNumber, @@ -36,14 +41,20 @@ abstract class MyCentralControllerHostApi { @async void notifyCharacteristic( int myPeripheralKey, + int myServiceKey, int myCharacteristicKey, bool state, ); @async - Uint8List readDescriptor(int myPeripheralKey, int myDescriptorKey); + Uint8List readDescriptor( + int myPeripheralKey, + int myCharacteristicKey, + int myDescriptorKey, + ); @async void writeDescriptor( int myPeripheralKey, + int myCharacteristicKey, int myDescriptorKey, Uint8List value, ); diff --git a/bluetooth_low_energy_ios/pubspec.yaml b/bluetooth_low_energy_ios/pubspec.yaml index 7439b3b..11c4e22 100644 --- a/bluetooth_low_energy_ios/pubspec.yaml +++ b/bluetooth_low_energy_ios/pubspec.yaml @@ -1,6 +1,6 @@ name: bluetooth_low_energy_ios description: iOS implementation of the bluetooth_low_energy plugin. -version: 2.0.0 +version: 2.0.1 homepage: https://github.com/yanshouwang/bluetooth_low_energy environment: @@ -10,7 +10,7 @@ environment: dependencies: flutter: sdk: flutter - bluetooth_low_energy_platform_interface: ^2.0.0 + bluetooth_low_energy_platform_interface: ^2.0.1 dev_dependencies: flutter_test: diff --git a/bluetooth_low_energy_linux/CHANGELOG.md b/bluetooth_low_energy_linux/CHANGELOG.md index e510273..367297e 100644 --- a/bluetooth_low_energy_linux/CHANGELOG.md +++ b/bluetooth_low_energy_linux/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.0.1 + +- Fix the issue that GATTs is cleared after peripheral disconnected on iOS and macOS. +- Fix the issue that create UUID form peripheral's address failed on Linux. +- Fix the issue that instance match failed on Linux. + ## 2.0.0 - Rewrite the whole project with federated plugins. diff --git a/bluetooth_low_energy_linux/lib/src/my_bluez.dart b/bluetooth_low_energy_linux/lib/src/my_bluez.dart index 30de865..a277292 100644 --- a/bluetooth_low_energy_linux/lib/src/my_bluez.dart +++ b/bluetooth_low_energy_linux/lib/src/my_bluez.dart @@ -13,10 +13,11 @@ extension MyBlueZDevice on BlueZDevice { BlueZUUID get uuid { final node = address.replaceAll(':', ''); // We don't know the timestamp of the bluetooth device, use nil UUID as prefix. - return BlueZUUID.fromString("00000000-0000-0000-$node"); + return BlueZUUID.fromString("00000000-0000-0000-0000-$node"); } Advertisement get advertisement { + final name = this.name.isNotEmpty ? this.name : null; final manufacturerSpecificData = manufacturerData.map((key, value) { final id = key.id; final data = Uint8List.fromList(value); diff --git a/bluetooth_low_energy_linux/lib/src/my_central_controller.dart b/bluetooth_low_energy_linux/lib/src/my_central_controller.dart index d71f663..5ca28f3 100644 --- a/bluetooth_low_energy_linux/lib/src/my_central_controller.dart +++ b/bluetooth_low_energy_linux/lib/src/my_central_controller.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:typed_data'; +import 'package:bluetooth_low_energy_linux/src/my_event_args.dart'; import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; import 'package:bluez/bluez.dart'; @@ -17,7 +18,7 @@ class MyCentralController extends CentralController { _discoveredController = StreamController.broadcast(), _peripheralStateChangedController = StreamController.broadcast(), _characteristicValueChangedController = StreamController.broadcast(), - _servicesResolvedController = StreamController.broadcast(), + _myPeripheralDiscoveredController = StreamController.broadcast(), _devicePropertiesChangedSubscriptions = {}, _characteristicPropertiesChangedSubscriptions = {}, _myPeripherals = {}, @@ -33,15 +34,16 @@ class MyCentralController extends CentralController { _peripheralStateChangedController; final StreamController _characteristicValueChangedController; - final StreamController _servicesResolvedController; + final StreamController + _myPeripheralDiscoveredController; final Map>> _devicePropertiesChangedSubscriptions; final Map>> _characteristicPropertiesChangedSubscriptions; final Map _myPeripherals; - final Map _myServices; - final Map _myCharacteristics; - final Map _myDescriptors; + final Map> _myServices; + final Map> _myCharacteristics; + final Map> _myDescriptors; BlueZAdapter get _adapter => _client.adapters.first; CentralState _state; @@ -61,7 +63,8 @@ class MyCentralController extends CentralController { Stream get characteristicValueChanged => _characteristicValueChangedController.stream; - Stream get _servicesResolved => _servicesResolvedController.stream; + Stream get _myPeripheralDiscovered => + _myPeripheralDiscoveredController.stream; late StreamSubscription> _adapterPropertiesChangedSubscription; late StreamSubscription _deviceAddedSubscription; @@ -91,7 +94,7 @@ class MyCentralController extends CentralController { return; } for (var device in _client.devices) { - if (device.adapter != _adapter) { + if (device.adapter.address != _adapter.address) { continue; } _beginDevicePropertiesChangedListener(device); @@ -120,7 +123,7 @@ class MyCentralController extends CentralController { _myCharacteristics.clear(); _myDescriptors.clear(); for (var device in _client.devices) { - if (device.adapter != _adapter) { + if (device.adapter.address != _adapter.address) { continue; } _endDevicePropertiesChangedListener(device); @@ -171,8 +174,8 @@ class MyCentralController extends CentralController { if (device.servicesResolved) { return; } - await _servicesResolved.firstWhere( - (hashCode) => hashCode == peripheral.hashCode, + await _myPeripheralDiscovered.firstWhere( + (eventArgs) => eventArgs.myPeripheral == myPeripheral, ); } @@ -180,15 +183,11 @@ class MyCentralController extends CentralController { Future> getServices(Peripheral peripheral) async { await _throwWithoutState(CentralState.poweredOn); final myPeripheral = peripheral as MyPeripheral; - final blueZDevice = myPeripheral.device; - return blueZDevice.gattServices - .map( - (service) => _myServices.putIfAbsent( - service.hashCode, - () => MyGattService(service), - ), - ) - .toList(); + final myServices = _myServices[myPeripheral.hashCode]; + if (myServices == null) { + throw ArgumentError(); + } + return myServices.values.toList(); } @override @@ -197,15 +196,11 @@ class MyCentralController extends CentralController { ) async { await _throwWithoutState(CentralState.poweredOn); final myService = service as MyGattService; - final blueZService = myService.service; - return blueZService.characteristics - .map( - (characteristic) => _myCharacteristics.putIfAbsent( - characteristic.hashCode, - () => MyGattCharacteristic(characteristic), - ), - ) - .toList(); + final myCharacteristics = _myCharacteristics[myService.hashCode]; + if (myCharacteristics == null) { + throw ArgumentError(); + } + return myCharacteristics.values.toList(); } @override @@ -214,15 +209,11 @@ class MyCentralController extends CentralController { ) async { await _throwWithoutState(CentralState.poweredOn); final myCharacteristic = characteristic as MyGattCharacteristic; - final blueZCharacteristic = myCharacteristic.characteristic; - return blueZCharacteristic.descriptors - .map( - (descriptor) => _myDescriptors.putIfAbsent( - descriptor.hashCode, - () => MyGattDescriptor(descriptor), - ), - ) - .toList(); + final myDescriptors = _myDescriptors[myCharacteristic.hashCode]; + if (myDescriptors == null) { + throw ArgumentError(); + } + return myDescriptors.values.toList(); } @override @@ -305,7 +296,7 @@ class MyCentralController extends CentralController { } void _onDeviceAdded(BlueZDevice device) { - if (device.adapter != _adapter) { + if (device.adapter.address != _adapter.address) { return; } _onDiscovered(device); @@ -313,17 +304,15 @@ class MyCentralController extends CentralController { } void _onDeviceRemoved(BlueZDevice device) { - if (device.adapter != _adapter) { + if (device.adapter.address != _adapter.address) { return; } _endDevicePropertiesChangedListener(device); } void _onDiscovered(BlueZDevice device) { - final myPeripheral = _myPeripherals.putIfAbsent( - device.hashCode, - () => MyPeripheral(device), - ); + final myPeripheral = MyPeripheral(device); + _myPeripherals[myPeripheral.hashCode] = myPeripheral; final rssi = device.rssi; final advertisement = device.advertisement; final eventArgs = CentralDiscoveredEventArgs( @@ -335,11 +324,6 @@ class MyCentralController extends CentralController { } void _beginDevicePropertiesChangedListener(BlueZDevice device) { - for (var service in device.gattServices) { - for (var characteristic in service.characteristics) { - _beginCharacteristicPropertiesChangedListener(characteristic); - } - } final subscription = device.propertiesChanged.listen((properties) { for (var property in properties) { switch (property) { @@ -360,12 +344,33 @@ class MyCentralController extends CentralController { break; case 'ServicesResolved': if (device.servicesResolved) { + final myPeripheral = + _myPeripherals[device.hashCode] as MyPeripheral; + final myServices = {}; for (var service in device.gattServices) { + final myService = MyGattService(service); + myServices[myService.hashCode] = myService; + final myCharacteristics = {}; for (var characteristic in service.characteristics) { - _beginCharacteristicPropertiesChangedListener(characteristic); + final myCharacteristic = MyGattCharacteristic(characteristic); + myCharacteristics[myCharacteristic.hashCode] = + myCharacteristic; + _beginCharacteristicPropertiesChangedListener( + service, + characteristic, + ); + final myDescriptors = {}; + for (var descriptor in characteristic.descriptors) { + final myDescriptor = MyGattDescriptor(descriptor); + myDescriptors[myDescriptor.hashCode] = myDescriptor; + } + _myDescriptors[myCharacteristic.hashCode] = myDescriptors; } + _myCharacteristics[myService.hashCode] = myCharacteristics; } - _servicesResolvedController.add(device.hashCode); + _myServices[myPeripheral.hashCode] = myServices; + final eventArgs = MyPeripheralDiscoveredEventArgs(myPeripheral); + _myPeripheralDiscoveredController.add(eventArgs); } break; default: @@ -389,16 +394,19 @@ class MyCentralController extends CentralController { } void _beginCharacteristicPropertiesChangedListener( + BlueZGattService service, BlueZGattCharacteristic characteristic, ) { final subscription = characteristic.propertiesChanged.listen((properties) { for (var property in properties) { switch (property) { case 'Value': - final instance = _myCharacteristics[characteristic.hashCode]; - final myCharacteristic = instance is MyGattCharacteristic - ? instance - : MyGattCharacteristic(characteristic); + final myCharacteristics = _myCharacteristics[service.hashCode]; + if (myCharacteristics == null) { + throw ArgumentError(); + } + final myCharacteristic = myCharacteristics[characteristic.hashCode] + as MyGattCharacteristic; final value = Uint8List.fromList(characteristic.value); final eventArgs = GattCharacteristicValueChangedEventArgs( myCharacteristic, diff --git a/bluetooth_low_energy_linux/lib/src/my_event_args.dart b/bluetooth_low_energy_linux/lib/src/my_event_args.dart new file mode 100644 index 0000000..31e8141 --- /dev/null +++ b/bluetooth_low_energy_linux/lib/src/my_event_args.dart @@ -0,0 +1,9 @@ +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_peripheral.dart'; + +class MyPeripheralDiscoveredEventArgs extends EventArgs { + final MyPeripheral myPeripheral; + + MyPeripheralDiscoveredEventArgs(this.myPeripheral); +} diff --git a/bluetooth_low_energy_linux/pubspec.yaml b/bluetooth_low_energy_linux/pubspec.yaml index 7b63ef0..21cf8f2 100644 --- a/bluetooth_low_energy_linux/pubspec.yaml +++ b/bluetooth_low_energy_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: bluetooth_low_energy_linux description: Linux implementation of the bluetooth_low_energy plugin. -version: 2.0.0 +version: 2.0.1 homepage: https://github.com/yanshouwang/bluetooth_low_energy environment: @@ -10,7 +10,7 @@ environment: dependencies: flutter: sdk: flutter - bluetooth_low_energy_platform_interface: ^2.0.0 + bluetooth_low_energy_platform_interface: ^2.0.1 bluez: ^0.8.1 dev_dependencies: diff --git a/bluetooth_low_energy_macos/CHANGELOG.md b/bluetooth_low_energy_macos/CHANGELOG.md index e510273..367297e 100644 --- a/bluetooth_low_energy_macos/CHANGELOG.md +++ b/bluetooth_low_energy_macos/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.0.1 + +- Fix the issue that GATTs is cleared after peripheral disconnected on iOS and macOS. +- Fix the issue that create UUID form peripheral's address failed on Linux. +- Fix the issue that instance match failed on Linux. + ## 2.0.0 - Rewrite the whole project with federated plugins. diff --git a/bluetooth_low_energy_macos/lib/src/my_api.g.dart b/bluetooth_low_energy_macos/lib/src/my_api.g.dart index 248235a..e4eaa84 100644 --- a/bluetooth_low_energy_macos/lib/src/my_api.g.dart +++ b/bluetooth_low_energy_macos/lib/src/my_api.g.dart @@ -483,12 +483,12 @@ class MyCentralControllerHostApi { } } - Future readCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey) async { + Future readCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.readCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey]) as List?; + await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -510,12 +510,12 @@ class MyCentralControllerHostApi { } } - Future writeCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async { + Future writeCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.writeCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List?; + await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -532,12 +532,12 @@ class MyCentralControllerHostApi { } } - Future notifyCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, bool arg_state) async { + Future notifyCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, bool arg_state) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.notifyCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_state]) as List?; + await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_state]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -554,12 +554,12 @@ class MyCentralControllerHostApi { } } - Future readDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey) async { + Future readDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.readDescriptor', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myDescriptorKey]) as List?; + await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -581,12 +581,12 @@ class MyCentralControllerHostApi { } } - Future writeDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey, Uint8List arg_value) async { + Future writeDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey, Uint8List arg_value) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.writeDescriptor', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myDescriptorKey, arg_value]) as List?; + await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey, arg_value]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', diff --git a/bluetooth_low_energy_macos/lib/src/my_central_controller.dart b/bluetooth_low_energy_macos/lib/src/my_central_controller.dart index 6444c3a..b717308 100644 --- a/bluetooth_low_energy_macos/lib/src/my_central_controller.dart +++ b/bluetooth_low_energy_macos/lib/src/my_central_controller.dart @@ -126,18 +126,16 @@ class MyCentralController extends CentralController await _throwWithoutState(CentralState.poweredOn); final myPeripheral = peripheral as MyPeripheral; final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode); - return myServiceArgses - .cast() - .map( - (myServiceArgs) => _myServices.putIfAbsent( - myServiceArgs.key, - () => MyGattService.fromMyArgs( - myPeripheral, - myServiceArgs, - ), - ), - ) - .toList(); + return myServiceArgses.cast().map( + (myServiceArgs) { + final myService = MyGattService.fromMyArgs( + myPeripheral, + myServiceArgs, + ); + _myServices[myService.hashCode] = myService; + return myService; + }, + ).toList(); } @override @@ -149,18 +147,16 @@ class MyCentralController extends CentralController final myCharactersiticArgses = await _myApi.getCharacteristics( myService.hashCode, ); - return myCharactersiticArgses - .cast() - .map( - (myCharacteristicArgs) => _myCharacteristics.putIfAbsent( - myCharacteristicArgs.key, - () => MyGattCharacteristic.fromMyArgs( - myService, - myCharacteristicArgs, - ), - ), - ) - .toList(); + return myCharactersiticArgses.cast().map( + (myCharacteristicArgs) { + final myCharacteristic = MyGattCharacteristic.fromMyArgs( + myService, + myCharacteristicArgs, + ); + _myCharacteristics[myCharacteristic.hashCode] = myCharacteristic; + return myCharacteristic; + }, + ).toList(); } @override @@ -172,18 +168,16 @@ class MyCentralController extends CentralController final myDescriptorArgses = await _myApi.getDescriptors( myCharacteristic.hashCode, ); - return myDescriptorArgses - .cast() - .map( - (myDescriptorArgs) => _myDescriptors.putIfAbsent( - myDescriptorArgs.key, - () => MyGattDescriptor.fromMyArgs( - myCharacteristic, - myDescriptorArgs, - ), - ), - ) - .toList(); + return myDescriptorArgses.cast().map( + (myDescriptorArgs) { + final myDescriptor = MyGattDescriptor.fromMyArgs( + myCharacteristic, + myDescriptorArgs, + ); + _myDescriptors[myDescriptor.hashCode] = myDescriptor; + return myDescriptor; + }, + ).toList(); } @override @@ -196,6 +190,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; final value = await _myApi.readCharacteristic( myPeripheral.hashCode, + myService.hashCode, myCharacteristic.hashCode, ); return value; @@ -215,6 +210,7 @@ class MyCentralController extends CentralController final typeNumber = typeArgs.index; await _myApi.writeCharacteristic( myPeripheral.hashCode, + myService.hashCode, myCharacteristic.hashCode, value, typeNumber, @@ -232,6 +228,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; await _myApi.notifyCharacteristic( myPeripheral.hashCode, + myService.hashCode, myCharacteristic.hashCode, state, ); @@ -246,6 +243,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; final value = await _myApi.readDescriptor( myPeripheral.hashCode, + myCharacteristic.hashCode, myDescriptor.hashCode, ); return value; @@ -263,6 +261,7 @@ class MyCentralController extends CentralController final myPeripheral = myService.myPeripheral; await _myApi.writeDescriptor( myPeripheral.hashCode, + myCharacteristic.hashCode, myDescriptor.hashCode, value, ); @@ -286,10 +285,8 @@ class MyCentralController extends CentralController int rssi, MyAdvertisementArgs myAdvertisementArgs, ) { - final myPeripheral = _myPeripherals.putIfAbsent( - myPeripheralArgs.key, - () => MyPeripheral.fromMyArgs(myPeripheralArgs), - ); + final myPeripheral = MyPeripheral.fromMyArgs(myPeripheralArgs); + _myPeripherals[myPeripheral.hashCode] = myPeripheral; final advertisement = myAdvertisementArgs.toAdvertisement(); final eventArgs = CentralDiscoveredEventArgs( myPeripheral, diff --git a/bluetooth_low_energy_macos/macos/Classes/MyApi.g.swift b/bluetooth_low_energy_macos/macos/Classes/MyApi.g.swift index 2347a9f..439dd78 100644 --- a/bluetooth_low_energy_macos/macos/Classes/MyApi.g.swift +++ b/bluetooth_low_energy_macos/macos/Classes/MyApi.g.swift @@ -258,11 +258,11 @@ protocol MyCentralControllerHostApi { func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] - func readCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result) -> Void) - func writeCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result) -> Void) - func notifyCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result) -> Void) - func readDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result) -> Void) - func writeDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result) -> Void) + func readCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result) -> Void) + func writeCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result) -> Void) + func notifyCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result) -> Void) + func readDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result) -> Void) + func writeDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result) -> Void) } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. @@ -426,8 +426,9 @@ class MyCentralControllerHostApiSetup { readCharacteristicChannel.setMessageHandler { message, reply in let args = message as! [Any?] let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - api.readCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg) { result in + let myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + api.readCharacteristic(myPeripheralKey: myPeripheralKeyArg, myServiceKey: myServiceKeyArg, myCharacteristicKey: myCharacteristicKeyArg) { result in switch result { case .success(let res): reply(wrapResult(res)) @@ -444,10 +445,11 @@ class MyCentralControllerHostApiSetup { writeCharacteristicChannel.setMessageHandler { message, reply in let args = message as! [Any?] let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - let valueArg = args[2] as! FlutterStandardTypedData - let myTypeNumberArg = args[3] is Int64 ? args[3] as! Int64 : Int64(args[3] as! Int32) - api.writeCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, value: valueArg, myTypeNumber: myTypeNumberArg) { result in + let myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + let valueArg = args[3] as! FlutterStandardTypedData + let myTypeNumberArg = args[4] is Int64 ? args[4] as! Int64 : Int64(args[4] as! Int32) + api.writeCharacteristic(myPeripheralKey: myPeripheralKeyArg, myServiceKey: myServiceKeyArg, myCharacteristicKey: myCharacteristicKeyArg, value: valueArg, myTypeNumber: myTypeNumberArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -464,9 +466,10 @@ class MyCentralControllerHostApiSetup { notifyCharacteristicChannel.setMessageHandler { message, reply in let args = message as! [Any?] let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - let stateArg = args[2] as! Bool - api.notifyCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, state: stateArg) { result in + let myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + let stateArg = args[3] as! Bool + api.notifyCharacteristic(myPeripheralKey: myPeripheralKeyArg, myServiceKey: myServiceKeyArg, myCharacteristicKey: myCharacteristicKeyArg, state: stateArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -483,8 +486,9 @@ class MyCentralControllerHostApiSetup { readDescriptorChannel.setMessageHandler { message, reply in let args = message as! [Any?] let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myDescriptorKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - api.readDescriptor(myPeripheralKey: myPeripheralKeyArg, myDescriptorKey: myDescriptorKeyArg) { result in + let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let myDescriptorKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + api.readDescriptor(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, myDescriptorKey: myDescriptorKeyArg) { result in switch result { case .success(let res): reply(wrapResult(res)) @@ -501,9 +505,10 @@ class MyCentralControllerHostApiSetup { writeDescriptorChannel.setMessageHandler { message, reply in let args = message as! [Any?] let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myDescriptorKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - let valueArg = args[2] as! FlutterStandardTypedData - api.writeDescriptor(myPeripheralKey: myPeripheralKeyArg, myDescriptorKey: myDescriptorKeyArg, value: valueArg) { result in + let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let myDescriptorKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + let valueArg = args[3] as! FlutterStandardTypedData + api.writeDescriptor(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, myDescriptorKey: myDescriptorKeyArg, value: valueArg) { result in switch result { case .success: reply(wrapResult(nil)) diff --git a/bluetooth_low_energy_macos/macos/Classes/MyCentralController.swift b/bluetooth_low_energy_macos/macos/Classes/MyCentralController.swift index 9cffd6c..699ee68 100644 --- a/bluetooth_low_energy_macos/macos/Classes/MyCentralController.swift +++ b/bluetooth_low_energy_macos/macos/Classes/MyCentralController.swift @@ -19,10 +19,10 @@ class MyCentralController: MyCentralControllerHostApi { private lazy var myPeripheralDelegate = MyPeripheralDelegate(self) private let centralManager = CBCentralManager() - private var peripherals = [Int: CBPeripheral]() - private var services = [Int: CBService]() - private var characteristics = [Int: CBCharacteristic]() - private var descriptors = [Int: CBDescriptor]() + private var cachedPeripherals = [Int: CBPeripheral]() + private var cachedServices = [Int: [Int: CBService]]() + private var cachedCharacteristics = [Int: [Int: CBCharacteristic]]() + private var cachedDescriptors = [Int: [Int: CBDescriptor]]() var setUpCompletion: ((Result) -> Void)? var connectCompletions = [Int: (Result) -> Void]() @@ -61,16 +61,16 @@ class MyCentralController: MyCentralControllerHostApi { if(centralManager.isScanning) { centralManager.stopScan() } - for peripheral in peripherals.values { + for peripheral in cachedPeripherals.values { peripheral.delegate = nil if peripheral.state != .disconnected { centralManager.cancelPeripheralConnection(peripheral) } } - peripherals.removeAll() - services.removeAll() - characteristics.removeAll() - descriptors.removeAll() + cachedPeripherals.removeAll() + cachedServices.removeAll() + cachedCharacteristics.removeAll() + cachedDescriptors.removeAll() } func startDiscovery() throws { @@ -89,7 +89,7 @@ class MyCentralController: MyCentralControllerHostApi { if unfinishedCompletion != nil { throw MyError.illegalState } - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { throw MyError.illegalArgument } centralManager.connect(peripheral) @@ -106,7 +106,7 @@ class MyCentralController: MyCentralControllerHostApi { if unfinishedCompletion != nil { throw MyError.illegalState } - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { throw MyError.illegalArgument } centralManager.cancelPeripheralConnection(peripheral) @@ -123,7 +123,7 @@ class MyCentralController: MyCentralControllerHostApi { if unfinishedCompletion != nil { throw MyError.illegalState } - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { throw MyError.illegalArgument } peripheral.discoverServices(nil) @@ -135,53 +135,42 @@ class MyCentralController: MyCentralControllerHostApi { func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let services = cachedServices[peripheralKey] else { throw MyError.illegalArgument } - let services = peripheral.services ?? [] - return services.map { service in - let serviceKey = service.hash - if self.services[serviceKey] == nil { - self.services[serviceKey] = service - } + return services.map { (key, service) in return service.toMyArgs() } } func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] { let serviceKey = Int(myServiceKey) - guard let service = services[serviceKey] else { + guard let characteristics = cachedCharacteristics[serviceKey] else { throw MyError.illegalArgument } - let characteristics = service.characteristics ?? [] - return characteristics.map { characteristic in - let characteristicKey = characteristic.hash - if self.characteristics[characteristicKey] == nil { - self.characteristics[characteristicKey] = characteristic - } + return characteristics.map { (key, characteristic) in return characteristic.toMyArgs() } } func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] { let characteristicKey = Int(myCharacteristicKey) - guard let characteristic = characteristics[characteristicKey] else { + guard let descriptors = cachedDescriptors[characteristicKey] else { throw MyError.illegalArgument } - let descritors = characteristic.descriptors ?? [] - return descritors.map { descriptor in - let descriptorKey = descriptor.hash - if self.descriptors[descriptorKey] == nil { - self.descriptors[descriptorKey] = descriptor - } + return descriptors.map { (key, descriptor) in return descriptor.toMyArgs() } } - func readCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result) -> Void) { + func readCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result) -> Void) { do { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { + throw MyError.illegalArgument + } + let serviceKey = Int(myServiceKey) + guard let characteristics = cachedCharacteristics[serviceKey] else { throw MyError.illegalArgument } let characteristicKey = Int(myCharacteristicKey) @@ -199,10 +188,14 @@ class MyCentralController: MyCentralControllerHostApi { } } - func writeCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result) -> Void) { + func writeCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result) -> Void) { do { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { + throw MyError.illegalArgument + } + let serviceKey = Int(myServiceKey) + guard let characteristics = cachedCharacteristics[serviceKey] else { throw MyError.illegalArgument } let characteristicKey = Int(myCharacteristicKey) @@ -226,10 +219,14 @@ class MyCentralController: MyCentralControllerHostApi { } } - func notifyCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result) -> Void) { + func notifyCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result) -> Void) { do { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { + throw MyError.illegalArgument + } + let serviceKey = Int(myServiceKey) + guard let characteristics = cachedCharacteristics[serviceKey] else { throw MyError.illegalArgument } let characteristicKey = Int(myCharacteristicKey) @@ -247,10 +244,14 @@ class MyCentralController: MyCentralControllerHostApi { } } - func readDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result) -> Void) { + func readDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result) -> Void) { do { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { + throw MyError.illegalArgument + } + let characteristicKey = Int(myCharacteristicKey) + guard let descriptors = cachedDescriptors[characteristicKey] else { throw MyError.illegalArgument } let descriptorKey = Int(myDescriptorKey) @@ -268,10 +269,14 @@ class MyCentralController: MyCentralControllerHostApi { } } - func writeDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result) -> Void) { + func writeDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result) -> Void) { do { let peripheralKey = Int(myPeripheralKey) - guard let peripheral = peripherals[peripheralKey] else { + guard let peripheral = cachedPeripherals[peripheralKey] else { + throw MyError.illegalArgument + } + let characteristicKey = Int(myCharacteristicKey) + guard let descriptors = cachedDescriptors[characteristicKey] else { throw MyError.illegalArgument } let descriptorKey = Int(myDescriptorKey) @@ -307,9 +312,9 @@ class MyCentralController: MyCentralControllerHostApi { func didDiscover(_ peripheral: CBPeripheral, _ advertisementData: [String : Any], _ rssiNumber: NSNumber) { let peripheralKey = peripheral.hash - if peripherals[peripheralKey] == nil { + if cachedPeripherals[peripheralKey] == nil { peripheral.delegate = myPeripheralDelegate - peripherals[peripheralKey] = peripheral + cachedPeripherals[peripheralKey] = peripheral } let myPeripheralArgs = peripheral.toMyArgs() let rssi = rssiNumber.int64Value @@ -368,26 +373,24 @@ class MyCentralController: MyCentralControllerHostApi { let myPeripheralKey = Int64(peripheralKey) let discoverGattCompletion = discoverGattCompletions.removeValue(forKey: peripheralKey) if discoverGattCompletion != nil { - discoverGattCompletion!(.failure(error ?? MyError.illegalState)) + didDiscoverGATT(peripheral, error ?? MyError.unknown) } - let services = peripheral.services ?? [] + let services = cachedServices[peripheralKey] ?? [:] for service in services { - let characteristics = service.characteristics ?? [] + let characteristics = cachedCharacteristics[service.key] ?? [:] for characteristic in characteristics { - let characteristicKey = characteristic.hash - let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristicKey) - let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristicKey) + let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristic.key) + let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristic.key) if readCharacteristicCompletion != nil { readCharacteristicCompletion!(.failure(MyError.illegalState)) } if writeCharacteristicCompletion != nil { writeCharacteristicCompletion!(.failure(MyError.illegalState)) } - let descriptors = characteristic.descriptors ?? [] + let descriptors = cachedDescriptors[characteristic.key] ?? [:] for descriptor in descriptors { - let descriptorKey = descriptor.hash - let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptorKey) - let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptorKey) + let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptor.key) + let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptor.key) if readDescriptorCompletion != nil { readDescriptorCompletion!(.failure(MyError.illegalState)) } @@ -411,37 +414,28 @@ class MyCentralController: MyCentralControllerHostApi { func didDiscoverServices(_ peripheral: CBPeripheral, _ error: Error?) { let peripheralKey = peripheral.hash - guard let completion = discoverGattCompletions[peripheralKey] else { - return - } if error == nil { var services = peripheral.services ?? [] if services.isEmpty { - discoverGattCompletions.removeValue(forKey: peripheralKey) - completion(.success(())) + didDiscoverGATT(peripheral, error) } else { let service = services.removeFirst() unfinishedServices[peripheralKey] = services peripheral.discoverCharacteristics(nil, for: service) } } else { - discoverGattCompletions.removeValue(forKey: peripheralKey) - completion(.failure(error!)) + didDiscoverGATT(peripheral, error) } } func didDiscoverCharacteristics(_ peripheral: CBPeripheral, _ service: CBService, _ error: Error?) { let peripheralKey = peripheral.hash - guard let completion = discoverGattCompletions[peripheralKey] else { - return - } if error == nil { var characteristics = service.characteristics ?? [] if characteristics.isEmpty { var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? [] if services.isEmpty { - discoverGattCompletions.removeValue(forKey: peripheralKey) - completion(.success(())) + didDiscoverGATT(peripheral, error) } else { let service = services.removeFirst() unfinishedServices[peripheralKey] = services @@ -453,24 +447,18 @@ class MyCentralController: MyCentralControllerHostApi { peripheral.discoverDescriptors(for: characteristic) } } else { - discoverGattCompletions.removeValue(forKey: peripheralKey) - unfinishedServices.removeValue(forKey: peripheralKey) - completion(.failure(error!)) + didDiscoverGATT(peripheral, error) } } func didDiscoverDescriptors(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic, _ error: Error?) { let peripheralKey = peripheral.hash - guard let completion = discoverGattCompletions[peripheralKey] else { - return - } if error == nil { var characteristics = unfinishedCharacteristics.removeValue(forKey: peripheralKey) ?? [] if (characteristics.isEmpty) { var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? [] if services.isEmpty { - discoverGattCompletions.removeValue(forKey: peripheralKey) - completion(.success(())) + didDiscoverGATT(peripheral, error) } else { let service = services.removeFirst() unfinishedServices[peripheralKey] = services @@ -482,9 +470,41 @@ class MyCentralController: MyCentralControllerHostApi { peripheral.discoverDescriptors(for: characteristic) } } else { - discoverGattCompletions.removeValue(forKey: peripheralKey) - unfinishedServices.removeValue(forKey: peripheralKey) - unfinishedCharacteristics.removeValue(forKey: peripheralKey) + didDiscoverGATT(peripheral, error) + } + } + + private func didDiscoverGATT(_ peripheral: CBPeripheral, _ error: Error?) { + let peripheralKey = peripheral.hash + unfinishedServices.removeValue(forKey: peripheralKey) + unfinishedCharacteristics.removeValue(forKey: peripheralKey) + guard let completion = discoverGattCompletions.removeValue(forKey: peripheralKey) else { + return + } + if error == nil { + let services = peripheral.services ?? [] + var cachedServices = [Int: CBService]() + for service in services { + let serviceKey = service.hash + cachedServices[serviceKey] = service + let characteristics = service.characteristics ?? [] + var cachedCharacteristics = [Int: CBCharacteristic]() + for characteristic in characteristics { + let characteristicKey = characteristic.hash + cachedCharacteristics[characteristicKey] = characteristic + let descriptors = characteristic.descriptors ?? [] + var cachedDescriptors = [Int: CBDescriptor]() + for descriptor in descriptors { + let descriptorKey = descriptor.hash + cachedDescriptors[descriptorKey] = descriptor + } + self.cachedDescriptors[characteristicKey] = cachedDescriptors + } + self.cachedCharacteristics[serviceKey] = cachedCharacteristics + } + self.cachedServices[peripheralKey] = cachedServices + completion(.success(())) + } else { completion(.failure(error!)) } } diff --git a/bluetooth_low_energy/macos/bluetooth_low_energy.podspec b/bluetooth_low_energy_macos/macos/bluetooth_low_energy.podspec similarity index 100% rename from bluetooth_low_energy/macos/bluetooth_low_energy.podspec rename to bluetooth_low_energy_macos/macos/bluetooth_low_energy.podspec diff --git a/bluetooth_low_energy_macos/macos/bluetooth_low_energy_macos.podspec b/bluetooth_low_energy_macos/macos/bluetooth_low_energy_macos.podspec deleted file mode 100644 index 33ca37f..0000000 --- a/bluetooth_low_energy_macos/macos/bluetooth_low_energy_macos.podspec +++ /dev/null @@ -1,23 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint bluetooth_low_energy_macos.podspec` to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'bluetooth_low_energy_macos' - s.version = '0.0.1' - s.summary = 'A new Flutter plugin project.' - s.description = <<-DESC -A new Flutter plugin project. - DESC - s.homepage = 'http://example.com' - s.license = { :file => '../LICENSE' } - s.author = { 'Your Company' => 'email@example.com' } - - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.dependency 'FlutterMacOS' - - s.platform = :osx, '10.11' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } - s.swift_version = '5.0' -end diff --git a/bluetooth_low_energy_macos/my_api.dart b/bluetooth_low_energy_macos/my_api.dart index b304c8a..44d0c24 100644 --- a/bluetooth_low_energy_macos/my_api.dart +++ b/bluetooth_low_energy_macos/my_api.dart @@ -25,10 +25,15 @@ abstract class MyCentralControllerHostApi { List getCharacteristics(int myServiceKey); List getDescriptors(int myCharacteristicKey); @async - Uint8List readCharacteristic(int myPeripheralKey, int myCharacteristicKey); + Uint8List readCharacteristic( + int myPeripheralKey, + int myServiceKey, + int myCharacteristicKey, + ); @async void writeCharacteristic( int myPeripheralKey, + int myServiceKey, int myCharacteristicKey, Uint8List value, int myTypeNumber, @@ -36,14 +41,20 @@ abstract class MyCentralControllerHostApi { @async void notifyCharacteristic( int myPeripheralKey, + int myServiceKey, int myCharacteristicKey, bool state, ); @async - Uint8List readDescriptor(int myPeripheralKey, int myDescriptorKey); + Uint8List readDescriptor( + int myPeripheralKey, + int myCharacteristicKey, + int myDescriptorKey, + ); @async void writeDescriptor( int myPeripheralKey, + int myCharacteristicKey, int myDescriptorKey, Uint8List value, ); diff --git a/bluetooth_low_energy_macos/pubspec.yaml b/bluetooth_low_energy_macos/pubspec.yaml index 28addbc..1ff01d9 100644 --- a/bluetooth_low_energy_macos/pubspec.yaml +++ b/bluetooth_low_energy_macos/pubspec.yaml @@ -1,6 +1,6 @@ name: bluetooth_low_energy_macos description: macOS implementation of the bluetooth_low_energy plugin. -version: 2.0.0 +version: 2.0.1 homepage: https://github.com/yanshouwang/bluetooth_low_energy environment: @@ -10,7 +10,7 @@ environment: dependencies: flutter: sdk: flutter - bluetooth_low_energy_platform_interface: ^2.0.0 + bluetooth_low_energy_platform_interface: ^2.0.1 dev_dependencies: flutter_test: diff --git a/bluetooth_low_energy_platform_interface/CHANGELOG.md b/bluetooth_low_energy_platform_interface/CHANGELOG.md index e510273..367297e 100644 --- a/bluetooth_low_energy_platform_interface/CHANGELOG.md +++ b/bluetooth_low_energy_platform_interface/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.0.1 + +- Fix the issue that GATTs is cleared after peripheral disconnected on iOS and macOS. +- Fix the issue that create UUID form peripheral's address failed on Linux. +- Fix the issue that instance match failed on Linux. + ## 2.0.0 - Rewrite the whole project with federated plugins. diff --git a/bluetooth_low_energy_platform_interface/pubspec.yaml b/bluetooth_low_energy_platform_interface/pubspec.yaml index b09dc24..fc8fea8 100644 --- a/bluetooth_low_energy_platform_interface/pubspec.yaml +++ b/bluetooth_low_energy_platform_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: bluetooth_low_energy_platform_interface description: A common platform interface for the bluetooth_low_energy plugin. -version: 2.0.0 +version: 2.0.1 homepage: https://github.com/yanshouwang/bluetooth_low_energy environment: diff --git a/bluetooth_low_energy_windows/CHANGELOG.md b/bluetooth_low_energy_windows/CHANGELOG.md index e510273..367297e 100644 --- a/bluetooth_low_energy_windows/CHANGELOG.md +++ b/bluetooth_low_energy_windows/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.0.1 + +- Fix the issue that GATTs is cleared after peripheral disconnected on iOS and macOS. +- Fix the issue that create UUID form peripheral's address failed on Linux. +- Fix the issue that instance match failed on Linux. + ## 2.0.0 - Rewrite the whole project with federated plugins. diff --git a/bluetooth_low_energy_windows/pubspec.yaml b/bluetooth_low_energy_windows/pubspec.yaml index 74754cd..f11afa6 100644 --- a/bluetooth_low_energy_windows/pubspec.yaml +++ b/bluetooth_low_energy_windows/pubspec.yaml @@ -1,6 +1,6 @@ name: bluetooth_low_energy_windows description: Windows implementation of the bluetooth_low_energy plugin. -version: 2.0.0 +version: 2.0.1 homepage: https://github.com/yanshouwang/bluetooth_low_energy environment: @@ -10,7 +10,7 @@ environment: dependencies: flutter: sdk: flutter - bluetooth_low_energy_platform_interface: ^2.0.0 + bluetooth_low_energy_platform_interface: ^2.0.1 win32: ^5.0.6 dev_dependencies: @@ -23,5 +23,5 @@ flutter: implements: bluetooth_low_energy platforms: windows: - pluginClass: BluetoothLowEnergyWindowsPluginCApi + pluginClass: BluetoothLowEnergyPluginCApi dartPluginClass: BluetoothLowEnergyWindows diff --git a/bluetooth_low_energy_windows/windows/CMakeLists.txt b/bluetooth_low_energy_windows/windows/CMakeLists.txt index 038bd7c..13df83f 100644 --- a/bluetooth_low_energy_windows/windows/CMakeLists.txt +++ b/bluetooth_low_energy_windows/windows/CMakeLists.txt @@ -5,24 +5,24 @@ cmake_minimum_required(VERSION 3.14) # Project-level configuration. -set(PROJECT_NAME "bluetooth_low_energy_windows") +set(PROJECT_NAME "bluetooth_low_energy") project(${PROJECT_NAME} LANGUAGES CXX) # This value is used when generating builds using this plugin, so it must # not be changed -set(PLUGIN_NAME "bluetooth_low_energy_windows_plugin") +set(PLUGIN_NAME "bluetooth_low_energy_plugin") # Any new source files that you add to the plugin should be added here. list(APPEND PLUGIN_SOURCES - "bluetooth_low_energy_windows_plugin.cpp" - "bluetooth_low_energy_windows_plugin.h" + "bluetooth_low_energy_plugin.cpp" + "bluetooth_low_energy_plugin.h" ) # Define the plugin library target. Its name must not be changed (see comment # on PLUGIN_NAME above). add_library(${PLUGIN_NAME} SHARED - "include/bluetooth_low_energy_windows/bluetooth_low_energy_windows_plugin_c_api.h" - "bluetooth_low_energy_windows_plugin_c_api.cpp" + "include/bluetooth_low_energy/bluetooth_low_energy_plugin_c_api.h" + "bluetooth_low_energy_plugin_c_api.cpp" ${PLUGIN_SOURCES} ) @@ -47,7 +47,50 @@ target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) # List of absolute paths to libraries that should be bundled with the plugin. # This list could contain prebuilt libraries, or libraries created by an # external build triggered from this build file. -set(bluetooth_low_energy_windows_bundled_libraries +set(bluetooth_low_energy_bundled_libraries "" PARENT_SCOPE ) + +# === Tests === +# These unit tests can be run from a terminal after building the example, or +# from Visual Studio after opening the generated solution file. + +# Only enable test builds when building the example (which sets this variable) +# so that plugin clients aren't building the tests. +if (${include_${PROJECT_NAME}_tests}) +set(TEST_RUNNER "${PROJECT_NAME}_test") +enable_testing() + +# Add the Google Test dependency. +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/release-1.11.0.zip +) +# Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +# Disable install commands for gtest so it doesn't end up in the bundle. +set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE) +FetchContent_MakeAvailable(googletest) + +# The plugin's C API is not very useful for unit testing, so build the sources +# directly into the test binary rather than using the DLL. +add_executable(${TEST_RUNNER} + test/bluetooth_low_energy_plugin_test.cpp + ${PLUGIN_SOURCES} +) +apply_standard_settings(${TEST_RUNNER}) +target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") +target_link_libraries(${TEST_RUNNER} PRIVATE flutter_wrapper_plugin) +target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock) +# flutter_wrapper_plugin has link dependencies on the Flutter DLL. +add_custom_command(TARGET ${TEST_RUNNER} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${FLUTTER_LIBRARY}" $ +) + +# Enable automatic test discovery. +include(GoogleTest) +gtest_discover_tests(${TEST_RUNNER}) +endif() diff --git a/bluetooth_low_energy/windows/bluetooth_low_energy_plugin.cpp b/bluetooth_low_energy_windows/windows/bluetooth_low_energy_plugin.cpp similarity index 100% rename from bluetooth_low_energy/windows/bluetooth_low_energy_plugin.cpp rename to bluetooth_low_energy_windows/windows/bluetooth_low_energy_plugin.cpp diff --git a/bluetooth_low_energy/windows/bluetooth_low_energy_plugin.h b/bluetooth_low_energy_windows/windows/bluetooth_low_energy_plugin.h similarity index 100% rename from bluetooth_low_energy/windows/bluetooth_low_energy_plugin.h rename to bluetooth_low_energy_windows/windows/bluetooth_low_energy_plugin.h diff --git a/bluetooth_low_energy/windows/bluetooth_low_energy_plugin_c_api.cpp b/bluetooth_low_energy_windows/windows/bluetooth_low_energy_plugin_c_api.cpp similarity index 100% rename from bluetooth_low_energy/windows/bluetooth_low_energy_plugin_c_api.cpp rename to bluetooth_low_energy_windows/windows/bluetooth_low_energy_plugin_c_api.cpp diff --git a/bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin.cpp b/bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin.cpp deleted file mode 100644 index aa3a4f4..0000000 --- a/bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "bluetooth_low_energy_windows_plugin.h" - -// This must be included before many other Windows headers. -#include - -// For getPlatformVersion; remove unless needed for your plugin implementation. -#include - -#include -#include -#include - -#include -#include - -namespace bluetooth_low_energy_windows { - -// static -void BluetoothLowEnergyWindowsPlugin::RegisterWithRegistrar( - flutter::PluginRegistrarWindows *registrar) { - auto channel = - std::make_unique>( - registrar->messenger(), "bluetooth_low_energy_windows", - &flutter::StandardMethodCodec::GetInstance()); - - auto plugin = std::make_unique(); - - channel->SetMethodCallHandler( - [plugin_pointer = plugin.get()](const auto &call, auto result) { - plugin_pointer->HandleMethodCall(call, std::move(result)); - }); - - registrar->AddPlugin(std::move(plugin)); -} - -BluetoothLowEnergyWindowsPlugin::BluetoothLowEnergyWindowsPlugin() {} - -BluetoothLowEnergyWindowsPlugin::~BluetoothLowEnergyWindowsPlugin() {} - -void BluetoothLowEnergyWindowsPlugin::HandleMethodCall( - const flutter::MethodCall &method_call, - std::unique_ptr> result) { - if (method_call.method_name().compare("getPlatformVersion") == 0) { - std::ostringstream version_stream; - version_stream << "Windows "; - if (IsWindows10OrGreater()) { - version_stream << "10+"; - } else if (IsWindows8OrGreater()) { - version_stream << "8"; - } else if (IsWindows7OrGreater()) { - version_stream << "7"; - } - result->Success(flutter::EncodableValue(version_stream.str())); - } else { - result->NotImplemented(); - } -} - -} // namespace bluetooth_low_energy_windows diff --git a/bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin.h b/bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin.h deleted file mode 100644 index adfae78..0000000 --- a/bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_WINDOWS_PLUGIN_H_ -#define FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_WINDOWS_PLUGIN_H_ - -#include -#include - -#include - -namespace bluetooth_low_energy_windows { - -class BluetoothLowEnergyWindowsPlugin : public flutter::Plugin { - public: - static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); - - BluetoothLowEnergyWindowsPlugin(); - - virtual ~BluetoothLowEnergyWindowsPlugin(); - - // Disallow copy and assign. - BluetoothLowEnergyWindowsPlugin(const BluetoothLowEnergyWindowsPlugin&) = delete; - BluetoothLowEnergyWindowsPlugin& operator=(const BluetoothLowEnergyWindowsPlugin&) = delete; - - private: - // Called when a method is called on this plugin's channel from Dart. - void HandleMethodCall( - const flutter::MethodCall &method_call, - std::unique_ptr> result); -}; - -} // namespace bluetooth_low_energy_windows - -#endif // FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_WINDOWS_PLUGIN_H_ diff --git a/bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin_c_api.cpp b/bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin_c_api.cpp deleted file mode 100644 index e3196d5..0000000 --- a/bluetooth_low_energy_windows/windows/bluetooth_low_energy_windows_plugin_c_api.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "include/bluetooth_low_energy_windows/bluetooth_low_energy_windows_plugin_c_api.h" - -#include - -#include "bluetooth_low_energy_windows_plugin.h" - -void BluetoothLowEnergyWindowsPluginCApiRegisterWithRegistrar( - FlutterDesktopPluginRegistrarRef registrar) { - bluetooth_low_energy_windows::BluetoothLowEnergyWindowsPlugin::RegisterWithRegistrar( - flutter::PluginRegistrarManager::GetInstance() - ->GetRegistrar(registrar)); -} diff --git a/bluetooth_low_energy/windows/include/bluetooth_low_energy/bluetooth_low_energy_plugin_c_api.h b/bluetooth_low_energy_windows/windows/include/bluetooth_low_energy/bluetooth_low_energy_plugin_c_api.h similarity index 100% rename from bluetooth_low_energy/windows/include/bluetooth_low_energy/bluetooth_low_energy_plugin_c_api.h rename to bluetooth_low_energy_windows/windows/include/bluetooth_low_energy/bluetooth_low_energy_plugin_c_api.h diff --git a/bluetooth_low_energy_windows/windows/include/bluetooth_low_energy_windows/bluetooth_low_energy_windows_plugin_c_api.h b/bluetooth_low_energy_windows/windows/include/bluetooth_low_energy_windows/bluetooth_low_energy_windows_plugin_c_api.h deleted file mode 100644 index 4c108ea..0000000 --- a/bluetooth_low_energy_windows/windows/include/bluetooth_low_energy_windows/bluetooth_low_energy_windows_plugin_c_api.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_WINDOWS_PLUGIN_C_API_H_ -#define FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_WINDOWS_PLUGIN_C_API_H_ - -#include - -#ifdef FLUTTER_PLUGIN_IMPL -#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) -#else -#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -FLUTTER_PLUGIN_EXPORT void BluetoothLowEnergyWindowsPluginCApiRegisterWithRegistrar( - FlutterDesktopPluginRegistrarRef registrar); - -#if defined(__cplusplus) -} // extern "C" -#endif - -#endif // FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_WINDOWS_PLUGIN_C_API_H_ diff --git a/bluetooth_low_energy/windows/test/bluetooth_low_energy_plugin_test.cpp b/bluetooth_low_energy_windows/windows/test/bluetooth_low_energy_plugin_test.cpp similarity index 100% rename from bluetooth_low_energy/windows/test/bluetooth_low_energy_plugin_test.cpp rename to bluetooth_low_energy_windows/windows/test/bluetooth_low_energy_plugin_test.cpp