Refactor BLE plugin structure and rename to 'ble' for consistency across platforms

This commit is contained in:
TonyLu
2026-05-07 17:22:39 +08:00
parent d670143817
commit 020abb118f
19 changed files with 163 additions and 121 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
group 'com.dalimaster.ble_relay_host' group 'com.dalimaster.ble'
version '1.0-SNAPSHOT' version '1.0-SNAPSHOT'
buildscript { buildscript {
@@ -24,7 +24,7 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
android { android {
namespace 'com.dalimaster.ble_relay_host' namespace 'com.dalimaster.ble'
compileSdk 34 compileSdk 34
defaultConfig { defaultConfig {
+1 -1
View File
@@ -1 +1 @@
include ':ble_relay_host' include ':ble'
@@ -1,6 +1,15 @@
package com.dalimaster.ble_relay_host package com.dalimaster.ble
import android.bluetooth.* import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothGattServer
import android.bluetooth.BluetoothGattServerCallback
import android.bluetooth.BluetoothGattService
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile
import android.bluetooth.le.AdvertiseCallback import android.bluetooth.le.AdvertiseCallback
import android.bluetooth.le.AdvertiseData import android.bluetooth.le.AdvertiseData
import android.bluetooth.le.AdvertiseSettings import android.bluetooth.le.AdvertiseSettings
@@ -16,11 +25,11 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result import io.flutter.plugin.common.MethodChannel.Result
import java.util.UUID import java.util.UUID
private const val TAG = "BleRelayHostPlugin" private const val TAG = "BlePlugin"
private const val CHANNEL = "com.dalimaster.ble_relay_host" private const val CHANNEL = "com.dalimaster.ble"
private const val EVENT_CHANNEL = "com.dalimaster.ble_relay_host/clientWrites" private const val EVENT_CHANNEL = "com.dalimaster.ble/clientWrites"
class BleRelayHostPlugin : FlutterPlugin, MethodCallHandler { class BlePlugin : FlutterPlugin, MethodCallHandler {
private lateinit var methodChannel: MethodChannel private lateinit var methodChannel: MethodChannel
private lateinit var eventChannel: EventChannel private lateinit var eventChannel: EventChannel
@@ -53,6 +62,7 @@ class BleRelayHostPlugin : FlutterPlugin, MethodCallHandler {
override fun onListen(arguments: Any?, sink: EventChannel.EventSink?) { override fun onListen(arguments: Any?, sink: EventChannel.EventSink?) {
eventSink = sink eventSink = sink
} }
override fun onCancel(arguments: Any?) { override fun onCancel(arguments: Any?) {
eventSink = null eventSink = null
} }
@@ -79,18 +89,24 @@ class BleRelayHostPlugin : FlutterPlugin, MethodCallHandler {
?: "0000fff1-0000-1000-8000-00805f9b34fb" ?: "0000fff1-0000-1000-8000-00805f9b34fb"
startInternal(advertisedName, serviceUuidStr, charUuidStr, result) startInternal(advertisedName, serviceUuidStr, charUuidStr, result)
} }
"push" -> { "push" -> {
val data = call.argument<ByteArray>("data") val data = call.argument<ByteArray>("data")
if (data != null) pushInternal(data) if (data != null) pushInternal(data)
result.success(null) result.success(null)
} }
"stop" -> { "stop" -> {
pendingStartResult?.error("CANCELLED", "BLE relay host start cancelled", null) pendingStartResult?.error("CANCELLED", "BLE relay host start cancelled", null)
pendingStartResult = null pendingStartResult = null
stopInternal() stopInternal()
result.success(null) result.success(null)
} }
"isSupported" -> result.success(bluetoothAdapter != null && bluetoothAdapter!!.isMultipleAdvertisementSupported)
"isSupported" -> result.success(
bluetoothAdapter != null && bluetoothAdapter!!.isMultipleAdvertisementSupported,
)
else -> result.notImplemented() else -> result.notImplemented()
} }
} }
@@ -263,6 +279,7 @@ class BleRelayHostPlugin : FlutterPlugin, MethodCallHandler {
pendingStartResult?.success(null) pendingStartResult?.success(null)
pendingStartResult = null pendingStartResult = null
} }
override fun onStartFailure(errorCode: Int) { override fun onStartFailure(errorCode: Int) {
Log.e(TAG, "BLE advertising failed: $errorCode") Log.e(TAG, "BLE advertising failed: $errorCode")
pendingStartResult?.error( pendingStartResult?.error(
@@ -1,14 +1,14 @@
import Foundation import Foundation
import Flutter import Flutter
/// iOS stub BLE peripheral (CoreBluetooth CBPeripheralManager) is available on iOS but /// iOS stub - BLE peripheral (CoreBluetooth CBPeripheralManager) is available on iOS but
/// not yet implemented. `isSupported` returns false; all other methods are no-ops. /// not yet implemented. `isSupported` returns false; all other methods are no-ops.
public class BleRelayHostPlugin: NSObject, FlutterPlugin { public class BlePlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) { public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel( let channel = FlutterMethodChannel(
name: "com.dalimaster.ble_relay_host", name: "com.dalimaster.ble",
binaryMessenger: registrar.messenger()) binaryMessenger: registrar.messenger())
let instance = BleRelayHostPlugin() let instance = BlePlugin()
registrar.addMethodCallDelegate(instance, channel: channel) registrar.addMethodCallDelegate(instance, channel: channel)
} }
@@ -1,5 +1,5 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'ble_relay_host' s.name = 'ble'
s.version = '0.1.0' s.version = '0.1.0'
s.summary = 'BLE GATT-server peripheral host for the DALI relay feature.' s.summary = 'BLE GATT-server peripheral host for the DALI relay feature.'
s.description = <<-DESC s.description = <<-DESC
+1 -1
View File
@@ -11,7 +11,7 @@ const String kBleRelayServiceUuid = '0000fff0-0000-1000-8000-00805f9b34fb';
const String kBleRelayCharacteristicUuid = '0000fff1-0000-1000-8000-00805f9b34fb'; const String kBleRelayCharacteristicUuid = '0000fff1-0000-1000-8000-00805f9b34fb';
/// Method-channel name (must match Android/iOS/macOS native implementations). /// Method-channel name (must match Android/iOS/macOS native implementations).
const String _kChannelName = 'com.dalimaster.ble_relay_host'; const String _kChannelName = 'com.dalimaster.ble';
/// An abstraction over the platform BLE GATT-server implementation. /// An abstraction over the platform BLE GATT-server implementation.
/// ///
+4 -4
View File
@@ -1,13 +1,13 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
set(PROJECT_NAME "ble_relay_host") set(PROJECT_NAME "ble")
project(${PROJECT_NAME} LANGUAGES CXX) project(${PROJECT_NAME} LANGUAGES CXX)
cmake_policy(VERSION 3.10...3.24) cmake_policy(VERSION 3.10...3.24)
set(PLUGIN_NAME "ble_relay_host_plugin") set(PLUGIN_NAME "ble_plugin")
list(APPEND PLUGIN_SOURCES list(APPEND PLUGIN_SOURCES
"ble_relay_host_plugin.cc" "ble_plugin.cc"
) )
add_library(${PLUGIN_NAME} SHARED add_library(${PLUGIN_NAME} SHARED
@@ -21,7 +21,7 @@ target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) target_link_libraries(${PLUGIN_NAME} PRIVATE flutter)
target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK)
set(ble_relay_host_bundled_libraries set(ble_bundled_libraries
"" ""
PARENT_SCOPE PARENT_SCOPE
) )
+50
View File
@@ -0,0 +1,50 @@
#include "ble_plugin.h"
#include <flutter_linux/flutter_linux.h>
#define BLE_PLUGIN(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), ble_plugin_get_type(), BlePlugin))
struct _BlePlugin {
GObject parent_instance;
};
G_DEFINE_TYPE(BlePlugin, ble_plugin, g_object_get_type())
static void ble_plugin_handle_method_call(BlePlugin* self,
FlMethodCall* method_call) {
g_autoptr(FlMethodResponse) response = nullptr;
const gchar* method = fl_method_call_get_name(method_call);
if (strcmp(method, "isSupported") == 0) {
g_autoptr(FlValue) result = fl_value_new_bool(FALSE);
response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
} else {
response = FL_METHOD_RESPONSE(
fl_method_success_response_new(fl_value_new_null()));
}
fl_method_call_respond(method_call, response, nullptr);
}
static void method_call_cb(FlMethodChannel* channel,
FlMethodCall* method_call,
gpointer user_data) {
BlePlugin* plugin = BLE_PLUGIN(user_data);
ble_plugin_handle_method_call(plugin, method_call);
}
void ble_plugin_register_with_registrar(FlPluginRegistrar* registrar) {
BlePlugin* plugin = BLE_PLUGIN(g_object_new(ble_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),
"com.dalimaster.ble",
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);
}
static void ble_plugin_class_init(BlePluginClass* klass) {}
static void ble_plugin_init(BlePlugin* self) {}
+16
View File
@@ -0,0 +1,16 @@
#ifndef FLUTTER_PLUGIN_BLE_PLUGIN_H_
#define FLUTTER_PLUGIN_BLE_PLUGIN_H_
#include <flutter_linux/flutter_linux.h>
G_BEGIN_DECLS
#define BLE_PLUGIN_TYPE (ble_plugin_get_type())
G_DECLARE_FINAL_TYPE(BlePlugin, ble_plugin, BLE, PLUGIN, GObject)
void ble_plugin_register_with_registrar(FlPluginRegistrar* registrar);
G_END_DECLS
#endif // FLUTTER_PLUGIN_BLE_PLUGIN_H_
-48
View File
@@ -1,48 +0,0 @@
#include "ble_relay_host_plugin.h"
#include <flutter_linux/flutter_linux.h>
#define BLE_RELAY_HOST_PLUGIN(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), ble_relay_host_plugin_get_type(), BleRelayHostPlugin))
struct _BleRelayHostPlugin {
GObject parent_instance;
};
G_DEFINE_TYPE(BleRelayHostPlugin, ble_relay_host_plugin, g_object_get_type())
static void ble_relay_host_plugin_handle_method_call(
BleRelayHostPlugin* self,
FlMethodCall* method_call) {
g_autoptr(FlMethodResponse) response = nullptr;
const gchar* method = fl_method_call_get_name(method_call);
if (strcmp(method, "isSupported") == 0) {
g_autoptr(FlValue) result = fl_value_new_bool(FALSE);
response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
} else {
response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_null()));
}
fl_method_call_respond(method_call, response, nullptr);
}
static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call,
gpointer user_data) {
BleRelayHostPlugin* plugin = BLE_RELAY_HOST_PLUGIN(user_data);
ble_relay_host_plugin_handle_method_call(plugin, method_call);
}
void ble_relay_host_plugin_register_with_registrar(FlPluginRegistrar* registrar) {
BleRelayHostPlugin* plugin = BLE_RELAY_HOST_PLUGIN(
g_object_new(ble_relay_host_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),
"com.dalimaster.ble_relay_host",
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);
}
static void ble_relay_host_plugin_class_init(BleRelayHostPluginClass* klass) {}
static void ble_relay_host_plugin_init(BleRelayHostPlugin* self) {}
-16
View File
@@ -1,16 +0,0 @@
#ifndef FLUTTER_PLUGIN_BLE_RELAY_HOST_PLUGIN_H_
#define FLUTTER_PLUGIN_BLE_RELAY_HOST_PLUGIN_H_
#include <flutter_linux/flutter_linux.h>
G_BEGIN_DECLS
#define BLE_RELAY_HOST_PLUGIN_TYPE (ble_relay_host_plugin_get_type())
G_DECLARE_FINAL_TYPE(BleRelayHostPlugin, ble_relay_host_plugin, BLE_RELAY_HOST, PLUGIN, GObject)
void ble_relay_host_plugin_register_with_registrar(FlPluginRegistrar* registrar);
G_END_DECLS
#endif // FLUTTER_PLUGIN_BLE_RELAY_HOST_PLUGIN_H_
@@ -1,13 +1,13 @@
import Foundation import Foundation
import FlutterMacOS import FlutterMacOS
/// macOS stub BLE peripheral mode not yet implemented. /// macOS stub - BLE peripheral mode not yet implemented.
public class BleRelayHostPlugin: NSObject, FlutterPlugin { public class BlePlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) { public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel( let channel = FlutterMethodChannel(
name: "com.dalimaster.ble_relay_host", name: "com.dalimaster.ble",
binaryMessenger: registrar.messenger) binaryMessenger: registrar.messenger)
let instance = BleRelayHostPlugin() let instance = BlePlugin()
registrar.addMethodCallDelegate(instance, channel: channel) registrar.addMethodCallDelegate(instance, channel: channel)
} }
@@ -1,5 +1,5 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'ble_relay_host' s.name = 'ble'
s.version = '0.1.0' s.version = '0.1.0'
s.summary = 'BLE GATT-server peripheral host for the DALI relay feature.' s.summary = 'BLE GATT-server peripheral host for the DALI relay feature.'
s.description = <<-DESC s.description = <<-DESC
+7 -7
View File
@@ -1,4 +1,4 @@
name: ble_relay_host name: ble
description: "BLE GATT-server peripheral host adapter for the DALI Toolkit relay feature. Provides a simple start/stop/push API backed by platform-specific BLE advertising." description: "BLE GATT-server peripheral host adapter for the DALI Toolkit relay feature. Provides a simple start/stop/push API backed by platform-specific BLE advertising."
version: 0.1.0 version: 0.1.0
publish_to: none publish_to: none
@@ -21,13 +21,13 @@ flutter:
plugin: plugin:
platforms: platforms:
android: android:
package: com.dalimaster.ble_relay_host package: com.dalimaster.ble
pluginClass: BleRelayHostPlugin pluginClass: BlePlugin
ios: ios:
pluginClass: BleRelayHostPlugin pluginClass: BlePlugin
macos: macos:
pluginClass: BleRelayHostPlugin pluginClass: BlePlugin
linux: linux:
pluginClass: BleRelayHostPlugin pluginClass: BlePlugin
windows: windows:
pluginClass: BleRelayHostPluginCApi pluginClass: BlePluginCApi
+5 -5
View File
@@ -1,17 +1,17 @@
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
set(PROJECT_NAME "ble_relay_host") set(PROJECT_NAME "ble")
project(${PROJECT_NAME} LANGUAGES CXX) project(${PROJECT_NAME} LANGUAGES CXX)
cmake_policy(VERSION 3.14...3.25) cmake_policy(VERSION 3.14...3.25)
set(PLUGIN_NAME "ble_relay_host_plugin") set(PLUGIN_NAME "ble_plugin")
list(APPEND PLUGIN_SOURCES list(APPEND PLUGIN_SOURCES
"ble_relay_host_plugin.cpp" "ble_plugin.cpp"
) )
add_library(${PLUGIN_NAME} SHARED add_library(${PLUGIN_NAME} SHARED
"include/ble_relay_host/ble_relay_host_plugin_c_api.h" "include/ble/ble_plugin_c_api.h"
${PLUGIN_SOURCES} ${PLUGIN_SOURCES}
) )
@@ -22,7 +22,7 @@ target_include_directories(${PLUGIN_NAME} INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/include") "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin)
set(ble_relay_host_bundled_libraries set(ble_bundled_libraries
"" ""
PARENT_SCOPE PARENT_SCOPE
) )
@@ -1,20 +1,20 @@
#include "ble_relay_host_plugin.h" #include "ble_plugin.h"
// Windows stub BLE peripheral not yet implemented. // Windows stub - BLE peripheral not yet implemented.
#include <flutter/method_channel.h> #include <flutter/method_channel.h>
#include <flutter/plugin_registrar_windows.h> #include <flutter/plugin_registrar_windows.h>
#include <flutter/standard_method_codec.h> #include <flutter/standard_method_codec.h>
namespace ble_relay_host { namespace ble {
class BleRelayHostPlugin : public flutter::Plugin { class BlePlugin : public flutter::Plugin {
public: public:
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar) { static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar) {
auto channel = std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>( auto channel = std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
registrar->messenger(), "com.dalimaster.ble_relay_host", registrar->messenger(), "com.dalimaster.ble",
&flutter::StandardMethodCodec::GetInstance()); &flutter::StandardMethodCodec::GetInstance());
auto plugin = std::make_unique<BleRelayHostPlugin>(); auto plugin = std::make_unique<BlePlugin>();
channel->SetMethodCallHandler( channel->SetMethodCallHandler(
[plugin_pointer = plugin.get()](const auto& call, auto result) { [plugin_pointer = plugin.get()](const auto& call, auto result) {
plugin_pointer->HandleMethodCall(call, std::move(result)); plugin_pointer->HandleMethodCall(call, std::move(result));
@@ -22,8 +22,8 @@ class BleRelayHostPlugin : public flutter::Plugin {
registrar->AddPlugin(std::move(plugin)); registrar->AddPlugin(std::move(plugin));
} }
BleRelayHostPlugin() {} BlePlugin() {}
virtual ~BleRelayHostPlugin() {} virtual ~BlePlugin() {}
private: private:
void HandleMethodCall( void HandleMethodCall(
@@ -37,11 +37,11 @@ class BleRelayHostPlugin : public flutter::Plugin {
} }
}; };
} // namespace ble_relay_host } // namespace ble
void BleRelayHostPluginCApiRegisterWithRegistrar( void BlePluginCApiRegisterWithRegistrar(
FlutterDesktopPluginRegistrarRef registrar) { FlutterDesktopPluginRegistrarRef registrar) {
ble_relay_host::BleRelayHostPlugin::RegisterWithRegistrar( ble::BlePlugin::RegisterWithRegistrar(
flutter::PluginRegistrarManager::GetInstance() flutter::PluginRegistrarManager::GetInstance()
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar)); ->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
} }
@@ -1,5 +1,5 @@
#ifndef FLUTTER_PLUGIN_BLE_RELAY_HOST_PLUGIN_H_ #ifndef FLUTTER_PLUGIN_BLE_PLUGIN_H_
#define FLUTTER_PLUGIN_BLE_RELAY_HOST_PLUGIN_H_ #define FLUTTER_PLUGIN_BLE_PLUGIN_H_
#include <flutter/plugin_registrar_windows.h> #include <flutter/plugin_registrar_windows.h>
@@ -13,11 +13,11 @@
extern "C" { extern "C" {
#endif #endif
FLUTTER_PLUGIN_EXPORT void BleRelayHostPluginCApiRegisterWithRegistrar( FLUTTER_PLUGIN_EXPORT void BlePluginCApiRegisterWithRegistrar(
FlutterDesktopPluginRegistrarRef registrar); FlutterDesktopPluginRegistrarRef registrar);
#if defined(__cplusplus) #if defined(__cplusplus)
} // extern "C" } // extern "C"
#endif #endif
#endif // FLUTTER_PLUGIN_BLE_RELAY_HOST_PLUGIN_H_ #endif // FLUTTER_PLUGIN_BLE_PLUGIN_H_
+23
View File
@@ -0,0 +1,23 @@
#ifndef FLUTTER_PLUGIN_BLE_PLUGIN_C_API_H_
#define FLUTTER_PLUGIN_BLE_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 BlePluginCApiRegisterWithRegistrar(
FlutterDesktopPluginRegistrarRef registrar);
#if defined(__cplusplus)
} // extern "C"
#endif
#endif // FLUTTER_PLUGIN_BLE_PLUGIN_C_API_H_