* 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 <jetson2@const.cc>
This commit is contained in:
Mr剑侠客
2023-08-18 18:24:24 +08:00
committed by GitHub
parent 9203908915
commit 689b1fb045
61 changed files with 734 additions and 1137 deletions

View File

@ -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 ## 2.0.0
- Rewrite the whole project with federated plugins. - Rewrite the whole project with federated plugins.

View File

@ -40,7 +40,7 @@ According to Apple's [documents](https://developer.apple.com/documentation/coreb
### Linux ### 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 ### Windows

View File

@ -27,7 +27,7 @@
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSBluetoothAlwaysUsageDescription</key> <key>NSBluetoothAlwaysUsageDescription</key>
<string>Hello Bluetooth Low Energy!</string> <string>Hello Bluetooth LowEnergy!</string>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>

View File

@ -162,9 +162,10 @@ class _HomeViewState extends State<HomeView> {
return ValueListenableBuilder( return ValueListenableBuilder(
valueListenable: discoveredEventArgs, valueListenable: discoveredEventArgs,
builder: (context, discoveredEventArgs, child) { builder: (context, discoveredEventArgs, child) {
final items = discoveredEventArgs // final items = discoveredEventArgs
.where((eventArgs) => eventArgs.advertisement.name != null) // .where((eventArgs) => eventArgs.advertisement.name != null)
.toList(); // .toList();
final items = discoveredEventArgs;
return ListView.separated( return ListView.separated(
itemBuilder: (context, i) { itemBuilder: (context, i) {
final theme = Theme.of(context); final theme = Theme.of(context);
@ -248,7 +249,7 @@ class _HomeViewState extends State<HomeView> {
}, },
); );
}, },
title: Text(name ?? '<EMPTY NAME>'), title: Text(name ?? 'N/A'),
subtitle: Text( subtitle: Text(
'$uuid', '$uuid',
style: theme.textTheme.bodySmall, style: theme.textTheme.bodySmall,

View File

@ -23,55 +23,55 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "2.0.0" version: "2.0.1"
bluetooth_low_energy_android: bluetooth_low_energy_android:
dependency: transitive dependency: transitive
description: description:
name: bluetooth_low_energy_android name: bluetooth_low_energy_android
sha256: f2a91728df49d52a77af9c8fb294a7afc173e2ce94abb6f9586949827b88a320 sha256: e4a14243be6b4556836a734e53e813a1c5f4f6c8e380ca49ebf8d02e5b3f37dc
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.1"
bluetooth_low_energy_ios: bluetooth_low_energy_ios:
dependency: transitive dependency: transitive
description: description:
name: bluetooth_low_energy_ios name: bluetooth_low_energy_ios
sha256: bf940f40321d1c3284957dbf7ff15587b4851bd722858798d77314d8f188b94f sha256: "38401d8e50d6f96b3e63f2c7e6fc32d6a1ae7d99dc60520fcb4162eb39ba2dd4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.1"
bluetooth_low_energy_linux: bluetooth_low_energy_linux:
dependency: transitive dependency: transitive
description: description:
name: bluetooth_low_energy_linux name: bluetooth_low_energy_linux
sha256: ff162bbf375240a615ee3539484438742c3c334c5ac6750db27a1e458cce8135 sha256: c88363e296ecb3a4b936e6d02f21214cf4e894d694c9996b523811b65e2d0eb0
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.1"
bluetooth_low_energy_macos: bluetooth_low_energy_macos:
dependency: transitive dependency: transitive
description: description:
name: bluetooth_low_energy_macos name: bluetooth_low_energy_macos
sha256: "0e454bde70f8d26a78156a2ffc7193c174f7bd04f8ff52eabfd21385fdcb22f9" sha256: b816568cc943d419bb395fbeb4b7aad66295c5e25e2f5b3e06532394dc27522e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.1"
bluetooth_low_energy_platform_interface: bluetooth_low_energy_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: bluetooth_low_energy_platform_interface name: bluetooth_low_energy_platform_interface
sha256: e07eb812e320cb167a2b9a59417fe1e632d23b031595dd8a9b72069243045900 sha256: "090b642fa738c04e899c4f4a78e88fa43a7dfa7f5b99f1c882cadad10a68e8fb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.1"
bluetooth_low_energy_windows: bluetooth_low_energy_windows:
dependency: transitive dependency: transitive
description: description:
name: bluetooth_low_energy_windows name: bluetooth_low_energy_windows
sha256: "6f28d9d7ce35e795207428f2c493a16759cbee34a74e9b254a29672dc8385205" sha256: ddd66c36811ad3fd347efaaba132e7bb27cdc446afc3e8cd3880c5f26a0d3b54
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.1"
bluez: bluez:
dependency: transitive dependency: transitive
description: description:

View File

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

View File

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

View File

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

View File

@ -1,76 +0,0 @@
#include "include/bluetooth_low_energy/bluetooth_low_energy_plugin.h"
#include <flutter_linux/flutter_linux.h>
#include <gtk/gtk.h>
#include <sys/utsname.h>
#include <cstring>
#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);
}

View File

@ -1,10 +0,0 @@
#include <flutter_linux/flutter_linux.h>
#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();

View File

@ -1,26 +0,0 @@
#ifndef FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_PLUGIN_H_
#define FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_PLUGIN_H_
#include <flutter_linux/flutter_linux.h>
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_

View File

@ -1,31 +0,0 @@
#include <flutter_linux/flutter_linux.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#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

View File

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

View File

@ -1,6 +1,6 @@
name: bluetooth_low_energy name: bluetooth_low_energy
description: A Flutter plugin for controlling the 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 homepage: https://github.com/yanshouwang/bluetooth_low_energy
environment: environment:
@ -10,12 +10,12 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
bluetooth_low_energy_platform_interface: ^2.0.0 bluetooth_low_energy_platform_interface: ^2.0.1
bluetooth_low_energy_android: ^2.0.0 bluetooth_low_energy_android: ^2.0.1
bluetooth_low_energy_ios: ^2.0.0 bluetooth_low_energy_ios: ^2.0.1
bluetooth_low_energy_macos: ^2.0.0 bluetooth_low_energy_macos: ^2.0.1
bluetooth_low_energy_linux: ^2.0.0 bluetooth_low_energy_linux: ^2.0.1
bluetooth_low_energy_windows: ^2.0.0 bluetooth_low_energy_windows: ^2.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

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

View File

@ -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}" $<TARGET_FILE_DIR:${TEST_RUNNER}>
)
# Enable automatic test discovery.
include(GoogleTest)
gtest_discover_tests(${TEST_RUNNER})
endif()

View File

@ -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 ## 2.0.0
- Rewrite the whole project with federated plugins. - Rewrite the whole project with federated plugins.

View File

@ -282,11 +282,11 @@ interface MyCentralControllerHostApi {
fun getServices(myPeripheralKey: Long): List<MyGattServiceArgs> fun getServices(myPeripheralKey: Long): List<MyGattServiceArgs>
fun getCharacteristics(myServiceKey: Long): List<MyGattCharacteristicArgs> fun getCharacteristics(myServiceKey: Long): List<MyGattCharacteristicArgs>
fun getDescriptors(myCharacteristicKey: Long): List<MyGattDescriptorArgs> fun getDescriptors(myCharacteristicKey: Long): List<MyGattDescriptorArgs>
fun readCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, callback: (Result<ByteArray>) -> Unit) fun readCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, callback: (Result<ByteArray>) -> Unit)
fun writeCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, value: ByteArray, myTypeNumber: Long, callback: (Result<Unit>) -> Unit) fun writeCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, value: ByteArray, myTypeNumber: Long, callback: (Result<Unit>) -> Unit)
fun notifyCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, state: Boolean, callback: (Result<Unit>) -> Unit) fun notifyCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, state: Boolean, callback: (Result<Unit>) -> Unit)
fun readDescriptor(myPeripheralKey: Long, myDescriptorKey: Long, callback: (Result<ByteArray>) -> Unit) fun readDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, callback: (Result<ByteArray>) -> Unit)
fun writeDescriptor(myPeripheralKey: Long, myDescriptorKey: Long, value: ByteArray, callback: (Result<Unit>) -> Unit) fun writeDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, value: ByteArray, callback: (Result<Unit>) -> Unit)
companion object { companion object {
/** The codec used by MyCentralControllerHostApi. */ /** The codec used by MyCentralControllerHostApi. */
@ -482,8 +482,9 @@ interface MyCentralControllerHostApi {
channel.setMessageHandler { message, reply -> channel.setMessageHandler { message, reply ->
val args = message as List<Any?> val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } 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 myServiceKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long }
api.readCharacteristic(myPeripheralKeyArg, myCharacteristicKeyArg) { result: Result<ByteArray> -> val myCharacteristicKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long }
api.readCharacteristic(myPeripheralKeyArg, myServiceKeyArg, myCharacteristicKeyArg) { result: Result<ByteArray> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(wrapError(error))
@ -503,10 +504,11 @@ interface MyCentralControllerHostApi {
channel.setMessageHandler { message, reply -> channel.setMessageHandler { message, reply ->
val args = message as List<Any?> val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } 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 myServiceKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long }
val valueArg = args[2] as ByteArray val myCharacteristicKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long }
val myTypeNumberArg = args[3].let { if (it is Int) it.toLong() else it as Long } val valueArg = args[3] as ByteArray
api.writeCharacteristic(myPeripheralKeyArg, myCharacteristicKeyArg, valueArg, myTypeNumberArg) { result: Result<Unit> -> val myTypeNumberArg = args[4].let { if (it is Int) it.toLong() else it as Long }
api.writeCharacteristic(myPeripheralKeyArg, myServiceKeyArg, myCharacteristicKeyArg, valueArg, myTypeNumberArg) { result: Result<Unit> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(wrapError(error))
@ -525,9 +527,10 @@ interface MyCentralControllerHostApi {
channel.setMessageHandler { message, reply -> channel.setMessageHandler { message, reply ->
val args = message as List<Any?> val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } 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 myServiceKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long }
val stateArg = args[2] as Boolean val myCharacteristicKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long }
api.notifyCharacteristic(myPeripheralKeyArg, myCharacteristicKeyArg, stateArg) { result: Result<Unit> -> val stateArg = args[3] as Boolean
api.notifyCharacteristic(myPeripheralKeyArg, myServiceKeyArg, myCharacteristicKeyArg, stateArg) { result: Result<Unit> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(wrapError(error))
@ -546,8 +549,9 @@ interface MyCentralControllerHostApi {
channel.setMessageHandler { message, reply -> channel.setMessageHandler { message, reply ->
val args = message as List<Any?> val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } 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 myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long }
api.readDescriptor(myPeripheralKeyArg, myDescriptorKeyArg) { result: Result<ByteArray> -> val myDescriptorKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long }
api.readDescriptor(myPeripheralKeyArg, myCharacteristicKeyArg, myDescriptorKeyArg) { result: Result<ByteArray> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(wrapError(error))
@ -567,9 +571,10 @@ interface MyCentralControllerHostApi {
channel.setMessageHandler { message, reply -> channel.setMessageHandler { message, reply ->
val args = message as List<Any?> val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } 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 myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long }
val valueArg = args[2] as ByteArray val myDescriptorKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long }
api.writeDescriptor(myPeripheralKeyArg, myDescriptorKeyArg, valueArg) { result: Result<Unit> -> val valueArg = args[3] as ByteArray
api.writeDescriptor(myPeripheralKeyArg, myCharacteristicKeyArg, myDescriptorKeyArg, valueArg) { result: Result<Unit> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(wrapError(error))

View File

@ -27,7 +27,8 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM
companion object { companion object {
// const val DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xff.toByte() // const val DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xff.toByte()
private const val REQUEST_CODE = 443 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") 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 myScanCallback = MyScanCallback(this)
private val myGattCallback = MyBluetoothGattCallback(this, executor) private val myGattCallback = MyBluetoothGattCallback(this, executor)
private val devices = mutableMapOf<Int, BluetoothDevice>() private val cachedDevices = mutableMapOf<Int, BluetoothDevice>()
private val gatts = mutableMapOf<Int, BluetoothGatt>() private val cachedGATTs = mutableMapOf<Int, BluetoothGatt>()
private val services = mutableMapOf<Int, BluetoothGattService>() private val cachedServices = mutableMapOf<Int, Map<Int, BluetoothGattService>>()
private val characteristics = mutableMapOf<Int, BluetoothGattCharacteristic>() private val cachedCharacteristics = mutableMapOf<Int, Map<Int, BluetoothGattCharacteristic>>()
private val descriptors = mutableMapOf<Int, BluetoothGattDescriptor>() private val cachedDescriptors = mutableMapOf<Int, Map<Int, BluetoothGattDescriptor>>()
private var registered = false private var registered = false
private var discovering = false private var discovering = false
@ -95,14 +96,14 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM
if (discovering) { if (discovering) {
stopDiscovery() stopDiscovery()
} }
for (gatt in gatts.values) { for (gatt in cachedGATTs.values) {
gatt.disconnect() gatt.disconnect()
} }
devices.clear() cachedDevices.clear()
gatts.clear() cachedGATTs.clear()
services.clear() cachedServices.clear()
characteristics.clear() cachedCharacteristics.clear()
descriptors.clear() cachedDescriptors.clear()
} }
private fun register() { private fun register() {
@ -148,9 +149,9 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM
if (unfinishedCallback != null) { if (unfinishedCallback != null) {
throw IllegalStateException() throw IllegalStateException()
} }
val device = devices[deviceKey] as BluetoothDevice val device = cachedDevices[deviceKey] as BluetoothDevice
val autoConnect = false 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 val transport = BluetoothDevice.TRANSPORT_LE
device.connectGatt(context, autoConnect, myGattCallback, transport) device.connectGatt(context, autoConnect, myGattCallback, transport)
} else { } else {
@ -169,7 +170,7 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM
if (unfinishedCallback != null) { if (unfinishedCallback != null) {
throw IllegalStateException() throw IllegalStateException()
} }
val gatt = gatts[deviceKey] as BluetoothGatt val gatt = cachedGATTs[deviceKey] as BluetoothGatt
gatt.disconnect() gatt.disconnect()
disconnectCallbacks[deviceKey] = callback disconnectCallbacks[deviceKey] = callback
} catch (e: Throwable) { } catch (e: Throwable) {
@ -184,7 +185,7 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM
if (unfinishedCallback != null) { if (unfinishedCallback != null) {
throw IllegalStateException() throw IllegalStateException()
} }
val gatt = gatts[deviceKey] as BluetoothGatt val gatt = cachedGATTs[deviceKey] as BluetoothGatt
val discovering = gatt.discoverServices() val discovering = gatt.discoverServices()
if (!discovering) { if (!discovering) {
throw IllegalStateException() throw IllegalStateException()
@ -197,53 +198,35 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM
override fun getServices(myPeripheralKey: Long): List<MyGattServiceArgs> { override fun getServices(myPeripheralKey: Long): List<MyGattServiceArgs> {
val deviceKey = myPeripheralKey.toInt() val deviceKey = myPeripheralKey.toInt()
val gatt = gatts[deviceKey] as BluetoothGatt val services = cachedServices[deviceKey] ?: throw IllegalStateException()
val services = gatt.services return services.values.map { service -> service.toMyArgs() }
return services.map { service ->
val serviceKey = service.hashCode()
if (this.services[serviceKey] == null) {
this.services[serviceKey] = service
}
return@map service.toMyArgs()
}
} }
override fun getCharacteristics(myServiceKey: Long): List<MyGattCharacteristicArgs> { override fun getCharacteristics(myServiceKey: Long): List<MyGattCharacteristicArgs> {
val serviceKey = myServiceKey.toInt() val serviceKey = myServiceKey.toInt()
val service = services[serviceKey] as BluetoothGattService val characteristics = cachedCharacteristics[serviceKey] ?: throw IllegalStateException()
val characteristics = service.characteristics return characteristics.values.map { characteristic -> characteristic.toMyArgs() }
return characteristics.map { characteristic ->
val characteristicKey = characteristic.hashCode()
if (this.characteristics[characteristicKey] == null) {
this.characteristics[characteristicKey] = characteristic
}
return@map characteristic.toMyArgs()
}
} }
override fun getDescriptors(myCharacteristicKey: Long): List<MyGattDescriptorArgs> { override fun getDescriptors(myCharacteristicKey: Long): List<MyGattDescriptorArgs> {
val characteristicKey = myCharacteristicKey.toInt() val characteristicKey = myCharacteristicKey.toInt()
val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic val descriptors = cachedDescriptors[characteristicKey] ?: throw IllegalStateException()
val descriptors = characteristic.descriptors return descriptors.values.map { descriptor -> descriptor.toMyArgs() }
return descriptors.map { descriptor ->
val descriptorKey = descriptor.hashCode()
if (this.descriptors[descriptorKey] == null) {
this.descriptors[descriptorKey] = descriptor
}
return@map descriptor.toMyArgs()
}
} }
override fun readCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, callback: (Result<ByteArray>) -> Unit) { override fun readCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, callback: (Result<ByteArray>) -> Unit) {
try { try {
val deviceKey = myPeripheralKey.toInt() 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 characteristicKey = myCharacteristicKey.toInt()
val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic
val unfinishedCallback = readCharacteristicCallbacks[characteristicKey] val unfinishedCallback = readCharacteristicCallbacks[characteristicKey]
if (unfinishedCallback != null) { if (unfinishedCallback != null) {
throw IllegalStateException() throw IllegalStateException()
} }
val gatt = gatts[deviceKey] as BluetoothGatt
val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic
val reading = gatt.readCharacteristic(characteristic) val reading = gatt.readCharacteristic(characteristic)
if (!reading) { if (!reading) {
throw IllegalStateException() 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>) -> Unit) { override fun writeCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, value: ByteArray, myTypeNumber: Long, callback: (Result<Unit>) -> Unit) {
try { try {
val deviceKey = myPeripheralKey.toInt() 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 characteristicKey = myCharacteristicKey.toInt()
val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic
val unfinishedCallback = writeCharacteristicCallbacks[characteristicKey] val unfinishedCallback = writeCharacteristicCallbacks[characteristicKey]
if (unfinishedCallback != null) { if (unfinishedCallback != null) {
throw IllegalStateException() throw IllegalStateException()
} }
val gatt = gatts[deviceKey] as BluetoothGatt
val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic
val myTypeArgs = myTypeNumber.toMyGattCharacteristicTypeArgs() val myTypeArgs = myTypeNumber.toMyGattCharacteristicTypeArgs()
val writeType = myTypeArgs.toType() val writeType = myTypeArgs.toType()
characteristic.value = value 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>) -> Unit) { override fun notifyCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, state: Boolean, callback: (Result<Unit>) -> Unit) {
try { try {
val deviceKey = myPeripheralKey.toInt() 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 characteristicKey = myCharacteristicKey.toInt()
val gatt = gatts[deviceKey] as BluetoothGatt
val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic
val notifying = gatt.setCharacteristicNotification(characteristic, state) val notifying = gatt.setCharacteristicNotification(characteristic, state)
if (!notifying) { if (!notifying) {
@ -314,16 +303,19 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM
} }
} }
override fun readDescriptor(myPeripheralKey: Long, myDescriptorKey: Long, callback: (Result<ByteArray>) -> Unit) { override fun readDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, callback: (Result<ByteArray>) -> Unit) {
try { try {
val deviceKey = myPeripheralKey.toInt() 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 descriptorKey = myDescriptorKey.toInt()
val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor
val unfinishedCallback = readDescriptorCallbacks[descriptorKey] val unfinishedCallback = readDescriptorCallbacks[descriptorKey]
if (unfinishedCallback != null) { if (unfinishedCallback != null) {
throw IllegalStateException() throw IllegalStateException()
} }
val gatt = gatts[deviceKey] as BluetoothGatt
val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor
val reading = gatt.readDescriptor(descriptor) val reading = gatt.readDescriptor(descriptor)
if (!reading) { if (!reading) {
throw IllegalStateException() 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>) -> Unit) { override fun writeDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, value: ByteArray, callback: (Result<Unit>) -> Unit) {
try { try {
val deviceKey = myPeripheralKey.toInt() 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 descriptorKey = myDescriptorKey.toInt()
val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor
val unfinishedCallback = writeDescriptorCallbacks[descriptorKey] val unfinishedCallback = writeDescriptorCallbacks[descriptorKey]
if (unfinishedCallback != null) { if (unfinishedCallback != null) {
throw IllegalStateException() throw IllegalStateException()
} }
val gatt = gatts[deviceKey] as BluetoothGatt
val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor
descriptor.value = value descriptor.value = value
val writing = gatt.writeDescriptor(descriptor) val writing = gatt.writeDescriptor(descriptor)
if (!writing) { if (!writing) {
@ -407,9 +402,7 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM
fun onScanResult(result: ScanResult) { fun onScanResult(result: ScanResult) {
val device = result.device val device = result.device
val deviceKey = device.hashCode() val deviceKey = device.hashCode()
if (devices[deviceKey] == null) { cachedDevices[deviceKey] = device
devices[deviceKey] = device
}
val myPeripheralArgs = device.toMyArgs() val myPeripheralArgs = device.toMyArgs()
val rssi = result.rssi.toLong() val rssi = result.rssi.toLong()
val myAdvertisementArgs = result.myAdvertisementArgs val myAdvertisementArgs = result.myAdvertisementArgs
@ -422,27 +415,28 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM
val myPeripheralKey = deviceKey.toLong() val myPeripheralKey = deviceKey.toLong()
if (newState != BluetoothProfile.STATE_CONNECTED) { if (newState != BluetoothProfile.STATE_CONNECTED) {
gatt.close() gatt.close()
gatts.remove(deviceKey) cachedGATTs.remove(deviceKey)
val error = IllegalStateException("GATT is disconnected with status: $status") val error = IllegalStateException("GATT is disconnected with status: $status")
val discoverGattCallback = discoverGattCallbacks.remove(deviceKey) val discoverGattCallback = discoverGattCallbacks.remove(deviceKey)
if (discoverGattCallback != null) { if (discoverGattCallback != null) {
discoverGattCallback(Result.failure(error)) discoverGattCallback(Result.failure(error))
} }
for (service in gatt.services) { val services = cachedServices[deviceKey] ?: emptyMap()
for (characteristic in service.characteristics) { for (service in services) {
val characteristicKey = characteristic.hashCode() val characteristics = cachedCharacteristics[service.key] ?: emptyMap()
val readCharacteristicCallback = readCharacteristicCallbacks.remove(characteristicKey) for (characteristic in characteristics) {
val writeCharacteristicCallback = writeCharacteristicCallbacks.remove(characteristicKey) val readCharacteristicCallback = readCharacteristicCallbacks.remove(characteristic.key)
val writeCharacteristicCallback = writeCharacteristicCallbacks.remove(characteristic.key)
if (readCharacteristicCallback != null) { if (readCharacteristicCallback != null) {
readCharacteristicCallback(Result.failure(error)) readCharacteristicCallback(Result.failure(error))
} }
if (writeCharacteristicCallback != null) { if (writeCharacteristicCallback != null) {
writeCharacteristicCallback(Result.failure(error)) writeCharacteristicCallback(Result.failure(error))
} }
for (descriptor in characteristic.descriptors) { val descriptors = cachedDescriptors[characteristic.key] ?: emptyMap()
val descriptorKey = descriptor.hashCode() for (descriptor in descriptors) {
val readDescriptorCallback = readDescriptorCallbacks.remove(descriptorKey) val readDescriptorCallback = readDescriptorCallbacks.remove(descriptor.key)
val writeDescriptorCallback = writeDescriptorCallbacks.remove(descriptorKey) val writeDescriptorCallback = writeDescriptorCallbacks.remove(descriptor.key)
if (readDescriptorCallback != null) { if (readDescriptorCallback != null) {
readDescriptorCallback(Result.failure(error)) readDescriptorCallback(Result.failure(error))
} }
@ -490,6 +484,24 @@ class MyCentralController(private val context: Context, binaryMessenger: BinaryM
val deviceKey = device.hashCode() val deviceKey = device.hashCode()
val callback = discoverGattCallbacks.remove(deviceKey) ?: return val callback = discoverGattCallbacks.remove(deviceKey) ?: return
if (status == BluetoothGatt.GATT_SUCCESS) { if (status == BluetoothGatt.GATT_SUCCESS) {
val cachedServices = mutableMapOf<Int, BluetoothGattService>()
for (service in gatt.services) {
val serviceKey = service.hashCode()
cachedServices[serviceKey] = service
val cachedCharacteristics = mutableMapOf<Int, BluetoothGattCharacteristic>()
for (characteristic in service.characteristics) {
val characteristicKey = characteristic.hashCode()
cachedCharacteristics[characteristicKey] = characteristic
val cachedDescriptors = mutableMapOf<Int, BluetoothGattDescriptor>()
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)) callback(Result.success(Unit))
} else { } else {
val error = IllegalStateException("Discover GATT failed with status: $status") val error = IllegalStateException("Discover GATT failed with status: $status")

View File

@ -483,12 +483,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<Uint8List> readCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey) async { Future<Uint8List> readCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readCharacteristic', codec, 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readCharacteristic', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -510,12 +510,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<void> writeCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async { Future<void> writeCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeCharacteristic', codec, 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeCharacteristic', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -532,12 +532,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<void> notifyCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, bool arg_state) async { Future<void> notifyCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, bool arg_state) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.notifyCharacteristic', codec, 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.notifyCharacteristic', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_state]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_state]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -554,12 +554,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<Uint8List> readDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey) async { Future<Uint8List> readDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readDescriptor', codec, 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readDescriptor', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myDescriptorKey]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -581,12 +581,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<void> writeDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey, Uint8List arg_value) async { Future<void> writeDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey, Uint8List arg_value) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeDescriptor', codec, 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeDescriptor', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myDescriptorKey, arg_value]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey, arg_value]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',

View File

@ -126,18 +126,16 @@ class MyCentralController extends CentralController
await _throwWithoutState(CentralState.poweredOn); await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral; final myPeripheral = peripheral as MyPeripheral;
final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode); final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode);
return myServiceArgses return myServiceArgses.cast<MyGattServiceArgs>().map(
.cast<MyGattServiceArgs>() (myServiceArgs) {
.map( final myService = MyGattService.fromMyArgs(
(myServiceArgs) => _myServices.putIfAbsent(
myServiceArgs.key,
() => MyGattService.fromMyArgs(
myPeripheral, myPeripheral,
myServiceArgs, myServiceArgs,
), );
), _myServices[myService.hashCode] = myService;
) return myService;
.toList(); },
).toList();
} }
@override @override
@ -149,18 +147,16 @@ class MyCentralController extends CentralController
final myCharactersiticArgses = await _myApi.getCharacteristics( final myCharactersiticArgses = await _myApi.getCharacteristics(
myService.hashCode, myService.hashCode,
); );
return myCharactersiticArgses return myCharactersiticArgses.cast<MyGattCharacteristicArgs>().map(
.cast<MyGattCharacteristicArgs>() (myCharacteristicArgs) {
.map( final myCharacteristic = MyGattCharacteristic.fromMyArgs(
(myCharacteristicArgs) => _myCharacteristics.putIfAbsent(
myCharacteristicArgs.key,
() => MyGattCharacteristic.fromMyArgs(
myService, myService,
myCharacteristicArgs, myCharacteristicArgs,
), );
), _myCharacteristics[myCharacteristic.hashCode] = myCharacteristic;
) return myCharacteristic;
.toList(); },
).toList();
} }
@override @override
@ -172,18 +168,16 @@ class MyCentralController extends CentralController
final myDescriptorArgses = await _myApi.getDescriptors( final myDescriptorArgses = await _myApi.getDescriptors(
myCharacteristic.hashCode, myCharacteristic.hashCode,
); );
return myDescriptorArgses return myDescriptorArgses.cast<MyGattDescriptorArgs>().map(
.cast<MyGattDescriptorArgs>() (myDescriptorArgs) {
.map( final myDescriptor = MyGattDescriptor.fromMyArgs(
(myDescriptorArgs) => _myDescriptors.putIfAbsent(
myDescriptorArgs.key,
() => MyGattDescriptor.fromMyArgs(
myCharacteristic, myCharacteristic,
myDescriptorArgs, myDescriptorArgs,
), );
), _myDescriptors[myDescriptor.hashCode] = myDescriptor;
) return myDescriptor;
.toList(); },
).toList();
} }
@override @override
@ -195,6 +189,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
final value = await _myApi.readCharacteristic( final value = await _myApi.readCharacteristic(
myPeripheral.hashCode, myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode, myCharacteristic.hashCode,
); );
return value; return value;
@ -214,6 +209,7 @@ class MyCentralController extends CentralController
final typeNumber = typeArgs.index; final typeNumber = typeArgs.index;
await _myApi.writeCharacteristic( await _myApi.writeCharacteristic(
myPeripheral.hashCode, myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode, myCharacteristic.hashCode,
value, value,
typeNumber, typeNumber,
@ -231,6 +227,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
await _myApi.notifyCharacteristic( await _myApi.notifyCharacteristic(
myPeripheral.hashCode, myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode, myCharacteristic.hashCode,
state, state,
); );
@ -245,6 +242,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
final value = await _myApi.readDescriptor( final value = await _myApi.readDescriptor(
myPeripheral.hashCode, myPeripheral.hashCode,
myCharacteristic.hashCode,
myDescriptor.hashCode, myDescriptor.hashCode,
); );
return value; return value;
@ -262,6 +260,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
await _myApi.writeDescriptor( await _myApi.writeDescriptor(
myPeripheral.hashCode, myPeripheral.hashCode,
myCharacteristic.hashCode,
myDescriptor.hashCode, myDescriptor.hashCode,
value, value,
); );
@ -285,10 +284,8 @@ class MyCentralController extends CentralController
int rssi, int rssi,
MyAdvertisementArgs myAdvertisementArgs, MyAdvertisementArgs myAdvertisementArgs,
) { ) {
final myPeripheral = _myPeripherals.putIfAbsent( final myPeripheral = MyPeripheral.fromMyArgs(myPeripheralArgs);
myPeripheralArgs.key, _myPeripherals[myPeripheral.hashCode] = myPeripheral;
() => MyPeripheral.fromMyArgs(myPeripheralArgs),
);
final advertisement = myAdvertisementArgs.toAdvertisement(); final advertisement = myAdvertisementArgs.toAdvertisement();
final eventArgs = CentralDiscoveredEventArgs( final eventArgs = CentralDiscoveredEventArgs(
myPeripheral, myPeripheral,

View File

@ -29,10 +29,15 @@ abstract class MyCentralControllerHostApi {
List<MyGattCharacteristicArgs> getCharacteristics(int myServiceKey); List<MyGattCharacteristicArgs> getCharacteristics(int myServiceKey);
List<MyGattDescriptorArgs> getDescriptors(int myCharacteristicKey); List<MyGattDescriptorArgs> getDescriptors(int myCharacteristicKey);
@async @async
Uint8List readCharacteristic(int myPeripheralKey, int myCharacteristicKey); Uint8List readCharacteristic(
int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey,
);
@async @async
void writeCharacteristic( void writeCharacteristic(
int myPeripheralKey, int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey, int myCharacteristicKey,
Uint8List value, Uint8List value,
int myTypeNumber, int myTypeNumber,
@ -40,14 +45,20 @@ abstract class MyCentralControllerHostApi {
@async @async
void notifyCharacteristic( void notifyCharacteristic(
int myPeripheralKey, int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey, int myCharacteristicKey,
bool state, bool state,
); );
@async @async
Uint8List readDescriptor(int myPeripheralKey, int myDescriptorKey); Uint8List readDescriptor(
int myPeripheralKey,
int myCharacteristicKey,
int myDescriptorKey,
);
@async @async
void writeDescriptor( void writeDescriptor(
int myPeripheralKey, int myPeripheralKey,
int myCharacteristicKey,
int myDescriptorKey, int myDescriptorKey,
Uint8List value, Uint8List value,
); );

View File

@ -1,6 +1,6 @@
name: bluetooth_low_energy_android name: bluetooth_low_energy_android
description: Android implementation of the bluetooth_low_energy plugin. 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 homepage: https://github.com/yanshouwang/bluetooth_low_energy
environment: environment:
@ -10,7 +10,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
bluetooth_low_energy_platform_interface: ^2.0.0 bluetooth_low_energy_platform_interface: ^2.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -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 ## 2.0.0
- Rewrite the whole project with federated plugins. - Rewrite the whole project with federated plugins.

View File

@ -258,11 +258,11 @@ protocol MyCentralControllerHostApi {
func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs]
func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs]
func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs]
func readCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) func readCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void)
func writeCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result<Void, Error>) -> Void) func writeCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result<Void, Error>) -> Void)
func notifyCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result<Void, Error>) -> Void) func notifyCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result<Void, Error>) -> Void)
func readDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) func readDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void)
func writeDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result<Void, Error>) -> Void) func writeDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result<Void, Error>) -> Void)
} }
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@ -426,8 +426,9 @@ class MyCentralControllerHostApiSetup {
readCharacteristicChannel.setMessageHandler { message, reply in readCharacteristicChannel.setMessageHandler { message, reply in
let args = message as! [Any?] let args = message as! [Any?]
let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) 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 myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
api.readCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg) { result in 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 { switch result {
case .success(let res): case .success(let res):
reply(wrapResult(res)) reply(wrapResult(res))
@ -444,10 +445,11 @@ class MyCentralControllerHostApiSetup {
writeCharacteristicChannel.setMessageHandler { message, reply in writeCharacteristicChannel.setMessageHandler { message, reply in
let args = message as! [Any?] let args = message as! [Any?]
let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) 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 myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
let valueArg = args[2] as! FlutterStandardTypedData let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32)
let myTypeNumberArg = args[3] is Int64 ? args[3] as! Int64 : Int64(args[3] as! Int32) let valueArg = args[3] as! FlutterStandardTypedData
api.writeCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, value: valueArg, myTypeNumber: myTypeNumberArg) { result in 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 { switch result {
case .success: case .success:
reply(wrapResult(nil)) reply(wrapResult(nil))
@ -464,9 +466,10 @@ class MyCentralControllerHostApiSetup {
notifyCharacteristicChannel.setMessageHandler { message, reply in notifyCharacteristicChannel.setMessageHandler { message, reply in
let args = message as! [Any?] let args = message as! [Any?]
let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) 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 myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
let stateArg = args[2] as! Bool let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32)
api.notifyCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, state: stateArg) { result in let stateArg = args[3] as! Bool
api.notifyCharacteristic(myPeripheralKey: myPeripheralKeyArg, myServiceKey: myServiceKeyArg, myCharacteristicKey: myCharacteristicKeyArg, state: stateArg) { result in
switch result { switch result {
case .success: case .success:
reply(wrapResult(nil)) reply(wrapResult(nil))
@ -483,8 +486,9 @@ class MyCentralControllerHostApiSetup {
readDescriptorChannel.setMessageHandler { message, reply in readDescriptorChannel.setMessageHandler { message, reply in
let args = message as! [Any?] let args = message as! [Any?]
let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) 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 myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
api.readDescriptor(myPeripheralKey: myPeripheralKeyArg, myDescriptorKey: myDescriptorKeyArg) { result in 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 { switch result {
case .success(let res): case .success(let res):
reply(wrapResult(res)) reply(wrapResult(res))
@ -501,9 +505,10 @@ class MyCentralControllerHostApiSetup {
writeDescriptorChannel.setMessageHandler { message, reply in writeDescriptorChannel.setMessageHandler { message, reply in
let args = message as! [Any?] let args = message as! [Any?]
let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) 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 myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
let valueArg = args[2] as! FlutterStandardTypedData let myDescriptorKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32)
api.writeDescriptor(myPeripheralKey: myPeripheralKeyArg, myDescriptorKey: myDescriptorKeyArg, value: valueArg) { result in let valueArg = args[3] as! FlutterStandardTypedData
api.writeDescriptor(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, myDescriptorKey: myDescriptorKeyArg, value: valueArg) { result in
switch result { switch result {
case .success: case .success:
reply(wrapResult(nil)) reply(wrapResult(nil))

View File

@ -19,10 +19,10 @@ class MyCentralController: MyCentralControllerHostApi {
private lazy var myPeripheralDelegate = MyPeripheralDelegate(self) private lazy var myPeripheralDelegate = MyPeripheralDelegate(self)
private let centralManager = CBCentralManager() private let centralManager = CBCentralManager()
private var peripherals = [Int: CBPeripheral]() private var cachedPeripherals = [Int: CBPeripheral]()
private var services = [Int: CBService]() private var cachedServices = [Int: [Int: CBService]]()
private var characteristics = [Int: CBCharacteristic]() private var cachedCharacteristics = [Int: [Int: CBCharacteristic]]()
private var descriptors = [Int: CBDescriptor]() private var cachedDescriptors = [Int: [Int: CBDescriptor]]()
var setUpCompletion: ((Result<MyCentralControllerArgs, Error>) -> Void)? var setUpCompletion: ((Result<MyCentralControllerArgs, Error>) -> Void)?
var connectCompletions = [Int: (Result<Void, Error>) -> Void]() var connectCompletions = [Int: (Result<Void, Error>) -> Void]()
@ -61,16 +61,16 @@ class MyCentralController: MyCentralControllerHostApi {
if(centralManager.isScanning) { if(centralManager.isScanning) {
centralManager.stopScan() centralManager.stopScan()
} }
for peripheral in peripherals.values { for peripheral in cachedPeripherals.values {
peripheral.delegate = nil peripheral.delegate = nil
if peripheral.state != .disconnected { if peripheral.state != .disconnected {
centralManager.cancelPeripheralConnection(peripheral) centralManager.cancelPeripheralConnection(peripheral)
} }
} }
peripherals.removeAll() cachedPeripherals.removeAll()
services.removeAll() cachedServices.removeAll()
characteristics.removeAll() cachedCharacteristics.removeAll()
descriptors.removeAll() cachedDescriptors.removeAll()
} }
func startDiscovery() throws { func startDiscovery() throws {
@ -89,7 +89,7 @@ class MyCentralController: MyCentralControllerHostApi {
if unfinishedCompletion != nil { if unfinishedCompletion != nil {
throw MyError.illegalState throw MyError.illegalState
} }
guard let peripheral = peripherals[peripheralKey] else { guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
centralManager.connect(peripheral) centralManager.connect(peripheral)
@ -106,7 +106,7 @@ class MyCentralController: MyCentralControllerHostApi {
if unfinishedCompletion != nil { if unfinishedCompletion != nil {
throw MyError.illegalState throw MyError.illegalState
} }
guard let peripheral = peripherals[peripheralKey] else { guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
centralManager.cancelPeripheralConnection(peripheral) centralManager.cancelPeripheralConnection(peripheral)
@ -123,7 +123,7 @@ class MyCentralController: MyCentralControllerHostApi {
if unfinishedCompletion != nil { if unfinishedCompletion != nil {
throw MyError.illegalState throw MyError.illegalState
} }
guard let peripheral = peripherals[peripheralKey] else { guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
peripheral.discoverServices(nil) peripheral.discoverServices(nil)
@ -135,53 +135,42 @@ class MyCentralController: MyCentralControllerHostApi {
func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] { func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] {
let peripheralKey = Int(myPeripheralKey) let peripheralKey = Int(myPeripheralKey)
guard let peripheral = peripherals[peripheralKey] else { guard let services = cachedServices[peripheralKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
let services = peripheral.services ?? [] return services.map { (key, service) in
return services.map { service in
let serviceKey = service.hash
if self.services[serviceKey] == nil {
self.services[serviceKey] = service
}
return service.toMyArgs() return service.toMyArgs()
} }
} }
func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] { func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] {
let serviceKey = Int(myServiceKey) let serviceKey = Int(myServiceKey)
guard let service = services[serviceKey] else { guard let characteristics = cachedCharacteristics[serviceKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
let characteristics = service.characteristics ?? [] return characteristics.map { (key, characteristic) in
return characteristics.map { characteristic in
let characteristicKey = characteristic.hash
if self.characteristics[characteristicKey] == nil {
self.characteristics[characteristicKey] = characteristic
}
return characteristic.toMyArgs() return characteristic.toMyArgs()
} }
} }
func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] { func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] {
let characteristicKey = Int(myCharacteristicKey) let characteristicKey = Int(myCharacteristicKey)
guard let characteristic = characteristics[characteristicKey] else { guard let descriptors = cachedDescriptors[characteristicKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
let descritors = characteristic.descriptors ?? [] return descriptors.map { (key, descriptor) in
return descritors.map { descriptor in
let descriptorKey = descriptor.hash
if self.descriptors[descriptorKey] == nil {
self.descriptors[descriptorKey] = descriptor
}
return descriptor.toMyArgs() return descriptor.toMyArgs()
} }
} }
func readCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) { func readCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
do { do {
let peripheralKey = Int(myPeripheralKey) 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 throw MyError.illegalArgument
} }
let characteristicKey = Int(myCharacteristicKey) 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, Error>) -> Void) { func writeCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
do { do {
let peripheralKey = Int(myPeripheralKey) 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 throw MyError.illegalArgument
} }
let characteristicKey = Int(myCharacteristicKey) let characteristicKey = Int(myCharacteristicKey)
@ -226,10 +219,14 @@ class MyCentralController: MyCentralControllerHostApi {
} }
} }
func notifyCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result<Void, Error>) -> Void) { func notifyCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result<Void, Error>) -> Void) {
do { do {
let peripheralKey = Int(myPeripheralKey) 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 throw MyError.illegalArgument
} }
let characteristicKey = Int(myCharacteristicKey) let characteristicKey = Int(myCharacteristicKey)
@ -247,10 +244,14 @@ class MyCentralController: MyCentralControllerHostApi {
} }
} }
func readDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) { func readDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
do { do {
let peripheralKey = Int(myPeripheralKey) 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 throw MyError.illegalArgument
} }
let descriptorKey = Int(myDescriptorKey) let descriptorKey = Int(myDescriptorKey)
@ -268,10 +269,14 @@ class MyCentralController: MyCentralControllerHostApi {
} }
} }
func writeDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result<Void, Error>) -> Void) { func writeDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result<Void, Error>) -> Void) {
do { do {
let peripheralKey = Int(myPeripheralKey) 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 throw MyError.illegalArgument
} }
let descriptorKey = Int(myDescriptorKey) let descriptorKey = Int(myDescriptorKey)
@ -307,9 +312,9 @@ class MyCentralController: MyCentralControllerHostApi {
func didDiscover(_ peripheral: CBPeripheral, _ advertisementData: [String : Any], _ rssiNumber: NSNumber) { func didDiscover(_ peripheral: CBPeripheral, _ advertisementData: [String : Any], _ rssiNumber: NSNumber) {
let peripheralKey = peripheral.hash let peripheralKey = peripheral.hash
if peripherals[peripheralKey] == nil { if cachedPeripherals[peripheralKey] == nil {
peripheral.delegate = myPeripheralDelegate peripheral.delegate = myPeripheralDelegate
peripherals[peripheralKey] = peripheral cachedPeripherals[peripheralKey] = peripheral
} }
let myPeripheralArgs = peripheral.toMyArgs() let myPeripheralArgs = peripheral.toMyArgs()
let rssi = rssiNumber.int64Value let rssi = rssiNumber.int64Value
@ -368,26 +373,24 @@ class MyCentralController: MyCentralControllerHostApi {
let myPeripheralKey = Int64(peripheralKey) let myPeripheralKey = Int64(peripheralKey)
let discoverGattCompletion = discoverGattCompletions.removeValue(forKey: peripheralKey) let discoverGattCompletion = discoverGattCompletions.removeValue(forKey: peripheralKey)
if discoverGattCompletion != nil { 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 { for service in services {
let characteristics = service.characteristics ?? [] let characteristics = cachedCharacteristics[service.key] ?? [:]
for characteristic in characteristics { for characteristic in characteristics {
let characteristicKey = characteristic.hash let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristic.key)
let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristicKey) let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristic.key)
let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristicKey)
if readCharacteristicCompletion != nil { if readCharacteristicCompletion != nil {
readCharacteristicCompletion!(.failure(MyError.illegalState)) readCharacteristicCompletion!(.failure(MyError.illegalState))
} }
if writeCharacteristicCompletion != nil { if writeCharacteristicCompletion != nil {
writeCharacteristicCompletion!(.failure(MyError.illegalState)) writeCharacteristicCompletion!(.failure(MyError.illegalState))
} }
let descriptors = characteristic.descriptors ?? [] let descriptors = cachedDescriptors[characteristic.key] ?? [:]
for descriptor in descriptors { for descriptor in descriptors {
let descriptorKey = descriptor.hash let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptor.key)
let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptorKey) let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptor.key)
let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptorKey)
if readDescriptorCompletion != nil { if readDescriptorCompletion != nil {
readDescriptorCompletion!(.failure(MyError.illegalState)) readDescriptorCompletion!(.failure(MyError.illegalState))
} }
@ -411,37 +414,28 @@ class MyCentralController: MyCentralControllerHostApi {
func didDiscoverServices(_ peripheral: CBPeripheral, _ error: Error?) { func didDiscoverServices(_ peripheral: CBPeripheral, _ error: Error?) {
let peripheralKey = peripheral.hash let peripheralKey = peripheral.hash
guard let completion = discoverGattCompletions[peripheralKey] else {
return
}
if error == nil { if error == nil {
var services = peripheral.services ?? [] var services = peripheral.services ?? []
if services.isEmpty { if services.isEmpty {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
completion(.success(()))
} else { } else {
let service = services.removeFirst() let service = services.removeFirst()
unfinishedServices[peripheralKey] = services unfinishedServices[peripheralKey] = services
peripheral.discoverCharacteristics(nil, for: service) peripheral.discoverCharacteristics(nil, for: service)
} }
} else { } else {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
completion(.failure(error!))
} }
} }
func didDiscoverCharacteristics(_ peripheral: CBPeripheral, _ service: CBService, _ error: Error?) { func didDiscoverCharacteristics(_ peripheral: CBPeripheral, _ service: CBService, _ error: Error?) {
let peripheralKey = peripheral.hash let peripheralKey = peripheral.hash
guard let completion = discoverGattCompletions[peripheralKey] else {
return
}
if error == nil { if error == nil {
var characteristics = service.characteristics ?? [] var characteristics = service.characteristics ?? []
if characteristics.isEmpty { if characteristics.isEmpty {
var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? [] var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? []
if services.isEmpty { if services.isEmpty {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
completion(.success(()))
} else { } else {
let service = services.removeFirst() let service = services.removeFirst()
unfinishedServices[peripheralKey] = services unfinishedServices[peripheralKey] = services
@ -453,24 +447,18 @@ class MyCentralController: MyCentralControllerHostApi {
peripheral.discoverDescriptors(for: characteristic) peripheral.discoverDescriptors(for: characteristic)
} }
} else { } else {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
unfinishedServices.removeValue(forKey: peripheralKey)
completion(.failure(error!))
} }
} }
func didDiscoverDescriptors(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic, _ error: Error?) { func didDiscoverDescriptors(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic, _ error: Error?) {
let peripheralKey = peripheral.hash let peripheralKey = peripheral.hash
guard let completion = discoverGattCompletions[peripheralKey] else {
return
}
if error == nil { if error == nil {
var characteristics = unfinishedCharacteristics.removeValue(forKey: peripheralKey) ?? [] var characteristics = unfinishedCharacteristics.removeValue(forKey: peripheralKey) ?? []
if (characteristics.isEmpty) { if (characteristics.isEmpty) {
var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? [] var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? []
if services.isEmpty { if services.isEmpty {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
completion(.success(()))
} else { } else {
let service = services.removeFirst() let service = services.removeFirst()
unfinishedServices[peripheralKey] = services unfinishedServices[peripheralKey] = services
@ -482,9 +470,41 @@ class MyCentralController: MyCentralControllerHostApi {
peripheral.discoverDescriptors(for: characteristic) peripheral.discoverDescriptors(for: characteristic)
} }
} else { } else {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
}
}
private func didDiscoverGATT(_ peripheral: CBPeripheral, _ error: Error?) {
let peripheralKey = peripheral.hash
unfinishedServices.removeValue(forKey: peripheralKey) unfinishedServices.removeValue(forKey: peripheralKey)
unfinishedCharacteristics.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!)) completion(.failure(error!))
} }
} }

View File

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

View File

@ -483,12 +483,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<Uint8List> readCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey) async { Future<Uint8List> readCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.readCharacteristic', codec, 'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.readCharacteristic', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -510,12 +510,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<void> writeCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async { Future<void> writeCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.writeCharacteristic', codec, 'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.writeCharacteristic', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -532,12 +532,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<void> notifyCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, bool arg_state) async { Future<void> notifyCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, bool arg_state) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.notifyCharacteristic', codec, 'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.notifyCharacteristic', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_state]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_state]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -554,12 +554,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<Uint8List> readDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey) async { Future<Uint8List> readDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.readDescriptor', codec, 'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.readDescriptor', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myDescriptorKey]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -581,12 +581,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<void> writeDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey, Uint8List arg_value) async { Future<void> writeDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey, Uint8List arg_value) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.writeDescriptor', codec, 'dev.flutter.pigeon.bluetooth_low_energy_ios.MyCentralControllerHostApi.writeDescriptor', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myDescriptorKey, arg_value]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey, arg_value]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',

View File

@ -126,18 +126,16 @@ class MyCentralController extends CentralController
await _throwWithoutState(CentralState.poweredOn); await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral; final myPeripheral = peripheral as MyPeripheral;
final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode); final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode);
return myServiceArgses return myServiceArgses.cast<MyGattServiceArgs>().map(
.cast<MyGattServiceArgs>() (myServiceArgs) {
.map( final myService = MyGattService.fromMyArgs(
(myServiceArgs) => _myServices.putIfAbsent(
myServiceArgs.key,
() => MyGattService.fromMyArgs(
myPeripheral, myPeripheral,
myServiceArgs, myServiceArgs,
), );
), _myServices[myService.hashCode] = myService;
) return myService;
.toList(); },
).toList();
} }
@override @override
@ -149,18 +147,16 @@ class MyCentralController extends CentralController
final myCharactersiticArgses = await _myApi.getCharacteristics( final myCharactersiticArgses = await _myApi.getCharacteristics(
myService.hashCode, myService.hashCode,
); );
return myCharactersiticArgses return myCharactersiticArgses.cast<MyGattCharacteristicArgs>().map(
.cast<MyGattCharacteristicArgs>() (myCharacteristicArgs) {
.map( final myCharacteristic = MyGattCharacteristic.fromMyArgs(
(myCharacteristicArgs) => _myCharacteristics.putIfAbsent(
myCharacteristicArgs.key,
() => MyGattCharacteristic.fromMyArgs(
myService, myService,
myCharacteristicArgs, myCharacteristicArgs,
), );
), _myCharacteristics[myCharacteristic.hashCode] = myCharacteristic;
) return myCharacteristic;
.toList(); },
).toList();
} }
@override @override
@ -172,18 +168,16 @@ class MyCentralController extends CentralController
final myDescriptorArgses = await _myApi.getDescriptors( final myDescriptorArgses = await _myApi.getDescriptors(
myCharacteristic.hashCode, myCharacteristic.hashCode,
); );
return myDescriptorArgses return myDescriptorArgses.cast<MyGattDescriptorArgs>().map(
.cast<MyGattDescriptorArgs>() (myDescriptorArgs) {
.map( final myDescriptor = MyGattDescriptor.fromMyArgs(
(myDescriptorArgs) => _myDescriptors.putIfAbsent(
myDescriptorArgs.key,
() => MyGattDescriptor.fromMyArgs(
myCharacteristic, myCharacteristic,
myDescriptorArgs, myDescriptorArgs,
), );
), _myDescriptors[myDescriptor.hashCode] = myDescriptor;
) return myDescriptor;
.toList(); },
).toList();
} }
@override @override
@ -196,6 +190,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
final value = await _myApi.readCharacteristic( final value = await _myApi.readCharacteristic(
myPeripheral.hashCode, myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode, myCharacteristic.hashCode,
); );
return value; return value;
@ -215,6 +210,7 @@ class MyCentralController extends CentralController
final typeNumber = typeArgs.index; final typeNumber = typeArgs.index;
await _myApi.writeCharacteristic( await _myApi.writeCharacteristic(
myPeripheral.hashCode, myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode, myCharacteristic.hashCode,
value, value,
typeNumber, typeNumber,
@ -232,6 +228,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
await _myApi.notifyCharacteristic( await _myApi.notifyCharacteristic(
myPeripheral.hashCode, myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode, myCharacteristic.hashCode,
state, state,
); );
@ -246,6 +243,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
final value = await _myApi.readDescriptor( final value = await _myApi.readDescriptor(
myPeripheral.hashCode, myPeripheral.hashCode,
myCharacteristic.hashCode,
myDescriptor.hashCode, myDescriptor.hashCode,
); );
return value; return value;
@ -263,6 +261,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
await _myApi.writeDescriptor( await _myApi.writeDescriptor(
myPeripheral.hashCode, myPeripheral.hashCode,
myCharacteristic.hashCode,
myDescriptor.hashCode, myDescriptor.hashCode,
value, value,
); );
@ -286,10 +285,8 @@ class MyCentralController extends CentralController
int rssi, int rssi,
MyAdvertisementArgs myAdvertisementArgs, MyAdvertisementArgs myAdvertisementArgs,
) { ) {
final myPeripheral = _myPeripherals.putIfAbsent( final myPeripheral = MyPeripheral.fromMyArgs(myPeripheralArgs);
myPeripheralArgs.key, _myPeripherals[myPeripheral.hashCode] = myPeripheral;
() => MyPeripheral.fromMyArgs(myPeripheralArgs),
);
final advertisement = myAdvertisementArgs.toAdvertisement(); final advertisement = myAdvertisementArgs.toAdvertisement();
final eventArgs = CentralDiscoveredEventArgs( final eventArgs = CentralDiscoveredEventArgs(
myPeripheral, myPeripheral,

View File

@ -25,10 +25,15 @@ abstract class MyCentralControllerHostApi {
List<MyGattCharacteristicArgs> getCharacteristics(int myServiceKey); List<MyGattCharacteristicArgs> getCharacteristics(int myServiceKey);
List<MyGattDescriptorArgs> getDescriptors(int myCharacteristicKey); List<MyGattDescriptorArgs> getDescriptors(int myCharacteristicKey);
@async @async
Uint8List readCharacteristic(int myPeripheralKey, int myCharacteristicKey); Uint8List readCharacteristic(
int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey,
);
@async @async
void writeCharacteristic( void writeCharacteristic(
int myPeripheralKey, int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey, int myCharacteristicKey,
Uint8List value, Uint8List value,
int myTypeNumber, int myTypeNumber,
@ -36,14 +41,20 @@ abstract class MyCentralControllerHostApi {
@async @async
void notifyCharacteristic( void notifyCharacteristic(
int myPeripheralKey, int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey, int myCharacteristicKey,
bool state, bool state,
); );
@async @async
Uint8List readDescriptor(int myPeripheralKey, int myDescriptorKey); Uint8List readDescriptor(
int myPeripheralKey,
int myCharacteristicKey,
int myDescriptorKey,
);
@async @async
void writeDescriptor( void writeDescriptor(
int myPeripheralKey, int myPeripheralKey,
int myCharacteristicKey,
int myDescriptorKey, int myDescriptorKey,
Uint8List value, Uint8List value,
); );

View File

@ -1,6 +1,6 @@
name: bluetooth_low_energy_ios name: bluetooth_low_energy_ios
description: iOS implementation of the bluetooth_low_energy plugin. 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 homepage: https://github.com/yanshouwang/bluetooth_low_energy
environment: environment:
@ -10,7 +10,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
bluetooth_low_energy_platform_interface: ^2.0.0 bluetooth_low_energy_platform_interface: ^2.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -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 ## 2.0.0
- Rewrite the whole project with federated plugins. - Rewrite the whole project with federated plugins.

View File

@ -13,10 +13,11 @@ extension MyBlueZDevice on BlueZDevice {
BlueZUUID get uuid { BlueZUUID get uuid {
final node = address.replaceAll(':', ''); final node = address.replaceAll(':', '');
// We don't know the timestamp of the bluetooth device, use nil UUID as prefix. // 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 { Advertisement get advertisement {
final name = this.name.isNotEmpty ? this.name : null;
final manufacturerSpecificData = manufacturerData.map((key, value) { final manufacturerSpecificData = manufacturerData.map((key, value) {
final id = key.id; final id = key.id;
final data = Uint8List.fromList(value); final data = Uint8List.fromList(value);

View File

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; 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:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'package:bluez/bluez.dart'; import 'package:bluez/bluez.dart';
@ -17,7 +18,7 @@ class MyCentralController extends CentralController {
_discoveredController = StreamController.broadcast(), _discoveredController = StreamController.broadcast(),
_peripheralStateChangedController = StreamController.broadcast(), _peripheralStateChangedController = StreamController.broadcast(),
_characteristicValueChangedController = StreamController.broadcast(), _characteristicValueChangedController = StreamController.broadcast(),
_servicesResolvedController = StreamController.broadcast(), _myPeripheralDiscoveredController = StreamController.broadcast(),
_devicePropertiesChangedSubscriptions = {}, _devicePropertiesChangedSubscriptions = {},
_characteristicPropertiesChangedSubscriptions = {}, _characteristicPropertiesChangedSubscriptions = {},
_myPeripherals = {}, _myPeripherals = {},
@ -33,15 +34,16 @@ class MyCentralController extends CentralController {
_peripheralStateChangedController; _peripheralStateChangedController;
final StreamController<GattCharacteristicValueChangedEventArgs> final StreamController<GattCharacteristicValueChangedEventArgs>
_characteristicValueChangedController; _characteristicValueChangedController;
final StreamController<int> _servicesResolvedController; final StreamController<MyPeripheralDiscoveredEventArgs>
_myPeripheralDiscoveredController;
final Map<int, StreamSubscription<List<String>>> final Map<int, StreamSubscription<List<String>>>
_devicePropertiesChangedSubscriptions; _devicePropertiesChangedSubscriptions;
final Map<int, StreamSubscription<List<String>>> final Map<int, StreamSubscription<List<String>>>
_characteristicPropertiesChangedSubscriptions; _characteristicPropertiesChangedSubscriptions;
final Map<int, MyPeripheral> _myPeripherals; final Map<int, MyPeripheral> _myPeripherals;
final Map<int, MyGattService> _myServices; final Map<int, Map<int, MyGattService>> _myServices;
final Map<int, MyGattCharacteristic> _myCharacteristics; final Map<int, Map<int, MyGattCharacteristic>> _myCharacteristics;
final Map<int, MyGattDescriptor> _myDescriptors; final Map<int, Map<int, MyGattDescriptor>> _myDescriptors;
BlueZAdapter get _adapter => _client.adapters.first; BlueZAdapter get _adapter => _client.adapters.first;
CentralState _state; CentralState _state;
@ -61,7 +63,8 @@ class MyCentralController extends CentralController {
Stream<GattCharacteristicValueChangedEventArgs> Stream<GattCharacteristicValueChangedEventArgs>
get characteristicValueChanged => get characteristicValueChanged =>
_characteristicValueChangedController.stream; _characteristicValueChangedController.stream;
Stream<int> get _servicesResolved => _servicesResolvedController.stream; Stream<MyPeripheralDiscoveredEventArgs> get _myPeripheralDiscovered =>
_myPeripheralDiscoveredController.stream;
late StreamSubscription<List<String>> _adapterPropertiesChangedSubscription; late StreamSubscription<List<String>> _adapterPropertiesChangedSubscription;
late StreamSubscription<BlueZDevice> _deviceAddedSubscription; late StreamSubscription<BlueZDevice> _deviceAddedSubscription;
@ -91,7 +94,7 @@ class MyCentralController extends CentralController {
return; return;
} }
for (var device in _client.devices) { for (var device in _client.devices) {
if (device.adapter != _adapter) { if (device.adapter.address != _adapter.address) {
continue; continue;
} }
_beginDevicePropertiesChangedListener(device); _beginDevicePropertiesChangedListener(device);
@ -120,7 +123,7 @@ class MyCentralController extends CentralController {
_myCharacteristics.clear(); _myCharacteristics.clear();
_myDescriptors.clear(); _myDescriptors.clear();
for (var device in _client.devices) { for (var device in _client.devices) {
if (device.adapter != _adapter) { if (device.adapter.address != _adapter.address) {
continue; continue;
} }
_endDevicePropertiesChangedListener(device); _endDevicePropertiesChangedListener(device);
@ -171,8 +174,8 @@ class MyCentralController extends CentralController {
if (device.servicesResolved) { if (device.servicesResolved) {
return; return;
} }
await _servicesResolved.firstWhere( await _myPeripheralDiscovered.firstWhere(
(hashCode) => hashCode == peripheral.hashCode, (eventArgs) => eventArgs.myPeripheral == myPeripheral,
); );
} }
@ -180,15 +183,11 @@ class MyCentralController extends CentralController {
Future<List<GattService>> getServices(Peripheral peripheral) async { Future<List<GattService>> getServices(Peripheral peripheral) async {
await _throwWithoutState(CentralState.poweredOn); await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral; final myPeripheral = peripheral as MyPeripheral;
final blueZDevice = myPeripheral.device; final myServices = _myServices[myPeripheral.hashCode];
return blueZDevice.gattServices if (myServices == null) {
.map( throw ArgumentError();
(service) => _myServices.putIfAbsent( }
service.hashCode, return myServices.values.toList();
() => MyGattService(service),
),
)
.toList();
} }
@override @override
@ -197,15 +196,11 @@ class MyCentralController extends CentralController {
) async { ) async {
await _throwWithoutState(CentralState.poweredOn); await _throwWithoutState(CentralState.poweredOn);
final myService = service as MyGattService; final myService = service as MyGattService;
final blueZService = myService.service; final myCharacteristics = _myCharacteristics[myService.hashCode];
return blueZService.characteristics if (myCharacteristics == null) {
.map( throw ArgumentError();
(characteristic) => _myCharacteristics.putIfAbsent( }
characteristic.hashCode, return myCharacteristics.values.toList();
() => MyGattCharacteristic(characteristic),
),
)
.toList();
} }
@override @override
@ -214,15 +209,11 @@ class MyCentralController extends CentralController {
) async { ) async {
await _throwWithoutState(CentralState.poweredOn); await _throwWithoutState(CentralState.poweredOn);
final myCharacteristic = characteristic as MyGattCharacteristic; final myCharacteristic = characteristic as MyGattCharacteristic;
final blueZCharacteristic = myCharacteristic.characteristic; final myDescriptors = _myDescriptors[myCharacteristic.hashCode];
return blueZCharacteristic.descriptors if (myDescriptors == null) {
.map( throw ArgumentError();
(descriptor) => _myDescriptors.putIfAbsent( }
descriptor.hashCode, return myDescriptors.values.toList();
() => MyGattDescriptor(descriptor),
),
)
.toList();
} }
@override @override
@ -305,7 +296,7 @@ class MyCentralController extends CentralController {
} }
void _onDeviceAdded(BlueZDevice device) { void _onDeviceAdded(BlueZDevice device) {
if (device.adapter != _adapter) { if (device.adapter.address != _adapter.address) {
return; return;
} }
_onDiscovered(device); _onDiscovered(device);
@ -313,17 +304,15 @@ class MyCentralController extends CentralController {
} }
void _onDeviceRemoved(BlueZDevice device) { void _onDeviceRemoved(BlueZDevice device) {
if (device.adapter != _adapter) { if (device.adapter.address != _adapter.address) {
return; return;
} }
_endDevicePropertiesChangedListener(device); _endDevicePropertiesChangedListener(device);
} }
void _onDiscovered(BlueZDevice device) { void _onDiscovered(BlueZDevice device) {
final myPeripheral = _myPeripherals.putIfAbsent( final myPeripheral = MyPeripheral(device);
device.hashCode, _myPeripherals[myPeripheral.hashCode] = myPeripheral;
() => MyPeripheral(device),
);
final rssi = device.rssi; final rssi = device.rssi;
final advertisement = device.advertisement; final advertisement = device.advertisement;
final eventArgs = CentralDiscoveredEventArgs( final eventArgs = CentralDiscoveredEventArgs(
@ -335,11 +324,6 @@ class MyCentralController extends CentralController {
} }
void _beginDevicePropertiesChangedListener(BlueZDevice device) { void _beginDevicePropertiesChangedListener(BlueZDevice device) {
for (var service in device.gattServices) {
for (var characteristic in service.characteristics) {
_beginCharacteristicPropertiesChangedListener(characteristic);
}
}
final subscription = device.propertiesChanged.listen((properties) { final subscription = device.propertiesChanged.listen((properties) {
for (var property in properties) { for (var property in properties) {
switch (property) { switch (property) {
@ -360,12 +344,33 @@ class MyCentralController extends CentralController {
break; break;
case 'ServicesResolved': case 'ServicesResolved':
if (device.servicesResolved) { if (device.servicesResolved) {
final myPeripheral =
_myPeripherals[device.hashCode] as MyPeripheral;
final myServices = <int, MyGattService>{};
for (var service in device.gattServices) { for (var service in device.gattServices) {
final myService = MyGattService(service);
myServices[myService.hashCode] = myService;
final myCharacteristics = <int, MyGattCharacteristic>{};
for (var characteristic in service.characteristics) { for (var characteristic in service.characteristics) {
_beginCharacteristicPropertiesChangedListener(characteristic); final myCharacteristic = MyGattCharacteristic(characteristic);
myCharacteristics[myCharacteristic.hashCode] =
myCharacteristic;
_beginCharacteristicPropertiesChangedListener(
service,
characteristic,
);
final myDescriptors = <int, MyGattDescriptor>{};
for (var descriptor in characteristic.descriptors) {
final myDescriptor = MyGattDescriptor(descriptor);
myDescriptors[myDescriptor.hashCode] = myDescriptor;
} }
_myDescriptors[myCharacteristic.hashCode] = myDescriptors;
} }
_servicesResolvedController.add(device.hashCode); _myCharacteristics[myService.hashCode] = myCharacteristics;
}
_myServices[myPeripheral.hashCode] = myServices;
final eventArgs = MyPeripheralDiscoveredEventArgs(myPeripheral);
_myPeripheralDiscoveredController.add(eventArgs);
} }
break; break;
default: default:
@ -389,16 +394,19 @@ class MyCentralController extends CentralController {
} }
void _beginCharacteristicPropertiesChangedListener( void _beginCharacteristicPropertiesChangedListener(
BlueZGattService service,
BlueZGattCharacteristic characteristic, BlueZGattCharacteristic characteristic,
) { ) {
final subscription = characteristic.propertiesChanged.listen((properties) { final subscription = characteristic.propertiesChanged.listen((properties) {
for (var property in properties) { for (var property in properties) {
switch (property) { switch (property) {
case 'Value': case 'Value':
final instance = _myCharacteristics[characteristic.hashCode]; final myCharacteristics = _myCharacteristics[service.hashCode];
final myCharacteristic = instance is MyGattCharacteristic if (myCharacteristics == null) {
? instance throw ArgumentError();
: MyGattCharacteristic(characteristic); }
final myCharacteristic = myCharacteristics[characteristic.hashCode]
as MyGattCharacteristic;
final value = Uint8List.fromList(characteristic.value); final value = Uint8List.fromList(characteristic.value);
final eventArgs = GattCharacteristicValueChangedEventArgs( final eventArgs = GattCharacteristicValueChangedEventArgs(
myCharacteristic, myCharacteristic,

View File

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

View File

@ -1,6 +1,6 @@
name: bluetooth_low_energy_linux name: bluetooth_low_energy_linux
description: Linux implementation of the bluetooth_low_energy plugin. 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 homepage: https://github.com/yanshouwang/bluetooth_low_energy
environment: environment:
@ -10,7 +10,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
bluetooth_low_energy_platform_interface: ^2.0.0 bluetooth_low_energy_platform_interface: ^2.0.1
bluez: ^0.8.1 bluez: ^0.8.1
dev_dependencies: dev_dependencies:

View File

@ -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 ## 2.0.0
- Rewrite the whole project with federated plugins. - Rewrite the whole project with federated plugins.

View File

@ -483,12 +483,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<Uint8List> readCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey) async { Future<Uint8List> readCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.readCharacteristic', codec, 'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.readCharacteristic', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -510,12 +510,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<void> writeCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async { Future<void> writeCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.writeCharacteristic', codec, 'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.writeCharacteristic', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -532,12 +532,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<void> notifyCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, bool arg_state) async { Future<void> notifyCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, bool arg_state) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.notifyCharacteristic', codec, 'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.notifyCharacteristic', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_state]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_state]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -554,12 +554,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<Uint8List> readDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey) async { Future<Uint8List> readDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.readDescriptor', codec, 'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.readDescriptor', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myDescriptorKey]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -581,12 +581,12 @@ class MyCentralControllerHostApi {
} }
} }
Future<void> writeDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey, Uint8List arg_value) async { Future<void> writeDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey, Uint8List arg_value) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.writeDescriptor', codec, 'dev.flutter.pigeon.bluetooth_low_energy_macos.MyCentralControllerHostApi.writeDescriptor', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myDescriptorKey, arg_value]) as List<Object?>?; await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey, arg_value]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',

View File

@ -126,18 +126,16 @@ class MyCentralController extends CentralController
await _throwWithoutState(CentralState.poweredOn); await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral; final myPeripheral = peripheral as MyPeripheral;
final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode); final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode);
return myServiceArgses return myServiceArgses.cast<MyGattServiceArgs>().map(
.cast<MyGattServiceArgs>() (myServiceArgs) {
.map( final myService = MyGattService.fromMyArgs(
(myServiceArgs) => _myServices.putIfAbsent(
myServiceArgs.key,
() => MyGattService.fromMyArgs(
myPeripheral, myPeripheral,
myServiceArgs, myServiceArgs,
), );
), _myServices[myService.hashCode] = myService;
) return myService;
.toList(); },
).toList();
} }
@override @override
@ -149,18 +147,16 @@ class MyCentralController extends CentralController
final myCharactersiticArgses = await _myApi.getCharacteristics( final myCharactersiticArgses = await _myApi.getCharacteristics(
myService.hashCode, myService.hashCode,
); );
return myCharactersiticArgses return myCharactersiticArgses.cast<MyGattCharacteristicArgs>().map(
.cast<MyGattCharacteristicArgs>() (myCharacteristicArgs) {
.map( final myCharacteristic = MyGattCharacteristic.fromMyArgs(
(myCharacteristicArgs) => _myCharacteristics.putIfAbsent(
myCharacteristicArgs.key,
() => MyGattCharacteristic.fromMyArgs(
myService, myService,
myCharacteristicArgs, myCharacteristicArgs,
), );
), _myCharacteristics[myCharacteristic.hashCode] = myCharacteristic;
) return myCharacteristic;
.toList(); },
).toList();
} }
@override @override
@ -172,18 +168,16 @@ class MyCentralController extends CentralController
final myDescriptorArgses = await _myApi.getDescriptors( final myDescriptorArgses = await _myApi.getDescriptors(
myCharacteristic.hashCode, myCharacteristic.hashCode,
); );
return myDescriptorArgses return myDescriptorArgses.cast<MyGattDescriptorArgs>().map(
.cast<MyGattDescriptorArgs>() (myDescriptorArgs) {
.map( final myDescriptor = MyGattDescriptor.fromMyArgs(
(myDescriptorArgs) => _myDescriptors.putIfAbsent(
myDescriptorArgs.key,
() => MyGattDescriptor.fromMyArgs(
myCharacteristic, myCharacteristic,
myDescriptorArgs, myDescriptorArgs,
), );
), _myDescriptors[myDescriptor.hashCode] = myDescriptor;
) return myDescriptor;
.toList(); },
).toList();
} }
@override @override
@ -196,6 +190,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
final value = await _myApi.readCharacteristic( final value = await _myApi.readCharacteristic(
myPeripheral.hashCode, myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode, myCharacteristic.hashCode,
); );
return value; return value;
@ -215,6 +210,7 @@ class MyCentralController extends CentralController
final typeNumber = typeArgs.index; final typeNumber = typeArgs.index;
await _myApi.writeCharacteristic( await _myApi.writeCharacteristic(
myPeripheral.hashCode, myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode, myCharacteristic.hashCode,
value, value,
typeNumber, typeNumber,
@ -232,6 +228,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
await _myApi.notifyCharacteristic( await _myApi.notifyCharacteristic(
myPeripheral.hashCode, myPeripheral.hashCode,
myService.hashCode,
myCharacteristic.hashCode, myCharacteristic.hashCode,
state, state,
); );
@ -246,6 +243,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
final value = await _myApi.readDescriptor( final value = await _myApi.readDescriptor(
myPeripheral.hashCode, myPeripheral.hashCode,
myCharacteristic.hashCode,
myDescriptor.hashCode, myDescriptor.hashCode,
); );
return value; return value;
@ -263,6 +261,7 @@ class MyCentralController extends CentralController
final myPeripheral = myService.myPeripheral; final myPeripheral = myService.myPeripheral;
await _myApi.writeDescriptor( await _myApi.writeDescriptor(
myPeripheral.hashCode, myPeripheral.hashCode,
myCharacteristic.hashCode,
myDescriptor.hashCode, myDescriptor.hashCode,
value, value,
); );
@ -286,10 +285,8 @@ class MyCentralController extends CentralController
int rssi, int rssi,
MyAdvertisementArgs myAdvertisementArgs, MyAdvertisementArgs myAdvertisementArgs,
) { ) {
final myPeripheral = _myPeripherals.putIfAbsent( final myPeripheral = MyPeripheral.fromMyArgs(myPeripheralArgs);
myPeripheralArgs.key, _myPeripherals[myPeripheral.hashCode] = myPeripheral;
() => MyPeripheral.fromMyArgs(myPeripheralArgs),
);
final advertisement = myAdvertisementArgs.toAdvertisement(); final advertisement = myAdvertisementArgs.toAdvertisement();
final eventArgs = CentralDiscoveredEventArgs( final eventArgs = CentralDiscoveredEventArgs(
myPeripheral, myPeripheral,

View File

@ -258,11 +258,11 @@ protocol MyCentralControllerHostApi {
func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs]
func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs]
func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs]
func readCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) func readCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void)
func writeCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result<Void, Error>) -> Void) func writeCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result<Void, Error>) -> Void)
func notifyCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result<Void, Error>) -> Void) func notifyCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result<Void, Error>) -> Void)
func readDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) func readDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void)
func writeDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result<Void, Error>) -> Void) func writeDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result<Void, Error>) -> Void)
} }
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@ -426,8 +426,9 @@ class MyCentralControllerHostApiSetup {
readCharacteristicChannel.setMessageHandler { message, reply in readCharacteristicChannel.setMessageHandler { message, reply in
let args = message as! [Any?] let args = message as! [Any?]
let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) 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 myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
api.readCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg) { result in 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 { switch result {
case .success(let res): case .success(let res):
reply(wrapResult(res)) reply(wrapResult(res))
@ -444,10 +445,11 @@ class MyCentralControllerHostApiSetup {
writeCharacteristicChannel.setMessageHandler { message, reply in writeCharacteristicChannel.setMessageHandler { message, reply in
let args = message as! [Any?] let args = message as! [Any?]
let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) 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 myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
let valueArg = args[2] as! FlutterStandardTypedData let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32)
let myTypeNumberArg = args[3] is Int64 ? args[3] as! Int64 : Int64(args[3] as! Int32) let valueArg = args[3] as! FlutterStandardTypedData
api.writeCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, value: valueArg, myTypeNumber: myTypeNumberArg) { result in 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 { switch result {
case .success: case .success:
reply(wrapResult(nil)) reply(wrapResult(nil))
@ -464,9 +466,10 @@ class MyCentralControllerHostApiSetup {
notifyCharacteristicChannel.setMessageHandler { message, reply in notifyCharacteristicChannel.setMessageHandler { message, reply in
let args = message as! [Any?] let args = message as! [Any?]
let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) 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 myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
let stateArg = args[2] as! Bool let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32)
api.notifyCharacteristic(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, state: stateArg) { result in let stateArg = args[3] as! Bool
api.notifyCharacteristic(myPeripheralKey: myPeripheralKeyArg, myServiceKey: myServiceKeyArg, myCharacteristicKey: myCharacteristicKeyArg, state: stateArg) { result in
switch result { switch result {
case .success: case .success:
reply(wrapResult(nil)) reply(wrapResult(nil))
@ -483,8 +486,9 @@ class MyCentralControllerHostApiSetup {
readDescriptorChannel.setMessageHandler { message, reply in readDescriptorChannel.setMessageHandler { message, reply in
let args = message as! [Any?] let args = message as! [Any?]
let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) 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 myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
api.readDescriptor(myPeripheralKey: myPeripheralKeyArg, myDescriptorKey: myDescriptorKeyArg) { result in 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 { switch result {
case .success(let res): case .success(let res):
reply(wrapResult(res)) reply(wrapResult(res))
@ -501,9 +505,10 @@ class MyCentralControllerHostApiSetup {
writeDescriptorChannel.setMessageHandler { message, reply in writeDescriptorChannel.setMessageHandler { message, reply in
let args = message as! [Any?] let args = message as! [Any?]
let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) 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 myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
let valueArg = args[2] as! FlutterStandardTypedData let myDescriptorKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32)
api.writeDescriptor(myPeripheralKey: myPeripheralKeyArg, myDescriptorKey: myDescriptorKeyArg, value: valueArg) { result in let valueArg = args[3] as! FlutterStandardTypedData
api.writeDescriptor(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, myDescriptorKey: myDescriptorKeyArg, value: valueArg) { result in
switch result { switch result {
case .success: case .success:
reply(wrapResult(nil)) reply(wrapResult(nil))

View File

@ -19,10 +19,10 @@ class MyCentralController: MyCentralControllerHostApi {
private lazy var myPeripheralDelegate = MyPeripheralDelegate(self) private lazy var myPeripheralDelegate = MyPeripheralDelegate(self)
private let centralManager = CBCentralManager() private let centralManager = CBCentralManager()
private var peripherals = [Int: CBPeripheral]() private var cachedPeripherals = [Int: CBPeripheral]()
private var services = [Int: CBService]() private var cachedServices = [Int: [Int: CBService]]()
private var characteristics = [Int: CBCharacteristic]() private var cachedCharacteristics = [Int: [Int: CBCharacteristic]]()
private var descriptors = [Int: CBDescriptor]() private var cachedDescriptors = [Int: [Int: CBDescriptor]]()
var setUpCompletion: ((Result<MyCentralControllerArgs, Error>) -> Void)? var setUpCompletion: ((Result<MyCentralControllerArgs, Error>) -> Void)?
var connectCompletions = [Int: (Result<Void, Error>) -> Void]() var connectCompletions = [Int: (Result<Void, Error>) -> Void]()
@ -61,16 +61,16 @@ class MyCentralController: MyCentralControllerHostApi {
if(centralManager.isScanning) { if(centralManager.isScanning) {
centralManager.stopScan() centralManager.stopScan()
} }
for peripheral in peripherals.values { for peripheral in cachedPeripherals.values {
peripheral.delegate = nil peripheral.delegate = nil
if peripheral.state != .disconnected { if peripheral.state != .disconnected {
centralManager.cancelPeripheralConnection(peripheral) centralManager.cancelPeripheralConnection(peripheral)
} }
} }
peripherals.removeAll() cachedPeripherals.removeAll()
services.removeAll() cachedServices.removeAll()
characteristics.removeAll() cachedCharacteristics.removeAll()
descriptors.removeAll() cachedDescriptors.removeAll()
} }
func startDiscovery() throws { func startDiscovery() throws {
@ -89,7 +89,7 @@ class MyCentralController: MyCentralControllerHostApi {
if unfinishedCompletion != nil { if unfinishedCompletion != nil {
throw MyError.illegalState throw MyError.illegalState
} }
guard let peripheral = peripherals[peripheralKey] else { guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
centralManager.connect(peripheral) centralManager.connect(peripheral)
@ -106,7 +106,7 @@ class MyCentralController: MyCentralControllerHostApi {
if unfinishedCompletion != nil { if unfinishedCompletion != nil {
throw MyError.illegalState throw MyError.illegalState
} }
guard let peripheral = peripherals[peripheralKey] else { guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
centralManager.cancelPeripheralConnection(peripheral) centralManager.cancelPeripheralConnection(peripheral)
@ -123,7 +123,7 @@ class MyCentralController: MyCentralControllerHostApi {
if unfinishedCompletion != nil { if unfinishedCompletion != nil {
throw MyError.illegalState throw MyError.illegalState
} }
guard let peripheral = peripherals[peripheralKey] else { guard let peripheral = cachedPeripherals[peripheralKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
peripheral.discoverServices(nil) peripheral.discoverServices(nil)
@ -135,53 +135,42 @@ class MyCentralController: MyCentralControllerHostApi {
func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] { func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] {
let peripheralKey = Int(myPeripheralKey) let peripheralKey = Int(myPeripheralKey)
guard let peripheral = peripherals[peripheralKey] else { guard let services = cachedServices[peripheralKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
let services = peripheral.services ?? [] return services.map { (key, service) in
return services.map { service in
let serviceKey = service.hash
if self.services[serviceKey] == nil {
self.services[serviceKey] = service
}
return service.toMyArgs() return service.toMyArgs()
} }
} }
func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] { func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] {
let serviceKey = Int(myServiceKey) let serviceKey = Int(myServiceKey)
guard let service = services[serviceKey] else { guard let characteristics = cachedCharacteristics[serviceKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
let characteristics = service.characteristics ?? [] return characteristics.map { (key, characteristic) in
return characteristics.map { characteristic in
let characteristicKey = characteristic.hash
if self.characteristics[characteristicKey] == nil {
self.characteristics[characteristicKey] = characteristic
}
return characteristic.toMyArgs() return characteristic.toMyArgs()
} }
} }
func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] { func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] {
let characteristicKey = Int(myCharacteristicKey) let characteristicKey = Int(myCharacteristicKey)
guard let characteristic = characteristics[characteristicKey] else { guard let descriptors = cachedDescriptors[characteristicKey] else {
throw MyError.illegalArgument throw MyError.illegalArgument
} }
let descritors = characteristic.descriptors ?? [] return descriptors.map { (key, descriptor) in
return descritors.map { descriptor in
let descriptorKey = descriptor.hash
if self.descriptors[descriptorKey] == nil {
self.descriptors[descriptorKey] = descriptor
}
return descriptor.toMyArgs() return descriptor.toMyArgs()
} }
} }
func readCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) { func readCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
do { do {
let peripheralKey = Int(myPeripheralKey) 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 throw MyError.illegalArgument
} }
let characteristicKey = Int(myCharacteristicKey) 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, Error>) -> Void) { func writeCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
do { do {
let peripheralKey = Int(myPeripheralKey) 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 throw MyError.illegalArgument
} }
let characteristicKey = Int(myCharacteristicKey) let characteristicKey = Int(myCharacteristicKey)
@ -226,10 +219,14 @@ class MyCentralController: MyCentralControllerHostApi {
} }
} }
func notifyCharacteristic(myPeripheralKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result<Void, Error>) -> Void) { func notifyCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result<Void, Error>) -> Void) {
do { do {
let peripheralKey = Int(myPeripheralKey) 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 throw MyError.illegalArgument
} }
let characteristicKey = Int(myCharacteristicKey) let characteristicKey = Int(myCharacteristicKey)
@ -247,10 +244,14 @@ class MyCentralController: MyCentralControllerHostApi {
} }
} }
func readDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) { func readDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
do { do {
let peripheralKey = Int(myPeripheralKey) 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 throw MyError.illegalArgument
} }
let descriptorKey = Int(myDescriptorKey) let descriptorKey = Int(myDescriptorKey)
@ -268,10 +269,14 @@ class MyCentralController: MyCentralControllerHostApi {
} }
} }
func writeDescriptor(myPeripheralKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result<Void, Error>) -> Void) { func writeDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result<Void, Error>) -> Void) {
do { do {
let peripheralKey = Int(myPeripheralKey) 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 throw MyError.illegalArgument
} }
let descriptorKey = Int(myDescriptorKey) let descriptorKey = Int(myDescriptorKey)
@ -307,9 +312,9 @@ class MyCentralController: MyCentralControllerHostApi {
func didDiscover(_ peripheral: CBPeripheral, _ advertisementData: [String : Any], _ rssiNumber: NSNumber) { func didDiscover(_ peripheral: CBPeripheral, _ advertisementData: [String : Any], _ rssiNumber: NSNumber) {
let peripheralKey = peripheral.hash let peripheralKey = peripheral.hash
if peripherals[peripheralKey] == nil { if cachedPeripherals[peripheralKey] == nil {
peripheral.delegate = myPeripheralDelegate peripheral.delegate = myPeripheralDelegate
peripherals[peripheralKey] = peripheral cachedPeripherals[peripheralKey] = peripheral
} }
let myPeripheralArgs = peripheral.toMyArgs() let myPeripheralArgs = peripheral.toMyArgs()
let rssi = rssiNumber.int64Value let rssi = rssiNumber.int64Value
@ -368,26 +373,24 @@ class MyCentralController: MyCentralControllerHostApi {
let myPeripheralKey = Int64(peripheralKey) let myPeripheralKey = Int64(peripheralKey)
let discoverGattCompletion = discoverGattCompletions.removeValue(forKey: peripheralKey) let discoverGattCompletion = discoverGattCompletions.removeValue(forKey: peripheralKey)
if discoverGattCompletion != nil { 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 { for service in services {
let characteristics = service.characteristics ?? [] let characteristics = cachedCharacteristics[service.key] ?? [:]
for characteristic in characteristics { for characteristic in characteristics {
let characteristicKey = characteristic.hash let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristic.key)
let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristicKey) let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristic.key)
let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristicKey)
if readCharacteristicCompletion != nil { if readCharacteristicCompletion != nil {
readCharacteristicCompletion!(.failure(MyError.illegalState)) readCharacteristicCompletion!(.failure(MyError.illegalState))
} }
if writeCharacteristicCompletion != nil { if writeCharacteristicCompletion != nil {
writeCharacteristicCompletion!(.failure(MyError.illegalState)) writeCharacteristicCompletion!(.failure(MyError.illegalState))
} }
let descriptors = characteristic.descriptors ?? [] let descriptors = cachedDescriptors[characteristic.key] ?? [:]
for descriptor in descriptors { for descriptor in descriptors {
let descriptorKey = descriptor.hash let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptor.key)
let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptorKey) let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptor.key)
let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptorKey)
if readDescriptorCompletion != nil { if readDescriptorCompletion != nil {
readDescriptorCompletion!(.failure(MyError.illegalState)) readDescriptorCompletion!(.failure(MyError.illegalState))
} }
@ -411,37 +414,28 @@ class MyCentralController: MyCentralControllerHostApi {
func didDiscoverServices(_ peripheral: CBPeripheral, _ error: Error?) { func didDiscoverServices(_ peripheral: CBPeripheral, _ error: Error?) {
let peripheralKey = peripheral.hash let peripheralKey = peripheral.hash
guard let completion = discoverGattCompletions[peripheralKey] else {
return
}
if error == nil { if error == nil {
var services = peripheral.services ?? [] var services = peripheral.services ?? []
if services.isEmpty { if services.isEmpty {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
completion(.success(()))
} else { } else {
let service = services.removeFirst() let service = services.removeFirst()
unfinishedServices[peripheralKey] = services unfinishedServices[peripheralKey] = services
peripheral.discoverCharacteristics(nil, for: service) peripheral.discoverCharacteristics(nil, for: service)
} }
} else { } else {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
completion(.failure(error!))
} }
} }
func didDiscoverCharacteristics(_ peripheral: CBPeripheral, _ service: CBService, _ error: Error?) { func didDiscoverCharacteristics(_ peripheral: CBPeripheral, _ service: CBService, _ error: Error?) {
let peripheralKey = peripheral.hash let peripheralKey = peripheral.hash
guard let completion = discoverGattCompletions[peripheralKey] else {
return
}
if error == nil { if error == nil {
var characteristics = service.characteristics ?? [] var characteristics = service.characteristics ?? []
if characteristics.isEmpty { if characteristics.isEmpty {
var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? [] var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? []
if services.isEmpty { if services.isEmpty {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
completion(.success(()))
} else { } else {
let service = services.removeFirst() let service = services.removeFirst()
unfinishedServices[peripheralKey] = services unfinishedServices[peripheralKey] = services
@ -453,24 +447,18 @@ class MyCentralController: MyCentralControllerHostApi {
peripheral.discoverDescriptors(for: characteristic) peripheral.discoverDescriptors(for: characteristic)
} }
} else { } else {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
unfinishedServices.removeValue(forKey: peripheralKey)
completion(.failure(error!))
} }
} }
func didDiscoverDescriptors(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic, _ error: Error?) { func didDiscoverDescriptors(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic, _ error: Error?) {
let peripheralKey = peripheral.hash let peripheralKey = peripheral.hash
guard let completion = discoverGattCompletions[peripheralKey] else {
return
}
if error == nil { if error == nil {
var characteristics = unfinishedCharacteristics.removeValue(forKey: peripheralKey) ?? [] var characteristics = unfinishedCharacteristics.removeValue(forKey: peripheralKey) ?? []
if (characteristics.isEmpty) { if (characteristics.isEmpty) {
var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? [] var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? []
if services.isEmpty { if services.isEmpty {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
completion(.success(()))
} else { } else {
let service = services.removeFirst() let service = services.removeFirst()
unfinishedServices[peripheralKey] = services unfinishedServices[peripheralKey] = services
@ -482,9 +470,41 @@ class MyCentralController: MyCentralControllerHostApi {
peripheral.discoverDescriptors(for: characteristic) peripheral.discoverDescriptors(for: characteristic)
} }
} else { } else {
discoverGattCompletions.removeValue(forKey: peripheralKey) didDiscoverGATT(peripheral, error)
}
}
private func didDiscoverGATT(_ peripheral: CBPeripheral, _ error: Error?) {
let peripheralKey = peripheral.hash
unfinishedServices.removeValue(forKey: peripheralKey) unfinishedServices.removeValue(forKey: peripheralKey)
unfinishedCharacteristics.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!)) completion(.failure(error!))
} }
} }

View File

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

View File

@ -25,10 +25,15 @@ abstract class MyCentralControllerHostApi {
List<MyGattCharacteristicArgs> getCharacteristics(int myServiceKey); List<MyGattCharacteristicArgs> getCharacteristics(int myServiceKey);
List<MyGattDescriptorArgs> getDescriptors(int myCharacteristicKey); List<MyGattDescriptorArgs> getDescriptors(int myCharacteristicKey);
@async @async
Uint8List readCharacteristic(int myPeripheralKey, int myCharacteristicKey); Uint8List readCharacteristic(
int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey,
);
@async @async
void writeCharacteristic( void writeCharacteristic(
int myPeripheralKey, int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey, int myCharacteristicKey,
Uint8List value, Uint8List value,
int myTypeNumber, int myTypeNumber,
@ -36,14 +41,20 @@ abstract class MyCentralControllerHostApi {
@async @async
void notifyCharacteristic( void notifyCharacteristic(
int myPeripheralKey, int myPeripheralKey,
int myServiceKey,
int myCharacteristicKey, int myCharacteristicKey,
bool state, bool state,
); );
@async @async
Uint8List readDescriptor(int myPeripheralKey, int myDescriptorKey); Uint8List readDescriptor(
int myPeripheralKey,
int myCharacteristicKey,
int myDescriptorKey,
);
@async @async
void writeDescriptor( void writeDescriptor(
int myPeripheralKey, int myPeripheralKey,
int myCharacteristicKey,
int myDescriptorKey, int myDescriptorKey,
Uint8List value, Uint8List value,
); );

View File

@ -1,6 +1,6 @@
name: bluetooth_low_energy_macos name: bluetooth_low_energy_macos
description: macOS implementation of the bluetooth_low_energy plugin. 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 homepage: https://github.com/yanshouwang/bluetooth_low_energy
environment: environment:
@ -10,7 +10,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
bluetooth_low_energy_platform_interface: ^2.0.0 bluetooth_low_energy_platform_interface: ^2.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -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 ## 2.0.0
- Rewrite the whole project with federated plugins. - Rewrite the whole project with federated plugins.

View File

@ -1,6 +1,6 @@
name: bluetooth_low_energy_platform_interface name: bluetooth_low_energy_platform_interface
description: A common platform interface for the bluetooth_low_energy plugin. 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 homepage: https://github.com/yanshouwang/bluetooth_low_energy
environment: environment:

View File

@ -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 ## 2.0.0
- Rewrite the whole project with federated plugins. - Rewrite the whole project with federated plugins.

View File

@ -1,6 +1,6 @@
name: bluetooth_low_energy_windows name: bluetooth_low_energy_windows
description: Windows implementation of the bluetooth_low_energy plugin. 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 homepage: https://github.com/yanshouwang/bluetooth_low_energy
environment: environment:
@ -10,7 +10,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
bluetooth_low_energy_platform_interface: ^2.0.0 bluetooth_low_energy_platform_interface: ^2.0.1
win32: ^5.0.6 win32: ^5.0.6
dev_dependencies: dev_dependencies:
@ -23,5 +23,5 @@ flutter:
implements: bluetooth_low_energy implements: bluetooth_low_energy
platforms: platforms:
windows: windows:
pluginClass: BluetoothLowEnergyWindowsPluginCApi pluginClass: BluetoothLowEnergyPluginCApi
dartPluginClass: BluetoothLowEnergyWindows dartPluginClass: BluetoothLowEnergyWindows

View File

@ -5,24 +5,24 @@
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
# Project-level configuration. # Project-level configuration.
set(PROJECT_NAME "bluetooth_low_energy_windows") set(PROJECT_NAME "bluetooth_low_energy")
project(${PROJECT_NAME} LANGUAGES CXX) project(${PROJECT_NAME} LANGUAGES CXX)
# This value is used when generating builds using this plugin, so it must # This value is used when generating builds using this plugin, so it must
# not be changed # 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. # Any new source files that you add to the plugin should be added here.
list(APPEND PLUGIN_SOURCES list(APPEND PLUGIN_SOURCES
"bluetooth_low_energy_windows_plugin.cpp" "bluetooth_low_energy_plugin.cpp"
"bluetooth_low_energy_windows_plugin.h" "bluetooth_low_energy_plugin.h"
) )
# Define the plugin library target. Its name must not be changed (see comment # Define the plugin library target. Its name must not be changed (see comment
# on PLUGIN_NAME above). # on PLUGIN_NAME above).
add_library(${PLUGIN_NAME} SHARED add_library(${PLUGIN_NAME} SHARED
"include/bluetooth_low_energy_windows/bluetooth_low_energy_windows_plugin_c_api.h" "include/bluetooth_low_energy/bluetooth_low_energy_plugin_c_api.h"
"bluetooth_low_energy_windows_plugin_c_api.cpp" "bluetooth_low_energy_plugin_c_api.cpp"
${PLUGIN_SOURCES} ${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. # List of absolute paths to libraries that should be bundled with the plugin.
# This list could contain prebuilt libraries, or libraries created by an # This list could contain prebuilt libraries, or libraries created by an
# external build triggered from this build file. # external build triggered from this build file.
set(bluetooth_low_energy_windows_bundled_libraries set(bluetooth_low_energy_bundled_libraries
"" ""
PARENT_SCOPE 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}" $<TARGET_FILE_DIR:${TEST_RUNNER}>
)
# Enable automatic test discovery.
include(GoogleTest)
gtest_discover_tests(${TEST_RUNNER})
endif()

View File

@ -1,59 +0,0 @@
#include "bluetooth_low_energy_windows_plugin.h"
// This must be included before many other Windows headers.
#include <windows.h>
// For getPlatformVersion; remove unless needed for your plugin implementation.
#include <VersionHelpers.h>
#include <flutter/method_channel.h>
#include <flutter/plugin_registrar_windows.h>
#include <flutter/standard_method_codec.h>
#include <memory>
#include <sstream>
namespace bluetooth_low_energy_windows {
// static
void BluetoothLowEnergyWindowsPlugin::RegisterWithRegistrar(
flutter::PluginRegistrarWindows *registrar) {
auto channel =
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
registrar->messenger(), "bluetooth_low_energy_windows",
&flutter::StandardMethodCodec::GetInstance());
auto plugin = std::make_unique<BluetoothLowEnergyWindowsPlugin>();
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<flutter::EncodableValue> &method_call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> 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

View File

@ -1,32 +0,0 @@
#ifndef FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_WINDOWS_PLUGIN_H_
#define FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_WINDOWS_PLUGIN_H_
#include <flutter/method_channel.h>
#include <flutter/plugin_registrar_windows.h>
#include <memory>
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<flutter::EncodableValue> &method_call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
};
} // namespace bluetooth_low_energy_windows
#endif // FLUTTER_PLUGIN_BLUETOOTH_LOW_ENERGY_WINDOWS_PLUGIN_H_

View File

@ -1,12 +0,0 @@
#include "include/bluetooth_low_energy_windows/bluetooth_low_energy_windows_plugin_c_api.h"
#include <flutter/plugin_registrar_windows.h>
#include "bluetooth_low_energy_windows_plugin.h"
void BluetoothLowEnergyWindowsPluginCApiRegisterWithRegistrar(
FlutterDesktopPluginRegistrarRef registrar) {
bluetooth_low_energy_windows::BluetoothLowEnergyWindowsPlugin::RegisterWithRegistrar(
flutter::PluginRegistrarManager::GetInstance()
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
}

View File

@ -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 <flutter_plugin_registrar.h>
#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_