From a7d636efc14eb3cf57816acebb35b0f2bc48e4c6 Mon Sep 17 00:00:00 2001 From: LiJianying Date: Sun, 28 Jan 2024 15:15:26 +0800 Subject: [PATCH] chore: Windows implements migration to protocol_handler_windows package --- README-ZH.md | 5 +- README.md | 5 +- .../Flutter/GeneratedPluginRegistrant.swift | 2 + .../flutter/generated_plugin_registrant.cc | 9 +- .../windows/flutter/generated_plugins.cmake | 3 +- .../example/windows/runner/main.cpp | 3 +- .../lib/src/protocol_handler.dart | 9 +- .../lib/src/protocol_registrar.dart | 30 ---- .../src/protocol_registrar_impl_android.dart | 14 -- .../lib/src/protocol_registrar_impl_ios.dart | 13 -- .../src/protocol_registrar_impl_macos.dart | 14 -- .../protocol_registrar_impl_windows_noop.dart | 12 -- packages/protocol_handler/pubspec.yaml | 4 +- .../protocol_handler/windows/CMakeLists.txt | 25 --- .../windows/protocol_handler_plugin.cpp | 154 ------------------ packages/protocol_handler_windows/.gitignore | 29 ++++ packages/protocol_handler_windows/.metadata | 30 ++++ .../protocol_handler_windows/CHANGELOG.md | 3 + packages/protocol_handler_windows/LICENSE | 21 +++ packages/protocol_handler_windows/README.md | 12 ++ .../analysis_options.yaml | 1 + .../lib/protocol_handler_windows.dart | 3 + .../lib/src/protocol_handler_windows.dart} | 14 +- .../protocol_handler_windows/pubspec.yaml | 27 +++ .../windows/.gitignore | 0 .../windows/CMakeLists.txt | 101 ++++++++++++ .../protocol_handler_windows_plugin_c_api.h} | 9 +- .../protocol_handler_windows_plugin.cpp | 128 +++++++++++++++ .../windows/protocol_handler_windows_plugin.h | 55 +++++++ .../protocol_handler_windows_plugin_c_api.cpp | 33 ++++ .../protocol_handler_windows_plugin_test.cpp | 43 +++++ 31 files changed, 523 insertions(+), 288 deletions(-) delete mode 100644 packages/protocol_handler/lib/src/protocol_registrar.dart delete mode 100644 packages/protocol_handler/lib/src/protocol_registrar_impl_android.dart delete mode 100644 packages/protocol_handler/lib/src/protocol_registrar_impl_ios.dart delete mode 100644 packages/protocol_handler/lib/src/protocol_registrar_impl_macos.dart delete mode 100644 packages/protocol_handler/lib/src/protocol_registrar_impl_windows_noop.dart delete mode 100644 packages/protocol_handler/windows/CMakeLists.txt delete mode 100644 packages/protocol_handler/windows/protocol_handler_plugin.cpp create mode 100644 packages/protocol_handler_windows/.gitignore create mode 100644 packages/protocol_handler_windows/.metadata create mode 100644 packages/protocol_handler_windows/CHANGELOG.md create mode 100644 packages/protocol_handler_windows/LICENSE create mode 100644 packages/protocol_handler_windows/README.md create mode 100644 packages/protocol_handler_windows/analysis_options.yaml create mode 100644 packages/protocol_handler_windows/lib/protocol_handler_windows.dart rename packages/{protocol_handler/lib/src/protocol_registrar_impl_windows.dart => protocol_handler_windows/lib/src/protocol_handler_windows.dart} (63%) create mode 100644 packages/protocol_handler_windows/pubspec.yaml rename packages/{protocol_handler => protocol_handler_windows}/windows/.gitignore (100%) create mode 100644 packages/protocol_handler_windows/windows/CMakeLists.txt rename packages/{protocol_handler/windows/include/protocol_handler/protocol_handler_plugin.h => protocol_handler_windows/windows/include/protocol_handler_windows/protocol_handler_windows_plugin_c_api.h} (62%) create mode 100644 packages/protocol_handler_windows/windows/protocol_handler_windows_plugin.cpp create mode 100644 packages/protocol_handler_windows/windows/protocol_handler_windows_plugin.h create mode 100644 packages/protocol_handler_windows/windows/protocol_handler_windows_plugin_c_api.cpp create mode 100644 packages/protocol_handler_windows/windows/test/protocol_handler_windows_plugin_test.cpp diff --git a/README-ZH.md b/README-ZH.md index f85568b..28b345c 100644 --- a/README-ZH.md +++ b/README-ZH.md @@ -21,7 +21,7 @@ -- [protocol_handler](#protocol_handler) +- [protocol\_handler](#protocol_handler) - [平台支持](#平台支持) - [截图](#截图) - [快速开始](#快速开始) @@ -252,10 +252,11 @@ dependencies: #include "flutter_window.h" #include "utils.h" -+#include ++#include int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { ++ // Replace protocol_handler_example with your_window_title. + HWND hwnd = ::FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW", L"protocol_handler_example"); + if (hwnd != NULL) { + DispatchToProtocolHandler(hwnd); diff --git a/README.md b/README.md index b6dcf6e..8f4c3ab 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ English | [简体中文](./README-ZH.md) -- [protocol_handler](#protocol_handler) +- [protocol\_handler](#protocol_handler) - [Platform Support](#platform-support) - [Screenshots](#screenshots) - [Quick Start](#quick-start) @@ -253,10 +253,11 @@ Change the file `windows/runner/main.cpp` as follows: #include "flutter_window.h" #include "utils.h" -+#include ++#include int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { ++ // Replace protocol_handler_example with your_window_title. + HWND hwnd = ::FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW", L"protocol_handler_example"); + if (hwnd != NULL) { + DispatchToProtocolHandler(hwnd); diff --git a/packages/protocol_handler/example/macos/Flutter/GeneratedPluginRegistrant.swift b/packages/protocol_handler/example/macos/Flutter/GeneratedPluginRegistrant.swift index e94b0bd..7d7b7e7 100644 --- a/packages/protocol_handler/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/packages/protocol_handler/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,9 +6,11 @@ import FlutterMacOS import Foundation import protocol_handler_macos +import screen_retriever import window_manager func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ProtocolHandlerMacosPlugin.register(with: registry.registrar(forPlugin: "ProtocolHandlerMacosPlugin")) + ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) } diff --git a/packages/protocol_handler/example/windows/flutter/generated_plugin_registrant.cc b/packages/protocol_handler/example/windows/flutter/generated_plugin_registrant.cc index 31c7678..7116ad1 100644 --- a/packages/protocol_handler/example/windows/flutter/generated_plugin_registrant.cc +++ b/packages/protocol_handler/example/windows/flutter/generated_plugin_registrant.cc @@ -6,12 +6,15 @@ #include "generated_plugin_registrant.h" -#include +#include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { - ProtocolHandlerPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("ProtocolHandlerPlugin")); + ProtocolHandlerWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ProtocolHandlerWindowsPluginCApi")); + ScreenRetrieverPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); WindowManagerPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("WindowManagerPlugin")); } diff --git a/packages/protocol_handler/example/windows/flutter/generated_plugins.cmake b/packages/protocol_handler/example/windows/flutter/generated_plugins.cmake index 835cf6b..f3f62d8 100644 --- a/packages/protocol_handler/example/windows/flutter/generated_plugins.cmake +++ b/packages/protocol_handler/example/windows/flutter/generated_plugins.cmake @@ -3,7 +3,8 @@ # list(APPEND FLUTTER_PLUGIN_LIST - protocol_handler + protocol_handler_windows + screen_retriever window_manager ) diff --git a/packages/protocol_handler/example/windows/runner/main.cpp b/packages/protocol_handler/example/windows/runner/main.cpp index c945387..8f844b2 100644 --- a/packages/protocol_handler/example/windows/runner/main.cpp +++ b/packages/protocol_handler/example/windows/runner/main.cpp @@ -5,10 +5,11 @@ #include "flutter_window.h" #include "utils.h" -#include +#include int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { + // Replace protocol_handler_example with your_window_title. HWND hwnd = ::FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW", L"protocol_handler_example"); if (hwnd != NULL) { DispatchToProtocolHandler(hwnd); diff --git a/packages/protocol_handler/lib/src/protocol_handler.dart b/packages/protocol_handler/lib/src/protocol_handler.dart index cdcf5d2..9790b03 100644 --- a/packages/protocol_handler/lib/src/protocol_handler.dart +++ b/packages/protocol_handler/lib/src/protocol_handler.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; -import 'package:protocol_handler/src/protocol_registrar.dart'; import 'package:protocol_handler_platform_interface/protocol_handler_platform_interface.dart'; class ProtocolHandler { @@ -61,16 +60,16 @@ class ProtocolHandler { } } + /// A broadcast stream of incoming protocol urls. + Stream get onUrlReceived => _platform.onUrlReceived; + /// Register a custom protocol /// /// [scheme] is the custom protocol scheme, e.g. `myapp` Future register(String scheme) { - return protocolRegistrar.register(scheme); + return _platform.register(scheme); } - /// A broadcast stream of incoming protocol urls. - Stream get onUrlReceived => _platform.onUrlReceived; - /// If the app launch was triggered by an protocol, it will give the link url, /// otherwise it will give null. Future getInitialUrl() { diff --git a/packages/protocol_handler/lib/src/protocol_registrar.dart b/packages/protocol_handler/lib/src/protocol_registrar.dart deleted file mode 100644 index 240cce2..0000000 --- a/packages/protocol_handler/lib/src/protocol_registrar.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:protocol_handler/src/protocol_registrar_impl_android.dart'; -import 'package:protocol_handler/src/protocol_registrar_impl_ios.dart'; -import 'package:protocol_handler/src/protocol_registrar_impl_macos.dart'; -import 'package:protocol_handler/src/protocol_registrar_impl_windows.dart' - if (dart.library.html) 'package:protocol_handler/src/protocol_registrar_impl_windows_noop.dart'; - -class ProtocolRegistrar { - /// The shared instance of [ProtocolRegistrar]. - static ProtocolRegistrar get instance { - if (!kIsWeb && Platform.isAndroid) { - return ProtocolRegistrarImplAndroid.instance; - } else if (!kIsWeb && Platform.isIOS) { - return ProtocolRegistrarImplIOS.instance; - } else if (!kIsWeb && Platform.isMacOS) { - return ProtocolRegistrarImplMacOS.instance; - } else if (!kIsWeb && Platform.isWindows) { - return ProtocolRegistrarImplWindows.instance; - } - return ProtocolRegistrar(); - } - - Future register(String scheme) async { - throw UnimplementedError(); - } -} - -final protocolRegistrar = ProtocolRegistrar.instance; diff --git a/packages/protocol_handler/lib/src/protocol_registrar_impl_android.dart b/packages/protocol_handler/lib/src/protocol_registrar_impl_android.dart deleted file mode 100644 index 105df56..0000000 --- a/packages/protocol_handler/lib/src/protocol_registrar_impl_android.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:protocol_handler/src/protocol_registrar.dart'; - -class ProtocolRegistrarImplAndroid extends ProtocolRegistrar { - ProtocolRegistrarImplAndroid._(); - - /// The shared instance of [ProtocolRegistrarImplAndroid]. - static final ProtocolRegistrarImplAndroid instance = - ProtocolRegistrarImplAndroid._(); - - @override - Future register(String scheme) async { - // Skip - } -} diff --git a/packages/protocol_handler/lib/src/protocol_registrar_impl_ios.dart b/packages/protocol_handler/lib/src/protocol_registrar_impl_ios.dart deleted file mode 100644 index f8d4170..0000000 --- a/packages/protocol_handler/lib/src/protocol_registrar_impl_ios.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:protocol_handler/src/protocol_registrar.dart'; - -class ProtocolRegistrarImplIOS extends ProtocolRegistrar { - ProtocolRegistrarImplIOS._(); - - /// The shared instance of [ProtocolRegistrarImplIOS]. - static final ProtocolRegistrarImplIOS instance = ProtocolRegistrarImplIOS._(); - - @override - Future register(String scheme) async { - // Skip - } -} diff --git a/packages/protocol_handler/lib/src/protocol_registrar_impl_macos.dart b/packages/protocol_handler/lib/src/protocol_registrar_impl_macos.dart deleted file mode 100644 index c25ee0c..0000000 --- a/packages/protocol_handler/lib/src/protocol_registrar_impl_macos.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:protocol_handler/src/protocol_registrar.dart'; - -class ProtocolRegistrarImplMacOS extends ProtocolRegistrar { - ProtocolRegistrarImplMacOS._(); - - /// The shared instance of [ProtocolRegistrarImplMacOS]. - static final ProtocolRegistrarImplMacOS instance = - ProtocolRegistrarImplMacOS._(); - - @override - Future register(String scheme) async { - // Skip - } -} diff --git a/packages/protocol_handler/lib/src/protocol_registrar_impl_windows_noop.dart b/packages/protocol_handler/lib/src/protocol_registrar_impl_windows_noop.dart deleted file mode 100644 index c97154b..0000000 --- a/packages/protocol_handler/lib/src/protocol_registrar_impl_windows_noop.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:protocol_handler/src/protocol_registrar.dart'; - -class ProtocolRegistrarImplWindows extends ProtocolRegistrar { - ProtocolRegistrarImplWindows._(); - - /// The shared instance of [ProtocolRegistrarImplWindows]. - static final ProtocolRegistrarImplWindows instance = - ProtocolRegistrarImplWindows._(); - - @override - Future register(String scheme) async {} -} diff --git a/packages/protocol_handler/pubspec.yaml b/packages/protocol_handler/pubspec.yaml index 74d76f4..413c1e7 100644 --- a/packages/protocol_handler/pubspec.yaml +++ b/packages/protocol_handler/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: protocol_handler_ios: ^0.2.0 protocol_handler_macos: ^0.2.0 protocol_handler_platform_interface: ^0.2.0 - win32_registry: ^1.0.2 + protocol_handler_windows: ^0.2.0 dev_dependencies: dependency_validator: ^3.0.0 @@ -38,4 +38,4 @@ flutter: macos: default_package: protocol_handler_macos windows: - pluginClass: ProtocolHandlerPlugin + default_package: protocol_handler_windows diff --git a/packages/protocol_handler/windows/CMakeLists.txt b/packages/protocol_handler/windows/CMakeLists.txt deleted file mode 100644 index 454a8e0..0000000 --- a/packages/protocol_handler/windows/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -set(PROJECT_NAME "protocol_handler") -project(${PROJECT_NAME} LANGUAGES CXX) - -# This value is used when generating builds using this plugin, so it must -# not be changed -set(PLUGIN_NAME "protocol_handler_plugin") - -add_library(${PLUGIN_NAME} SHARED - "protocol_handler_plugin.cpp" -) -apply_standard_settings(${PLUGIN_NAME}) -set_target_properties(${PLUGIN_NAME} PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) -target_compile_definitions(${PLUGIN_NAME} PRIVATE _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) -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 -set(protocol_handler_bundled_libraries - "" - PARENT_SCOPE -) diff --git a/packages/protocol_handler/windows/protocol_handler_plugin.cpp b/packages/protocol_handler/windows/protocol_handler_plugin.cpp deleted file mode 100644 index 22bf650..0000000 --- a/packages/protocol_handler/windows/protocol_handler_plugin.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include "include/protocol_handler/protocol_handler_plugin.h" - -// This must be included before many other Windows headers. -#include - -#include -#include -#include - -#include -#include -#include -#include - -namespace { - -class ProtocolHandlerPlugin : public flutter::Plugin { - public: - static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar); - - ProtocolHandlerPlugin( - flutter::PluginRegistrarWindows* registrar, - std::unique_ptr> channel); - - flutter::MethodChannel* channel() const { - return channel_.get(); - } - - std::string ProtocolHandlerPlugin::GetInitialUrl(); - - virtual ~ProtocolHandlerPlugin(); - - private: - flutter::PluginRegistrarWindows* registrar_; - std::unique_ptr> channel_ = - nullptr; - - int32_t window_proc_id_ = -1; - - std::optional HandleWindowProc(HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam); - - // Called when a method is called on this plugin's channel from Dart. - void HandleMethodCall( - const flutter::MethodCall& method_call, - std::unique_ptr> result); -}; - -// static -void ProtocolHandlerPlugin::RegisterWithRegistrar( - flutter::PluginRegistrarWindows* registrar) { - auto plugin = std::make_unique( - registrar, - std::make_unique>( - registrar->messenger(), "dev.leanflutter.plugins/protocol_handler", - &flutter::StandardMethodCodec::GetInstance())); - plugin->channel()->SetMethodCallHandler( - [plugin_pointer = plugin.get()](const auto& call, auto result) { - plugin_pointer->HandleMethodCall(call, std::move(result)); - }); - registrar->AddPlugin(std::move(plugin)); -} - -ProtocolHandlerPlugin::ProtocolHandlerPlugin( - flutter::PluginRegistrarWindows* registrar, - std::unique_ptr> channel) - : registrar_(registrar), channel_(std::move(channel)) { - window_proc_id_ = registrar->RegisterTopLevelWindowProcDelegate( - [this](HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { - return HandleWindowProc(hwnd, message, wparam, lparam); - }); -} - -ProtocolHandlerPlugin::~ProtocolHandlerPlugin() { - registrar_->UnregisterTopLevelWindowProcDelegate(window_proc_id_); -} - -std::optional ProtocolHandlerPlugin::HandleWindowProc(HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam) { - switch (message) { - case WM_COPYDATA: - COPYDATASTRUCT* cds = {0}; - cds = (COPYDATASTRUCT*)lparam; - - if (cds->dwData == PROTOCOL_MSG_ID) { - std::string url((char*)((LPCWSTR)cds->lpData)); - - flutter::EncodableMap args = flutter::EncodableMap(); - args[flutter::EncodableValue("url")] = - flutter::EncodableValue(url.c_str()); - - channel_->InvokeMethod("onProtocolUrlReceived", - std::make_unique(args)); - } - break; - } - return std::nullopt; -} - -std::string ProtocolHandlerPlugin::GetInitialUrl() { - int argc; - wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - if (argv == nullptr || argc < 2) { - return ""; - } - - std::wstring_convert> converter; - std::string url = converter.to_bytes(argv[1]); - ::LocalFree(argv); - return url; -} - -void ProtocolHandlerPlugin::HandleMethodCall( - const flutter::MethodCall& method_call, - std::unique_ptr> result) { - if (method_call.method_name().compare("getInitialUrl") == 0) { - std::string value = GetInitialUrl(); - result->Success(flutter::EncodableValue(value.c_str())); - } else { - result->NotImplemented(); - } -} - -} // namespace - -void ProtocolHandlerPluginRegisterWithRegistrar( - FlutterDesktopPluginRegistrarRef registrar) { - ProtocolHandlerPlugin::RegisterWithRegistrar( - flutter::PluginRegistrarManager::GetInstance() - ->GetRegistrar(registrar)); -} - -void DispatchToProtocolHandler(HWND hwnd) { - int argc; - wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - if (argv == nullptr || argc < 2) { - return; - } - - std::wstring_convert> converter; - std::string url = converter.to_bytes(argv[1]); - ::LocalFree(argv); - - COPYDATASTRUCT cds = {0}; - cds.dwData = PROTOCOL_MSG_ID; - cds.cbData = (DWORD)(strlen(url.c_str()) + 1); - cds.lpData = (PVOID)url.c_str(); - - SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)&cds); -} diff --git a/packages/protocol_handler_windows/.gitignore b/packages/protocol_handler_windows/.gitignore new file mode 100644 index 0000000..ac5aa98 --- /dev/null +++ b/packages/protocol_handler_windows/.gitignore @@ -0,0 +1,29 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ diff --git a/packages/protocol_handler_windows/.metadata b/packages/protocol_handler_windows/.metadata new file mode 100644 index 0000000..bcaf04f --- /dev/null +++ b/packages/protocol_handler_windows/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "67457e669f79e9f8d13d7a68fe09775fefbb79f4" + channel: "stable" + +project_type: plugin + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4 + base_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4 + - platform: windows + create_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4 + base_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/protocol_handler_windows/CHANGELOG.md b/packages/protocol_handler_windows/CHANGELOG.md new file mode 100644 index 0000000..2f145ce --- /dev/null +++ b/packages/protocol_handler_windows/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.2.0 + +* First release. diff --git a/packages/protocol_handler_windows/LICENSE b/packages/protocol_handler_windows/LICENSE new file mode 100644 index 0000000..eea05ab --- /dev/null +++ b/packages/protocol_handler_windows/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2024 LiJianying + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/protocol_handler_windows/README.md b/packages/protocol_handler_windows/README.md new file mode 100644 index 0000000..760bcf9 --- /dev/null +++ b/packages/protocol_handler_windows/README.md @@ -0,0 +1,12 @@ +# protocol_handler_windows + +[![pub version][pub-image]][pub-url] + +[pub-image]: https://img.shields.io/pub/v/protocol_handler_windows.svg +[pub-url]: https://pub.dev/packages/protocol_handler_windows + +The Windows implementation of [protocol_handler](https://pub.dev/packages/protocol_handler). + +## License + +[MIT](./LICENSE) diff --git a/packages/protocol_handler_windows/analysis_options.yaml b/packages/protocol_handler_windows/analysis_options.yaml new file mode 100644 index 0000000..095b1d6 --- /dev/null +++ b/packages/protocol_handler_windows/analysis_options.yaml @@ -0,0 +1 @@ +include: package:mostly_reasonable_lints/flutter.yaml diff --git a/packages/protocol_handler_windows/lib/protocol_handler_windows.dart b/packages/protocol_handler_windows/lib/protocol_handler_windows.dart new file mode 100644 index 0000000..a1c6c06 --- /dev/null +++ b/packages/protocol_handler_windows/lib/protocol_handler_windows.dart @@ -0,0 +1,3 @@ +library protocol_handler_windows; + +export 'src/protocol_handler_windows.dart'; diff --git a/packages/protocol_handler/lib/src/protocol_registrar_impl_windows.dart b/packages/protocol_handler_windows/lib/src/protocol_handler_windows.dart similarity index 63% rename from packages/protocol_handler/lib/src/protocol_registrar_impl_windows.dart rename to packages/protocol_handler_windows/lib/src/protocol_handler_windows.dart index 4d37e48..609831c 100644 --- a/packages/protocol_handler/lib/src/protocol_registrar_impl_windows.dart +++ b/packages/protocol_handler_windows/lib/src/protocol_handler_windows.dart @@ -1,14 +1,16 @@ import 'dart:io'; -import 'package:protocol_handler/src/protocol_registrar.dart'; +import 'package:protocol_handler_platform_interface/protocol_handler_platform_interface.dart'; import 'package:win32_registry/win32_registry.dart'; -class ProtocolRegistrarImplWindows extends ProtocolRegistrar { - ProtocolRegistrarImplWindows._(); +class ProtocolHandlerWindows extends MethodChannelProtocolHandler { + /// The [ProtocolHandlerWindows] constructor. + ProtocolHandlerWindows() : super(); - /// The shared instance of [ProtocolRegistrarImplWindows]. - static final ProtocolRegistrarImplWindows instance = - ProtocolRegistrarImplWindows._(); + /// Registers this class as the default instance of [ProtocolHandlerWindows]. + static void registerWith() { + ProtocolHandlerPlatform.instance = ProtocolHandlerWindows(); + } @override Future register(String scheme) async { diff --git a/packages/protocol_handler_windows/pubspec.yaml b/packages/protocol_handler_windows/pubspec.yaml new file mode 100644 index 0000000..4d1408f --- /dev/null +++ b/packages/protocol_handler_windows/pubspec.yaml @@ -0,0 +1,27 @@ +name: protocol_handler_windows +description: Windows implementation of the protocol_handler plugin. +version: 0.2.0 +repository: https://github.com/leanflutter/protocol_handler/tree/main/packages/protocol_handler_windows + +environment: + sdk: ">=3.1.0 <4.0.0" + flutter: ">=3.16.0" + +dependencies: + flutter: + sdk: flutter + protocol_handler_platform_interface: ^0.2.0 + win32_registry: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + mostly_reasonable_lints: ^0.1.1 + +flutter: + plugin: + implements: protocol_handler + platforms: + windows: + dartPluginClass: ProtocolHandlerWindows + pluginClass: ProtocolHandlerWindowsPluginCApi diff --git a/packages/protocol_handler/windows/.gitignore b/packages/protocol_handler_windows/windows/.gitignore similarity index 100% rename from packages/protocol_handler/windows/.gitignore rename to packages/protocol_handler_windows/windows/.gitignore diff --git a/packages/protocol_handler_windows/windows/CMakeLists.txt b/packages/protocol_handler_windows/windows/CMakeLists.txt new file mode 100644 index 0000000..6f4a422 --- /dev/null +++ b/packages/protocol_handler_windows/windows/CMakeLists.txt @@ -0,0 +1,101 @@ +# 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 "protocol_handler_windows") +project(${PROJECT_NAME} LANGUAGES CXX) + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# This value is used when generating builds using this plugin, so it must +# not be changed +set(PLUGIN_NAME "protocol_handler_windows_plugin") + +# Any new source files that you add to the plugin should be added here. +list(APPEND PLUGIN_SOURCES + "protocol_handler_windows_plugin.cpp" + "protocol_handler_windows_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/protocol_handler_windows/protocol_handler_windows_plugin_c_api.h" + "protocol_handler_windows_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) +target_compile_definitions(${PLUGIN_NAME} PRIVATE _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) + +# 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(protocol_handler_windows_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/protocol_handler_windows_plugin_test.cpp + ${PLUGIN_SOURCES} +) +apply_standard_settings(${TEST_RUNNER}) +target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") +target_link_libraries(${TEST_RUNNER} PRIVATE flutter_wrapper_plugin) +target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock) +# flutter_wrapper_plugin has link dependencies on the Flutter DLL. +add_custom_command(TARGET ${TEST_RUNNER} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${FLUTTER_LIBRARY}" $ +) + +# Enable automatic test discovery. +include(GoogleTest) +gtest_discover_tests(${TEST_RUNNER}) +endif() diff --git a/packages/protocol_handler/windows/include/protocol_handler/protocol_handler_plugin.h b/packages/protocol_handler_windows/windows/include/protocol_handler_windows/protocol_handler_windows_plugin_c_api.h similarity index 62% rename from packages/protocol_handler/windows/include/protocol_handler/protocol_handler_plugin.h rename to packages/protocol_handler_windows/windows/include/protocol_handler_windows/protocol_handler_windows_plugin_c_api.h index cbe229a..6c7099e 100644 --- a/packages/protocol_handler/windows/include/protocol_handler/protocol_handler_plugin.h +++ b/packages/protocol_handler_windows/windows/include/protocol_handler_windows/protocol_handler_windows_plugin_c_api.h @@ -1,7 +1,7 @@ #include -#ifndef FLUTTER_PLUGIN_PROTOCOL_HANDLER_PLUGIN_H_ -#define FLUTTER_PLUGIN_PROTOCOL_HANDLER_PLUGIN_H_ +#ifndef FLUTTER_PLUGIN_PROTOCOL_HANDLER_WINDOWS_PLUGIN_C_API_H_ +#define FLUTTER_PLUGIN_PROTOCOL_HANDLER_WINDOWS_PLUGIN_C_API_H_ #include @@ -15,7 +15,8 @@ extern "C" { #endif -FLUTTER_PLUGIN_EXPORT void ProtocolHandlerPluginRegisterWithRegistrar( +FLUTTER_PLUGIN_EXPORT void +ProtocolHandlerWindowsPluginCApiRegisterWithRegistrar( FlutterDesktopPluginRegistrarRef registrar); #define PROTOCOL_MSG_ID (WM_USER + 2) @@ -25,4 +26,4 @@ FLUTTER_PLUGIN_EXPORT void DispatchToProtocolHandler(HWND hwnd); } // extern "C" #endif -#endif // FLUTTER_PLUGIN_PROTOCOL_HANDLER_PLUGIN_H_ +#endif // FLUTTER_PLUGIN_PROTOCOL_HANDLER_WINDOWS_PLUGIN_C_API_H_ diff --git a/packages/protocol_handler_windows/windows/protocol_handler_windows_plugin.cpp b/packages/protocol_handler_windows/windows/protocol_handler_windows_plugin.cpp new file mode 100644 index 0000000..a1d8b44 --- /dev/null +++ b/packages/protocol_handler_windows/windows/protocol_handler_windows_plugin.cpp @@ -0,0 +1,128 @@ +#include "include/protocol_handler_windows/protocol_handler_windows_plugin_c_api.h" +#include "protocol_handler_windows_plugin.h" + +// This must be included before many other Windows headers. +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace protocol_handler_windows { + +// static +void ProtocolHandlerWindowsPlugin::RegisterWithRegistrar( + flutter::PluginRegistrarWindows* registrar) { + auto channel = + std::make_unique>( + registrar->messenger(), "dev.leanflutter.plugins/protocol_handler", + &flutter::StandardMethodCodec::GetInstance()); + + auto plugin = std::make_unique(registrar); + + channel->SetMethodCallHandler( + [plugin_pointer = plugin.get()](const auto& call, auto result) { + plugin_pointer->HandleMethodCall(call, std::move(result)); + }); + + auto event_channel = + std::make_unique>( + registrar->messenger(), + "dev.leanflutter.plugins/protocol_handler_event", + &flutter::StandardMethodCodec::GetInstance()); + auto streamHandler = std::make_unique>( + [plugin_pointer = plugin.get()]( + const flutter::EncodableValue* arguments, + std::unique_ptr>&& events) + -> std::unique_ptr> { + return plugin_pointer->OnListen(arguments, std::move(events)); + }, + [plugin_pointer = plugin.get()](const flutter::EncodableValue* arguments) + -> std::unique_ptr> { + return plugin_pointer->OnCancel(arguments); + }); + event_channel->SetStreamHandler(std::move(streamHandler)); + + registrar->AddPlugin(std::move(plugin)); +} + +ProtocolHandlerWindowsPlugin::ProtocolHandlerWindowsPlugin( + flutter::PluginRegistrarWindows* registrar) { + window_proc_id_ = registrar->RegisterTopLevelWindowProcDelegate( + [this](HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { + return HandleWindowProc(hwnd, message, wparam, lparam); + }); +} + +ProtocolHandlerWindowsPlugin::~ProtocolHandlerWindowsPlugin() {} + +std::optional ProtocolHandlerWindowsPlugin::HandleWindowProc( + HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + switch (message) { + case WM_COPYDATA: + COPYDATASTRUCT* cds = {0}; + cds = (COPYDATASTRUCT*)lparam; + + if (cds->dwData == PROTOCOL_MSG_ID) { + std::string url((char*)((LPCWSTR)cds->lpData)); + + flutter::EncodableMap args = flutter::EncodableMap(); + args[flutter::EncodableValue("url")] = + flutter::EncodableValue(url.c_str()); + if (event_sink_) { + event_sink_->Success(flutter::EncodableValue(url.c_str())); + } + } + break; + } + return std::nullopt; +} + +std::string ProtocolHandlerWindowsPlugin::GetInitialUrl() { + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr || argc < 2) { + return ""; + } + + std::wstring_convert> converter; + std::string url = converter.to_bytes(argv[1]); + ::LocalFree(argv); + return url; +} + +void ProtocolHandlerWindowsPlugin::HandleMethodCall( + const flutter::MethodCall& method_call, + std::unique_ptr> result) { + if (method_call.method_name().compare("getInitialUrl") == 0) { + std::string value = GetInitialUrl(); + result->Success(flutter::EncodableValue(value.c_str())); + } else { + result->NotImplemented(); + } +} + +std::unique_ptr> +ProtocolHandlerWindowsPlugin::OnListenInternal( + const flutter::EncodableValue* arguments, + std::unique_ptr>&& events) { + event_sink_ = std::move(events); + return nullptr; +} + +std::unique_ptr> +ProtocolHandlerWindowsPlugin::OnCancelInternal( + const flutter::EncodableValue* arguments) { + event_sink_ = nullptr; + return nullptr; +} + +} // namespace protocol_handler_windows diff --git a/packages/protocol_handler_windows/windows/protocol_handler_windows_plugin.h b/packages/protocol_handler_windows/windows/protocol_handler_windows_plugin.h new file mode 100644 index 0000000..e7aa96a --- /dev/null +++ b/packages/protocol_handler_windows/windows/protocol_handler_windows_plugin.h @@ -0,0 +1,55 @@ +#ifndef FLUTTER_PLUGIN_PROTOCOL_HANDLER_WINDOWS_PLUGIN_H_ +#define FLUTTER_PLUGIN_PROTOCOL_HANDLER_WINDOWS_PLUGIN_H_ + +#include +#include +#include +#include + +#include + +namespace protocol_handler_windows { + +class ProtocolHandlerWindowsPlugin + : public flutter::Plugin, + flutter::StreamHandler { + private: + std::unique_ptr> event_sink_; + + int32_t window_proc_id_ = -1; + + std::optional HandleWindowProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam); + + public: + static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar); + + ProtocolHandlerWindowsPlugin(flutter::PluginRegistrarWindows* registrar); + + virtual ~ProtocolHandlerWindowsPlugin(); + + // Disallow copy and assign. + ProtocolHandlerWindowsPlugin(const ProtocolHandlerWindowsPlugin&) = delete; + ProtocolHandlerWindowsPlugin& operator=(const ProtocolHandlerWindowsPlugin&) = + delete; + + std::string ProtocolHandlerWindowsPlugin::GetInitialUrl(); + + // Called when a method is called on this plugin's channel from Dart. + void HandleMethodCall( + const flutter::MethodCall& method_call, + std::unique_ptr> result); + + std::unique_ptr> OnListenInternal( + const flutter::EncodableValue* arguments, + std::unique_ptr>&& events) override; + + std::unique_ptr> OnCancelInternal( + const flutter::EncodableValue* arguments) override; +}; + +} // namespace protocol_handler_windows + +#endif // FLUTTER_PLUGIN_PROTOCOL_HANDLER_WINDOWS_PLUGIN_H_ diff --git a/packages/protocol_handler_windows/windows/protocol_handler_windows_plugin_c_api.cpp b/packages/protocol_handler_windows/windows/protocol_handler_windows_plugin_c_api.cpp new file mode 100644 index 0000000..394fff4 --- /dev/null +++ b/packages/protocol_handler_windows/windows/protocol_handler_windows_plugin_c_api.cpp @@ -0,0 +1,33 @@ +#include "include/protocol_handler_windows/protocol_handler_windows_plugin_c_api.h" + +#include + +#include "protocol_handler_windows_plugin.h" + +#include + +void ProtocolHandlerWindowsPluginCApiRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar) { + protocol_handler_windows::ProtocolHandlerWindowsPlugin::RegisterWithRegistrar( + flutter::PluginRegistrarManager::GetInstance() + ->GetRegistrar(registrar)); +} + +void DispatchToProtocolHandler(HWND hwnd) { + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr || argc < 2) { + return; + } + + std::wstring_convert> converter; + std::string url = converter.to_bytes(argv[1]); + ::LocalFree(argv); + + COPYDATASTRUCT cds = {0}; + cds.dwData = PROTOCOL_MSG_ID; + cds.cbData = (DWORD)(strlen(url.c_str()) + 1); + cds.lpData = (PVOID)url.c_str(); + + SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)&cds); +} diff --git a/packages/protocol_handler_windows/windows/test/protocol_handler_windows_plugin_test.cpp b/packages/protocol_handler_windows/windows/test/protocol_handler_windows_plugin_test.cpp new file mode 100644 index 0000000..aed2991 --- /dev/null +++ b/packages/protocol_handler_windows/windows/test/protocol_handler_windows_plugin_test.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "protocol_handler_windows_plugin.h" + +namespace protocol_handler_windows { +namespace test { + +namespace { + +using flutter::EncodableMap; +using flutter::EncodableValue; +using flutter::MethodCall; +using flutter::MethodResultFunctions; + +} // namespace + +TEST(ProtocolHandlerWindowsPlugin, GetPlatformVersion) { + ProtocolHandlerWindowsPlugin plugin; + // Save the reply value from the success callback. + std::string result_string; + plugin.HandleMethodCall( + MethodCall("getPlatformVersion", std::make_unique()), + std::make_unique>( + [&result_string](const EncodableValue* result) { + result_string = std::get(*result); + }, + nullptr, nullptr)); + + // Since the exact string varies by host, just ensure that it's a string + // with the expected format. + EXPECT_TRUE(result_string.rfind("Windows ", 0) == 0); +} + +} // namespace test +} // namespace protocol_handler_windows