diff --git a/packages/desktop_webview_window/CHANGELOG.md b/packages/desktop_webview_window/CHANGELOG.md index f5464974..cca876f5 100644 --- a/packages/desktop_webview_window/CHANGELOG.md +++ b/packages/desktop_webview_window/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.2.5 + +* Add support for `registerJavaScriptMessageHandler` and `unregisterJavaScriptMessageHandler` on + Linux. Use `window.webkit.messageHandlers..postMessage()` in js + ## 0.2.4 * Add backward compatibility with webkit2gtk-4.0 on Linux @@ -9,16 +14,22 @@ ## 0.2.2 * fix memory leak on macOS after close webview window. -* Show and Hide Webview window by [@Iri-Hor](https://github.com/Iri-Hor) in [#268](https://github.com/MixinNetwork/flutter-plugins/pull/268) +* Show and Hide Webview window by [@Iri-Hor](https://github.com/Iri-Hor) + in [#268](https://github.com/MixinNetwork/flutter-plugins/pull/268) ## 0.2.1 * add Windows attentions to readme. * fix linux close sub window cause app exited. * fix linux webview title bar expanded unexpected. -* More control over webview position and size under windows. [#206](https://github.com/MixinNetwork/flutter-plugins/pull/206) by [Lukas Heinze](https://github.com/Iri-Hor) -* fix zone mismatch [#250](https://github.com/MixinNetwork/flutter-plugins/pull/250) by [CD](https://github.com/459217974) -* fix linux webkit2gtk deprecated error [#246](https://github.com/MixinNetwork/flutter-plugins/pull/246) by [Zhiqiang Zhang](https://github.com/zhangzqs) +* More control over webview position and size under + windows. [#206](https://github.com/MixinNetwork/flutter-plugins/pull/206) + by [Lukas Heinze](https://github.com/Iri-Hor) +* fix zone mismatch [#250](https://github.com/MixinNetwork/flutter-plugins/pull/250) + by [CD](https://github.com/459217974) +* fix linux webkit2gtk deprecated + error [#246](https://github.com/MixinNetwork/flutter-plugins/pull/246) + by [Zhiqiang Zhang](https://github.com/zhangzqs) ## 0.2.0 @@ -63,7 +74,8 @@ NOTE: contains break change. more details see readme. ## 0.0.6 -fix swift definition conflict on macOS. [flutter-plugins#17](https://github.com/MixinNetwork/flutter-plugins/issues/17) +fix swift definition conflict on +macOS. [flutter-plugins#17](https://github.com/MixinNetwork/flutter-plugins/issues/17) ## 0.0.5 diff --git a/packages/desktop_webview_window/lib/src/webview_impl.dart b/packages/desktop_webview_window/lib/src/webview_impl.dart index 2ef6e706..a25c356d 100644 --- a/packages/desktop_webview_window/lib/src/webview_impl.dart +++ b/packages/desktop_webview_window/lib/src/webview_impl.dart @@ -25,7 +25,7 @@ class WebviewImpl extends Webview { final ValueNotifier _isNavigating = ValueNotifier(false); - OnUrlRequestCallback? _onUrlRequestCallback = null; + OnUrlRequestCallback? _onUrlRequestCallback; final Set _onWebMessageReceivedCallbacks = {}; @@ -85,7 +85,7 @@ class WebviewImpl extends Webview { @override void registerJavaScriptMessageHandler( String name, JavaScriptMessageHandler handler) { - if (!Platform.isMacOS) { + if (!(Platform.isMacOS || Platform.isLinux)) { return; } assert(!_closed); @@ -103,7 +103,7 @@ class WebviewImpl extends Webview { @override void unregisterJavaScriptMessageHandler(String name) { - if (!Platform.isMacOS) { + if (!(Platform.isMacOS || Platform.isLinux)) { return; } if (_closed) { diff --git a/packages/desktop_webview_window/linux/CMakeLists.txt b/packages/desktop_webview_window/linux/CMakeLists.txt index d999fd7f..13768238 100644 --- a/packages/desktop_webview_window/linux/CMakeLists.txt +++ b/packages/desktop_webview_window/linux/CMakeLists.txt @@ -1,42 +1,73 @@ +# 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 "desktop_webview_window") project(${PROJECT_NAME} LANGUAGES CXX) # This value is used when generating builds using this plugin, so it must -# not be changed +# not be changed. set(PLUGIN_NAME "desktop_webview_window_plugin") + +# === WebKit and libsoup dependencies === find_package(PkgConfig REQUIRED) -pkg_check_modules(WebKit IMPORTED_TARGET webkit2gtk-4.1) + +# Try webkit2gtk-4.1 first, then fallback to 4.0 +pkg_check_modules(WebKit IMPORTED_TARGET webkit2gtk-4.1) if (NOT WebKit_FOUND) - pkg_check_modules(WebKit REQUIRED IMPORTED_TARGET webkit2gtk-4.0) # for backward compatibility + pkg_check_modules(WebKit REQUIRED IMPORTED_TARGET webkit2gtk-4.0) endif () +# Try libsoup-3.0, fallback to libsoup-2.4 pkg_check_modules(LibSoup REQUIRED IMPORTED_TARGET libsoup-3.0) if (NOT LibSoup_FOUND) - pkg_check_modules(LibSoup REQUIRED IMPORTED_TARGET libsoup-2.4) -endif() + pkg_check_modules(LibSoup REQUIRED IMPORTED_TARGET libsoup-2.4) +endif () +# Any new source files that you add to the plugin should be added here. +list(APPEND PLUGIN_SOURCES + "desktop_webview_window_plugin.cc" + "webview_window.cc" + "webview_window.h" + "message_channel_plugin.h" + "message_channel_plugin.cc" +) +# Define the plugin library target. Its name must not be changed (see comment +# on PLUGIN_NAME above). add_library(${PLUGIN_NAME} SHARED - "desktop_webview_window_plugin.cc" - webview_window.cc - webview_window.h - message_channel_plugin.h - message_channel_plugin.cc - ) + ${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-spec ific +# 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) target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::WebKit) +target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::LibSoup) + -# 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 +# external build triggered from this build file. set(desktop_webview_window_bundled_libraries "" PARENT_SCOPE - ) +) diff --git a/packages/desktop_webview_window/linux/desktop_webview_window_plugin.cc b/packages/desktop_webview_window/linux/desktop_webview_window_plugin.cc index a57e8b54..f10d729d 100644 --- a/packages/desktop_webview_window/linux/desktop_webview_window_plugin.cc +++ b/packages/desktop_webview_window/linux/desktop_webview_window_plugin.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -13,7 +14,7 @@ namespace { -int64_t next_window_id_ = 0; + int64_t next_window_id_ = 0; } @@ -22,285 +23,319 @@ int64_t next_window_id_ = 0; WebviewWindowPlugin)) struct _WebviewWindowPlugin { - GObject parent_instance; - FlMethodChannel *method_channel; - std::map> *windows; + GObject parent_instance; + FlMethodChannel *method_channel; + std::map > *windows; }; -G_DEFINE_TYPE(WebviewWindowPlugin, webview_window_plugin, g_object_get_type()) +G_DEFINE_TYPE(WebviewWindowPlugin, webview_window_plugin, g_object_get_type() +) // Called when a method call is received from Flutter. static void webview_window_plugin_handle_method_call( - WebviewWindowPlugin *self, FlMethodCall *method_call) { - const gchar *method = fl_method_call_get_name(method_call); + WebviewWindowPlugin * self, FlMethodCall * method_call) { + const gchar *method = fl_method_call_get_name(method_call); - if (strcmp(method, "create") == 0) { - auto *args = fl_method_call_get_args(method_call); - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error(method_call, "0", "create args is not map", - nullptr, nullptr); - return; - } - auto width = fl_value_get_int(fl_value_lookup_string(args, "windowWidth")); - auto height = - fl_value_get_int(fl_value_lookup_string(args, "windowHeight")); - auto title = fl_value_get_string(fl_value_lookup_string(args, "title")); - auto title_bar_height = - fl_value_get_int(fl_value_lookup_string(args, "titleBarHeight")); + if (strcmp(method, "create") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error(method_call, "0", "create args is not map", + nullptr, nullptr); + return; + } + auto width = fl_value_get_int(fl_value_lookup_string(args, "windowWidth")); + auto height = + fl_value_get_int(fl_value_lookup_string(args, "windowHeight")); + auto title = fl_value_get_string(fl_value_lookup_string(args, "title")); + auto title_bar_height = + fl_value_get_int(fl_value_lookup_string(args, "titleBarHeight")); - auto window_id = next_window_id_; - g_object_ref(self); - auto webview = std::make_unique( - self->method_channel, window_id, - [self, window_id]() { - self->windows->erase(window_id); - g_object_unref(self); - }, - title, width, height, title_bar_height); - self->windows->insert({window_id, std::move(webview)}); - next_window_id_++; - fl_method_call_respond_success(method_call, fl_value_new_int(window_id), - nullptr); - } else if (strcmp(method, "launch") == 0) { - auto *args = fl_method_call_get_args(method_call); - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error(method_call, "0", "create args is not map", - nullptr, nullptr); - return; - } - auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); - auto url = fl_value_get_string(fl_value_lookup_string(args, "url")); + auto window_id = next_window_id_; + g_object_ref(self); + auto webview = std::make_unique( + self->method_channel, window_id, + [self, window_id]() { + self->windows->erase(window_id); + g_object_unref(self); + }, + title, width, height, title_bar_height); + self->windows->insert({window_id, std::move(webview)}); + next_window_id_++; + fl_method_call_respond_success(method_call, fl_value_new_int(window_id), + nullptr); + } else if (strcmp(method, "launch") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error(method_call, "0", "create args is not map", + nullptr, nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + auto url = fl_value_get_string(fl_value_lookup_string(args, "url")); - if (!self->windows->count(window_id)) { - fl_method_call_respond_error(method_call, "0", - "can not found webview for viewId", nullptr, - nullptr); - return; - } + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", + "can not found webview for viewId", nullptr, + nullptr); + return; + } - self->windows->at(window_id)->Navigate(url); - fl_method_call_respond_success(method_call, nullptr, nullptr); - } else if (strcmp(method, "addScriptToExecuteOnDocumentCreated") == 0) { - auto *args = fl_method_call_get_args(method_call); - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error(method_call, "0", "args is not map", nullptr, - nullptr); - return; - } - auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); - auto java_script = - fl_value_get_string(fl_value_lookup_string(args, "javaScript")); + self->windows->at(window_id)->Navigate(url); + fl_method_call_respond_success(method_call, nullptr, nullptr); + } else if (strcmp(method, "addScriptToExecuteOnDocumentCreated") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error(method_call, "0", "args is not map", nullptr, + nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + auto java_script = + fl_value_get_string(fl_value_lookup_string(args, "javaScript")); - if (!self->windows->count(window_id)) { - fl_method_call_respond_error(method_call, "0", - "can not found webview for viewId", nullptr, - nullptr); - return; - } - self->windows->at(window_id)->RunJavaScriptWhenContentReady(java_script); - fl_method_call_respond_success(method_call, nullptr, nullptr); - } else if (strcmp(method, "clearAll") == 0) { - for (const auto &item : *self->windows) { - item.second->Close(); - } - // If application didn't create a webview, but we called - // webkit_website_data_manager_clear, there will be a segment fault. To - // avoid crash, we create a fake webview first and then clear all data. - auto *web_view = webkit_web_view_new(); - auto *context = webkit_web_view_get_context(WEBKIT_WEB_VIEW(web_view)); - auto *website_data_manager = - webkit_web_context_get_website_data_manager(context); - webkit_website_data_manager_clear(website_data_manager, - WEBKIT_WEBSITE_DATA_ALL, 0, nullptr, - nullptr, nullptr); - fl_method_call_respond_success(method_call, nullptr, nullptr); - } else if (strcmp(method, "setApplicationNameForUserAgent") == 0) { - auto *args = fl_method_call_get_args(method_call); - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error( - method_call, "0", "setApplicationNameForUserAgent args is not map", - nullptr, nullptr); - return; - } - auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); - auto application_name = - fl_value_get_string(fl_value_lookup_string(args, "applicationName")); + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", + "can not found webview for viewId", nullptr, + nullptr); + return; + } + self->windows->at(window_id)->RunJavaScriptWhenContentReady(java_script); + fl_method_call_respond_success(method_call, nullptr, nullptr); + } else if (strcmp(method, "clearAll") == 0) { + for (const auto &item: *self->windows) { + item.second->Close(); + } + // If application didn't create a webview, but we called + // webkit_website_data_manager_clear, there will be a segment fault. To + // avoid crash, we create a fake webview first and then clear all data. + auto *web_view = webkit_web_view_new(); + auto *context = webkit_web_view_get_context(WEBKIT_WEB_VIEW(web_view)); + auto *website_data_manager = + webkit_web_context_get_website_data_manager(context); + webkit_website_data_manager_clear(website_data_manager, + WEBKIT_WEBSITE_DATA_ALL, 0, nullptr, + nullptr, nullptr); + fl_method_call_respond_success(method_call, nullptr, nullptr); + } else if (strcmp(method, "setApplicationNameForUserAgent") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error( + method_call, "0", "setApplicationNameForUserAgent args is not map", + nullptr, nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + auto application_name = + fl_value_get_string(fl_value_lookup_string(args, "applicationName")); - if (!self->windows->count(window_id)) { - fl_method_call_respond_error(method_call, "0", - "can not found webview for viewId", nullptr, - nullptr); - return; - } - self->windows->at(window_id)->SetApplicationNameForUserAgent( - application_name); - fl_method_call_respond_success(method_call, nullptr, nullptr); - } else if (strcmp(method, "back") == 0) { - auto *args = fl_method_call_get_args(method_call); - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error(method_call, "0", "back args is not map", - nullptr, nullptr); - return; - } - auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); - if (!self->windows->count(window_id)) { - fl_method_call_respond_error(method_call, "0", - "can not found webview for viewId", nullptr, - nullptr); - return; - } - self->windows->at(window_id)->GoBack(); - fl_method_call_respond_success(method_call, nullptr, nullptr); - } else if (strcmp(method, "forward") == 0) { - auto *args = fl_method_call_get_args(method_call); - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error(method_call, "0", "forward args is not map", - nullptr, nullptr); - return; - } - auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); - if (!self->windows->count(window_id)) { - fl_method_call_respond_error(method_call, "0", - "can not found webview for viewId", nullptr, - nullptr); - return; - } - self->windows->at(window_id)->GoForward(); - fl_method_call_respond_success(method_call, nullptr, nullptr); - } else if (strcmp(method, "reload") == 0) { - auto *args = fl_method_call_get_args(method_call); - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error(method_call, "0", "reload args is not map", - nullptr, nullptr); - return; - } - auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); - if (!self->windows->count(window_id)) { - fl_method_call_respond_error(method_call, "0", - "can not found webview for viewId", nullptr, - nullptr); - return; - } - self->windows->at(window_id)->Reload(); - fl_method_call_respond_success(method_call, nullptr, nullptr); - } else if (strcmp(method, "stop") == 0) { - auto *args = fl_method_call_get_args(method_call); - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error(method_call, "0", "stop args is not map", - nullptr, nullptr); - return; - } - auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); - if (!self->windows->count(window_id)) { - fl_method_call_respond_error(method_call, "0", - "can not found webview for viewId", nullptr, - nullptr); - return; - } - self->windows->at(window_id)->StopLoading(); - fl_method_call_respond_success(method_call, nullptr, nullptr); - } else if (strcmp(method, "getAllCookies") == 0) { - auto *args = fl_method_call_get_args(method_call); - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error( - method_call, "0", "getAllCookies args is not map", nullptr, nullptr); - return; - } - auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); - if (!self->windows->count(window_id)) { - fl_method_call_respond_error(method_call, "0", - "can not found webview for viewId", nullptr, - nullptr); - return; - } + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", + "can not found webview for viewId", nullptr, + nullptr); + return; + } + self->windows->at(window_id)->SetApplicationNameForUserAgent( + application_name); + fl_method_call_respond_success(method_call, nullptr, nullptr); + } else if (strcmp(method, "back") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error(method_call, "0", "back args is not map", + nullptr, nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", + "can not found webview for viewId", nullptr, + nullptr); + return; + } + self->windows->at(window_id)->GoBack(); + fl_method_call_respond_success(method_call, nullptr, nullptr); + } else if (strcmp(method, "forward") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error(method_call, "0", "forward args is not map", + nullptr, nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", + "can not found webview for viewId", nullptr, + nullptr); + return; + } + self->windows->at(window_id)->GoForward(); + fl_method_call_respond_success(method_call, nullptr, nullptr); + } else if (strcmp(method, "reload") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error(method_call, "0", "reload args is not map", + nullptr, nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", + "can not found webview for viewId", nullptr, + nullptr); + return; + } + self->windows->at(window_id)->Reload(); + fl_method_call_respond_success(method_call, nullptr, nullptr); + } else if (strcmp(method, "stop") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error(method_call, "0", "stop args is not map", + nullptr, nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", + "can not found webview for viewId", nullptr, + nullptr); + return; + } + self->windows->at(window_id)->StopLoading(); + fl_method_call_respond_success(method_call, nullptr, nullptr); + } else if (strcmp(method, "getAllCookies") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error( + method_call, "0", "getAllCookies args is not map", nullptr, nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", + "can not found webview for viewId", nullptr, + nullptr); + return; + } - FlValue *data = nullptr; + FlValue *data = self->windows->at(window_id)->GetAllCookies(); - data = self->windows->at(window_id)->GetAllCookies(); + if (data == nullptr) { + fl_method_call_respond_error(method_call, "0", "get all cookies failed", + nullptr, nullptr); + return; + } - if (data == nullptr) { - fl_method_call_respond_error(method_call, "0", "get all cookies failed", - nullptr, nullptr); - return; - } + fl_method_call_respond_success(method_call, data, nullptr); + fl_value_unref(data); + } else if (strcmp(method, "close") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error(method_call, "0", "close args is not map", + nullptr, nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", + "can not found webview for viewId", nullptr, + nullptr); + return; + } + self->windows->at(window_id)->Close(); + fl_method_call_respond_success(method_call, nullptr, nullptr); + } else if (strcmp(method, "evaluateJavaScript") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error(method_call, "0", + "evaluateJavaScript args is not map", + nullptr, nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", + "can not found webview for viewId", nullptr, + nullptr); + return; + } + auto *js = + fl_value_get_string(fl_value_lookup_string(args, "javaScriptString")); + self->windows->at(window_id)->EvaluateJavaScript(js, method_call); + } else if (strcmp(method, "registerJavaScripInterface") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error(method_call, "0", "args is not map", nullptr, nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + const gchar *channel_name = fl_value_get_string(fl_value_lookup_string(args, "name")); - fl_method_call_respond_success(method_call, data, nullptr); - fl_value_unref(data); - } else if (strcmp(method, "close") == 0) { - auto *args = fl_method_call_get_args(method_call); - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error(method_call, "0", "close args is not map", - nullptr, nullptr); - return; - } - auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); - if (!self->windows->count(window_id)) { - fl_method_call_respond_error(method_call, "0", - "can not found webview for viewId", nullptr, - nullptr); - return; - } - self->windows->at(window_id)->Close(); - fl_method_call_respond_success(method_call, nullptr, nullptr); - } else if (strcmp(method, "evaluateJavaScript") == 0) { - auto *args = fl_method_call_get_args(method_call); - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { - fl_method_call_respond_error(method_call, "0", - "evaluateJavaScript args is not map", - nullptr, nullptr); - return; - } - auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); - if (!self->windows->count(window_id)) { - fl_method_call_respond_error(method_call, "0", - "can not found webview for viewId", nullptr, - nullptr); - return; + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", "cannot find webview for viewId", + nullptr, nullptr); + return; + } + self->windows->at(window_id)->RegisterJavaScriptChannel(channel_name); + fl_method_call_respond_success(method_call, nullptr, nullptr); + + } else if (strcmp(method, "unregisterJavaScripInterface") == 0) { + auto *args = fl_method_call_get_args(method_call); + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + fl_method_call_respond_error(method_call, "0", "args is not map", nullptr, nullptr); + return; + } + auto window_id = fl_value_get_int(fl_value_lookup_string(args, "viewId")); + const gchar *channel_name = fl_value_get_string(fl_value_lookup_string(args, "name")); + + if (!self->windows->count(window_id)) { + fl_method_call_respond_error(method_call, "0", "cannot find webview for viewId", + nullptr, nullptr); + return; + } + self->windows->at(window_id)->UnregisterJavaScriptChannel(channel_name); + fl_method_call_respond_success(method_call, nullptr, nullptr); + } else { + fl_method_call_respond_not_implemented(method_call, nullptr); } - auto *js = - fl_value_get_string(fl_value_lookup_string(args, "javaScriptString")); - self->windows->at(window_id)->EvaluateJavaScript(js, method_call); - } else { - fl_method_call_respond_not_implemented(method_call, nullptr); - } } static void webview_window_plugin_dispose(GObject *object) { - delete WEBVIEW_WINDOW_PLUGIN(object)->windows; - g_object_unref(WEBVIEW_WINDOW_PLUGIN(object)->method_channel); - G_OBJECT_CLASS(webview_window_plugin_parent_class)->dispose(object); + delete WEBVIEW_WINDOW_PLUGIN(object)->windows; + g_object_unref(WEBVIEW_WINDOW_PLUGIN(object)->method_channel); + G_OBJECT_CLASS(webview_window_plugin_parent_class)->dispose(object); } static void webview_window_plugin_class_init(WebviewWindowPluginClass *klass) { - G_OBJECT_CLASS(klass)->dispose = webview_window_plugin_dispose; + G_OBJECT_CLASS(klass)->dispose = webview_window_plugin_dispose; } -static void webview_window_plugin_init(WebviewWindowPlugin *self) { - self->windows = new std::map>(); +static void webview_window_plugin_init(WebviewWindowPlugin * self) { + self->windows = new std::map >(); } static void method_call_cb(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data) { - WebviewWindowPlugin *plugin = WEBVIEW_WINDOW_PLUGIN(user_data); - webview_window_plugin_handle_method_call(plugin, method_call); + WebviewWindowPlugin * plugin = WEBVIEW_WINDOW_PLUGIN(user_data); + webview_window_plugin_handle_method_call(plugin, method_call); } void desktop_webview_window_plugin_register_with_registrar( - FlPluginRegistrar *registrar) { - client_message_channel_plugin_register_with_registrar(registrar); + FlPluginRegistrar *registrar) { + client_message_channel_plugin_register_with_registrar(registrar); - WebviewWindowPlugin *plugin = WEBVIEW_WINDOW_PLUGIN( - g_object_new(webview_window_plugin_get_type(), nullptr)); + WebviewWindowPlugin * plugin = WEBVIEW_WINDOW_PLUGIN( + g_object_new(webview_window_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), - "webview_window", FL_METHOD_CODEC(codec)); - g_object_ref(channel); - plugin->method_channel = channel; - fl_method_channel_set_method_call_handler( - channel, method_call_cb, g_object_ref(plugin), g_object_unref); + g_autoptr(FlStandardMethodCodec) + codec = fl_standard_method_codec_new(); + g_autoptr(FlMethodChannel) + channel = + fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), + "webview_window", FL_METHOD_CODEC(codec)); + g_object_ref(channel); + plugin->method_channel = channel; + fl_method_channel_set_method_call_handler( + channel, method_call_cb, g_object_ref(plugin), g_object_unref); - g_object_unref(plugin); + g_object_unref(plugin); } diff --git a/packages/desktop_webview_window/linux/webview_window.cc b/packages/desktop_webview_window/linux/webview_window.cc index d5a517f2..6b129392 100644 --- a/packages/desktop_webview_window/linux/webview_window.cc +++ b/packages/desktop_webview_window/linux/webview_window.cc @@ -15,83 +15,83 @@ void get_cookies_callback(WebKitCookieManager *manager, GAsyncResult *res, gpointer user_data) { - CookieData *data = (CookieData *)user_data; - GError *error = NULL; - - GList *cookies = - webkit_cookie_manager_get_cookies_finish(manager, res, &error); - if (error != NULL) { - g_print("Error getting cookies: %s\n", error->message); - g_error_free(error); - data->cookies = NULL; - } else { - data->cookies = cookies; - } - - g_main_loop_quit(data->loop); + CookieData *data = (CookieData *) user_data; + GError *error = NULL; + + GList *cookies = + webkit_cookie_manager_get_cookies_finish(manager, res, &error); + if (error != NULL) { + g_print("Error getting cookies: %s\n", error->message); + g_error_free(error); + data->cookies = NULL; + } else { + data->cookies = cookies; + } + + g_main_loop_quit(data->loop); } GList *get_cookies_sync(WebKitWebView *web_view) { - WebKitCookieManager *cookie_manager; - GMainLoop *loop; - CookieData data = {0}; + WebKitCookieManager *cookie_manager; + GMainLoop *loop; + CookieData data = {0}; - cookie_manager = webkit_web_context_get_cookie_manager( - webkit_web_view_get_context(web_view)); - loop = g_main_loop_new(NULL, FALSE); - data.loop = loop; + cookie_manager = webkit_web_context_get_cookie_manager( + webkit_web_view_get_context(web_view)); + loop = g_main_loop_new(NULL, FALSE); + data.loop = loop; - const gchar *uri = webkit_web_view_get_uri(web_view); + const gchar *uri = webkit_web_view_get_uri(web_view); - // Start the asynchronous operation - webkit_cookie_manager_get_cookies(cookie_manager, uri, NULL, - (GAsyncReadyCallback)get_cookies_callback, - &data); + // Start the asynchronous operation + webkit_cookie_manager_get_cookies(cookie_manager, uri, NULL, + (GAsyncReadyCallback) get_cookies_callback, + &data); - // Run the main loop until the callback is called - g_main_loop_run(loop); + // Run the main loop until the callback is called + g_main_loop_run(loop); - g_main_loop_unref(loop); + g_main_loop_unref(loop); - return data.cookies; + return data.cookies; } namespace { -gboolean on_load_failed_with_tls_errors(WebKitWebView *web_view, - char *failing_uri, - GTlsCertificate *certificate, - GTlsCertificateFlags errors, - gpointer user_data) { - auto *webview = static_cast(user_data); - g_critical("on_load_failed_with_tls_errors: %s %p error= %d", failing_uri, - webview, errors); - // TODO allow certificate for some certificate ? - // maybe we can use the pem from - // https://source.chromium.org/chromium/chromium/src/+/master:net/data/ssl/ev_roots/ - // webkit_web_context_allow_tls_certificate_for_host(webkit_web_view_get_context(web_view), - // certificate, uri->host); webkit_web_view_load_uri(web_view, failing_uri); - return false; -} + gboolean on_load_failed_with_tls_errors(WebKitWebView *web_view, + char *failing_uri, + GTlsCertificate *certificate, + GTlsCertificateFlags errors, + gpointer user_data) { + auto *webview = static_cast(user_data); + g_critical("on_load_failed_with_tls_errors: %s %p error= %d", failing_uri, + webview, errors); + // TODO allow certificate for some certificate ? + // maybe we can use the pem from + // https://source.chromium.org/chromium/chromium/src/+/master:net/data/ssl/ev_roots/ + // webkit_web_context_allow_tls_certificate_for_host(webkit_web_view_get_context(web_view), + // certificate, uri->host); webkit_web_view_load_uri(web_view, failing_uri); + return false; + } -GtkWidget *on_create(WebKitWebView *web_view, - WebKitNavigationAction *navigation_action, - gpointer user_data) { - return GTK_WIDGET(web_view); -} + GtkWidget *on_create(WebKitWebView *web_view, + WebKitNavigationAction *navigation_action, + gpointer user_data) { + return GTK_WIDGET(web_view); + } -void on_load_changed(WebKitWebView *web_view, WebKitLoadEvent load_event, - gpointer user_data) { - auto *window = static_cast(user_data); - window->OnLoadChanged(load_event); -} + void on_load_changed(WebKitWebView *web_view, WebKitLoadEvent load_event, + gpointer user_data) { + auto *window = static_cast(user_data); + window->OnLoadChanged(load_event); + } -gboolean decide_policy_cb(WebKitWebView *web_view, - WebKitPolicyDecision *decision, - WebKitPolicyDecisionType type, gpointer user_data) { - auto *window = static_cast(user_data); - return window->DecidePolicy(decision, type); -} + gboolean decide_policy_cb(WebKitWebView *web_view, + WebKitPolicyDecision *decision, + WebKitPolicyDecisionType type, gpointer user_data) { + auto *window = static_cast(user_data); + return window->DecidePolicy(decision, type); + } } // namespace @@ -99,272 +99,336 @@ WebviewWindow::WebviewWindow(FlMethodChannel *method_channel, int64_t window_id, std::function on_close_callback, const std::string &title, int width, int height, int title_bar_height) - : method_channel_(method_channel), - window_id_(window_id), - on_close_callback_(std::move(on_close_callback)), - default_user_agent_() { - g_object_ref(method_channel_); - - window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); - g_signal_connect(G_OBJECT(window_), "destroy", - G_CALLBACK(+[](GtkWidget *, gpointer arg) { - auto *window = static_cast(arg); - if (window->on_close_callback_) { - window->on_close_callback_(); - } - auto *args = fl_value_new_map(); - fl_value_set(args, fl_value_new_string("id"), - fl_value_new_int(window->window_id_)); - fl_method_channel_invoke_method( - FL_METHOD_CHANNEL(window->method_channel_), - "onWindowClose", args, nullptr, nullptr, nullptr); - }), - this); - gtk_window_set_title(GTK_WINDOW(window_), title.c_str()); - gtk_window_set_default_size(GTK_WINDOW(window_), width, height); - gtk_window_set_position(GTK_WINDOW(window_), GTK_WIN_POS_CENTER); - - box_ = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)); - gtk_container_add(GTK_CONTAINER(window_), GTK_WIDGET(box_)); - - // initial flutter_view - g_autoptr(FlDartProject) project = fl_dart_project_new(); - const char *args[] = {"web_view_title_bar", g_strdup_printf("%ld", window_id), - nullptr}; - fl_dart_project_set_dart_entrypoint_arguments(project, - const_cast(args)); - auto *title_bar = fl_view_new(project); - - g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar = - fl_plugin_registry_get_registrar_for_plugin(FL_PLUGIN_REGISTRY(title_bar), - "DesktopWebviewWindowPlugin"); - client_message_channel_plugin_register_with_registrar( - desktop_webview_window_registrar); - - gtk_widget_set_size_request(GTK_WIDGET(title_bar), -1, title_bar_height); - gtk_widget_set_vexpand(GTK_WIDGET(title_bar), FALSE); - gtk_box_pack_start(box_, GTK_WIDGET(title_bar), FALSE, FALSE, 0); - - // initial web_view - webview_ = webkit_web_view_new(); - g_signal_connect(G_OBJECT(webview_), "load-failed-with-tls-errors", - G_CALLBACK(on_load_failed_with_tls_errors), this); - g_signal_connect(G_OBJECT(webview_), "create", G_CALLBACK(on_create), this); - g_signal_connect(G_OBJECT(webview_), "load-changed", - G_CALLBACK(on_load_changed), this); - g_signal_connect(G_OBJECT(webview_), "decide-policy", - G_CALLBACK(decide_policy_cb), this); - - auto settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webview_)); - webkit_settings_set_javascript_can_open_windows_automatically(settings, true); - default_user_agent_ = webkit_settings_get_user_agent(settings); - gtk_box_pack_end(box_, webview_, true, true, 0); - - gtk_widget_show_all(GTK_WIDGET(window_)); - gtk_widget_grab_focus(GTK_WIDGET(webview_)); - - // FROM: https://github.com/leanflutter/window_manager/pull/343 - // Disconnect all delete-event handlers first in flutter 3.10.1, which causes - // delete_event not working. Issues from flutter/engine: - // https://github.com/flutter/engine/pull/40033 - guint handler_id = g_signal_handler_find(window_, G_SIGNAL_MATCH_DATA, 0, 0, - NULL, NULL, title_bar); - if (handler_id > 0) { - g_signal_handler_disconnect(window_, handler_id); - } + : method_channel_(method_channel), + window_id_(window_id), + on_close_callback_(std::move(on_close_callback)), + default_user_agent_() { + g_object_ref(method_channel_); + + window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); + g_signal_connect(G_OBJECT(window_), "destroy", + G_CALLBACK(+[](GtkWidget *, gpointer arg) { + auto *window = static_cast(arg); + if (window->on_close_callback_) { + window->on_close_callback_(); + } + auto *args = fl_value_new_map(); + fl_value_set(args, fl_value_new_string("id"), + fl_value_new_int(window->window_id_)); + fl_method_channel_invoke_method( + FL_METHOD_CHANNEL(window->method_channel_), + "onWindowClose", args, nullptr, nullptr, nullptr); + }), + this); + gtk_window_set_title(GTK_WINDOW(window_), title.c_str()); + gtk_window_set_default_size(GTK_WINDOW(window_), width, height); + gtk_window_set_position(GTK_WINDOW(window_), GTK_WIN_POS_CENTER); + + box_ = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)); + gtk_container_add(GTK_CONTAINER(window_), GTK_WIDGET(box_)); + + // initial flutter_view + g_autoptr(FlDartProject) + project = fl_dart_project_new(); + const char *args[] = {"web_view_title_bar", g_strdup_printf("%ld", window_id), + nullptr}; + fl_dart_project_set_dart_entrypoint_arguments(project, + const_cast(args)); + auto *title_bar = fl_view_new(project); + + g_autoptr(FlPluginRegistrar) + desktop_webview_window_registrar = + fl_plugin_registry_get_registrar_for_plugin(FL_PLUGIN_REGISTRY(title_bar), + "DesktopWebviewWindowPlugin"); + client_message_channel_plugin_register_with_registrar( + desktop_webview_window_registrar); + + gtk_widget_set_size_request(GTK_WIDGET(title_bar), -1, title_bar_height); + gtk_widget_set_vexpand(GTK_WIDGET(title_bar), FALSE); + gtk_box_pack_start(box_, GTK_WIDGET(title_bar), FALSE, FALSE, 0); + + // initial web_view + webview_ = webkit_web_view_new(); + g_signal_connect(G_OBJECT(webview_), "load-failed-with-tls-errors", + G_CALLBACK(on_load_failed_with_tls_errors), this); + g_signal_connect(G_OBJECT(webview_), "create", G_CALLBACK(on_create), this); + g_signal_connect(G_OBJECT(webview_), "load-changed", + G_CALLBACK(on_load_changed), this); + g_signal_connect(G_OBJECT(webview_), "decide-policy", + G_CALLBACK(decide_policy_cb), this); + + auto settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webview_)); + webkit_settings_set_javascript_can_open_windows_automatically(settings, true); + default_user_agent_ = webkit_settings_get_user_agent(settings); + gtk_box_pack_end(box_, webview_, true, true, 0); + + gtk_widget_show_all(GTK_WIDGET(window_)); + gtk_widget_grab_focus(GTK_WIDGET(webview_)); + + // FROM: https://github.com/leanflutter/window_manager/pull/343 + // Disconnect all delete-event handlers first in flutter 3.10.1, which causes + // delete_event not working. Issues from flutter/engine: + // https://github.com/flutter/engine/pull/40033 + guint handler_id = g_signal_handler_find(window_, G_SIGNAL_MATCH_DATA, 0, 0, + NULL, NULL, title_bar); + if (handler_id > 0) { + g_signal_handler_disconnect(window_, handler_id); + } } WebviewWindow::~WebviewWindow() { - g_object_unref(method_channel_); - printf("~WebviewWindow\n"); + g_object_unref(method_channel_); + printf("~WebviewWindow\n"); } void WebviewWindow::Navigate(const char *url) { - webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview_), url); + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview_), url); } void WebviewWindow::RunJavaScriptWhenContentReady(const char *java_script) { - auto *manager = - webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(webview_)); - webkit_user_content_manager_add_script( - manager, - webkit_user_script_new(java_script, WEBKIT_USER_CONTENT_INJECT_TOP_FRAME, - WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, - nullptr, nullptr)); + auto *manager = + webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(webview_)); + webkit_user_content_manager_add_script( + manager, + webkit_user_script_new(java_script, WEBKIT_USER_CONTENT_INJECT_TOP_FRAME, + WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, + nullptr, nullptr)); } void WebviewWindow::SetApplicationNameForUserAgent( - const std::string &app_name) { - auto *setting = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webview_)); - webkit_settings_set_user_agent(setting, - (default_user_agent_ + app_name).c_str()); + const std::string &app_name) { + auto *setting = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webview_)); + webkit_settings_set_user_agent(setting, + (default_user_agent_ + app_name).c_str()); } void WebviewWindow::Close() { gtk_window_close(GTK_WINDOW(window_)); } void WebviewWindow::OnLoadChanged(WebKitLoadEvent load_event) { - // notify history changed event. - { - auto can_go_back = webkit_web_view_can_go_back(WEBKIT_WEB_VIEW(webview_)); - auto can_go_forward = - webkit_web_view_can_go_forward(WEBKIT_WEB_VIEW(webview_)); - auto *args = fl_value_new_map(); - fl_value_set(args, fl_value_new_string("id"), fl_value_new_int(window_id_)); - fl_value_set(args, fl_value_new_string("canGoBack"), - fl_value_new_bool(can_go_back)); - fl_value_set(args, fl_value_new_string("canGoForward"), - fl_value_new_bool(can_go_forward)); - fl_method_channel_invoke_method(FL_METHOD_CHANNEL(method_channel_), - "onHistoryChanged", args, nullptr, nullptr, - nullptr); - } - - // notify load start/finished event. - switch (load_event) { - case WEBKIT_LOAD_STARTED: { - auto *args = fl_value_new_map(); - fl_value_set(args, fl_value_new_string("id"), - fl_value_new_int(window_id_)); - fl_method_channel_invoke_method(FL_METHOD_CHANNEL(method_channel_), - "onNavigationStarted", args, nullptr, - nullptr, nullptr); - break; + // notify history changed event. + { + auto can_go_back = webkit_web_view_can_go_back(WEBKIT_WEB_VIEW(webview_)); + auto can_go_forward = + webkit_web_view_can_go_forward(WEBKIT_WEB_VIEW(webview_)); + auto *args = fl_value_new_map(); + fl_value_set(args, fl_value_new_string("id"), fl_value_new_int(window_id_)); + fl_value_set(args, fl_value_new_string("canGoBack"), + fl_value_new_bool(can_go_back)); + fl_value_set(args, fl_value_new_string("canGoForward"), + fl_value_new_bool(can_go_forward)); + fl_method_channel_invoke_method(FL_METHOD_CHANNEL(method_channel_), + "onHistoryChanged", args, nullptr, nullptr, + nullptr); } - case WEBKIT_LOAD_FINISHED: { - auto *args = fl_value_new_map(); - fl_value_set(args, fl_value_new_string("id"), - fl_value_new_int(window_id_)); - fl_method_channel_invoke_method(FL_METHOD_CHANNEL(method_channel_), - "onNavigationCompleted", args, nullptr, - nullptr, nullptr); - break; + + // notify load start/finished event. + switch (load_event) { + case WEBKIT_LOAD_STARTED: { + auto *args = fl_value_new_map(); + fl_value_set(args, fl_value_new_string("id"), + fl_value_new_int(window_id_)); + fl_method_channel_invoke_method(FL_METHOD_CHANNEL(method_channel_), + "onNavigationStarted", args, nullptr, + nullptr, nullptr); + break; + } + case WEBKIT_LOAD_FINISHED: { + auto *args = fl_value_new_map(); + fl_value_set(args, fl_value_new_string("id"), + fl_value_new_int(window_id_)); + fl_method_channel_invoke_method(FL_METHOD_CHANNEL(method_channel_), + "onNavigationCompleted", args, nullptr, + nullptr, nullptr); + break; + } + default: + break; } - default: - break; - } } void WebviewWindow::GoForward() { - webkit_web_view_go_forward(WEBKIT_WEB_VIEW(webview_)); + webkit_web_view_go_forward(WEBKIT_WEB_VIEW(webview_)); } void WebviewWindow::GoBack() { - webkit_web_view_go_back(WEBKIT_WEB_VIEW(webview_)); + webkit_web_view_go_back(WEBKIT_WEB_VIEW(webview_)); } void WebviewWindow::Reload() { - webkit_web_view_reload(WEBKIT_WEB_VIEW(webview_)); + webkit_web_view_reload(WEBKIT_WEB_VIEW(webview_)); } void WebviewWindow::StopLoading() { - webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(webview_)); + webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(webview_)); } FlValue *WebviewWindow::GetAllCookies() { - GList *cookies = get_cookies_sync(WEBKIT_WEB_VIEW(webview_)); - - g_autoptr(FlValue) fl_cookie_list = fl_value_new_list(); - - FlValue* cookie_list = fl_value_ref(fl_cookie_list); - - for (GList *l = cookies; l; l = l->next) { - SoupCookie *cookie = (SoupCookie *)l->data; - g_autoptr(FlValue) cookie_map = fl_value_new_map(); - - fl_value_set_string_take(cookie_map, "name", - fl_value_new_string(soup_cookie_get_name(cookie))); - fl_value_set_string_take( - cookie_map, "value", - fl_value_new_string(soup_cookie_get_value(cookie))); - fl_value_set_string_take( - cookie_map, "domain", - fl_value_new_string(soup_cookie_get_domain(cookie))); - fl_value_set_string_take(cookie_map, "path", - fl_value_new_string(soup_cookie_get_path(cookie))); + GList *cookies = get_cookies_sync(WEBKIT_WEB_VIEW(webview_)); + + g_autoptr(FlValue) + fl_cookie_list = fl_value_new_list(); + + FlValue *cookie_list = fl_value_ref(fl_cookie_list); + + for (GList *l = cookies; l; l = l->next) { + SoupCookie *cookie = (SoupCookie *) l->data; + g_autoptr(FlValue) + cookie_map = fl_value_new_map(); + + fl_value_set_string_take(cookie_map, "name", + fl_value_new_string(soup_cookie_get_name(cookie))); + fl_value_set_string_take( + cookie_map, "value", + fl_value_new_string(soup_cookie_get_value(cookie))); + fl_value_set_string_take( + cookie_map, "domain", + fl_value_new_string(soup_cookie_get_domain(cookie))); + fl_value_set_string_take(cookie_map, "path", + fl_value_new_string(soup_cookie_get_path(cookie))); + + gdouble expires = g_date_time_get_seconds(soup_cookie_get_expires(cookie)); + + if (expires >= 0) { + fl_value_set_string_take(cookie_map, "expires", + fl_value_new_float(expires)); + } else { + fl_value_set_string_take(cookie_map, "expires", fl_value_new_null()); + } - gdouble expires = g_date_time_get_seconds(soup_cookie_get_expires(cookie)); + fl_value_set_string_take( + cookie_map, "httpOnly", + fl_value_new_bool(soup_cookie_get_http_only(cookie))); + fl_value_set_string_take(cookie_map, "secure", + fl_value_new_bool(soup_cookie_get_secure(cookie))); + fl_value_set_string_take(cookie_map, "sessionOnly", + fl_value_new_bool(false)); - if (expires >= 0) { - fl_value_set_string_take(cookie_map, "expires", - fl_value_new_float(expires)); - } else { - fl_value_set_string_take(cookie_map, "expires", fl_value_new_null()); + fl_value_append(cookie_list, cookie_map); + soup_cookie_free(cookie); } - fl_value_set_string_take( - cookie_map, "httpOnly", - fl_value_new_bool(soup_cookie_get_http_only(cookie))); - fl_value_set_string_take(cookie_map, "secure", - fl_value_new_bool(soup_cookie_get_secure(cookie))); - fl_value_set_string_take(cookie_map, "sessionOnly", - fl_value_new_bool(false)); - - fl_value_append(cookie_list, cookie_map); - soup_cookie_free(cookie); - } + g_free(cookies); - g_free(cookies); - - return cookie_list; + return cookie_list; } gboolean WebviewWindow::DecidePolicy(WebKitPolicyDecision *decision, WebKitPolicyDecisionType type) { - if (type == WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION) { - auto *navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION(decision); - auto *navigation_action = - webkit_navigation_policy_decision_get_navigation_action( - navigation_decision); - auto *request = webkit_navigation_action_get_request(navigation_action); - auto *uri = webkit_uri_request_get_uri(request); - auto *args = fl_value_new_map(); - fl_value_set(args, fl_value_new_string("id"), fl_value_new_int(window_id_)); - fl_value_set(args, fl_value_new_string("url"), fl_value_new_string(uri)); - fl_method_channel_invoke_method(FL_METHOD_CHANNEL(method_channel_), - "onUrlRequested", args, nullptr, nullptr, - nullptr); - } - return false; + if (type == WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION) { + auto *navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION(decision); + auto *navigation_action = + webkit_navigation_policy_decision_get_navigation_action( + navigation_decision); + auto *request = webkit_navigation_action_get_request(navigation_action); + auto *uri = webkit_uri_request_get_uri(request); + auto *args = fl_value_new_map(); + fl_value_set(args, fl_value_new_string("id"), fl_value_new_int(window_id_)); + fl_value_set(args, fl_value_new_string("url"), fl_value_new_string(uri)); + fl_method_channel_invoke_method(FL_METHOD_CHANNEL(method_channel_), + "onUrlRequested", args, nullptr, nullptr, + nullptr); + } + return false; } void WebviewWindow::EvaluateJavaScript(const char *java_script, FlMethodCall *call) { #ifdef WEBKIT_OLD_USED - webkit_web_view_run_javascript( + webkit_web_view_run_javascript( #else - webkit_web_view_evaluate_javascript( + webkit_web_view_evaluate_javascript( #endif - WEBKIT_WEB_VIEW(webview_), java_script, + WEBKIT_WEB_VIEW(webview_), java_script, #ifndef WEBKIT_OLD_USED - -1, nullptr, nullptr, + -1, nullptr, nullptr, #endif - nullptr, - [](GObject *object, GAsyncResult *result, gpointer user_data) { - auto *call = static_cast(user_data); - GError *error = nullptr; - auto *js_result = + nullptr, + [](GObject *object, GAsyncResult *result, gpointer user_data) { + auto *call = static_cast(user_data); + GError *error = nullptr; + auto *js_result = #ifdef WEBKIT_OLD_USED - webkit_web_view_run_javascript_finish( + webkit_web_view_run_javascript_finish( #else - webkit_web_view_evaluate_javascript_finish( + webkit_web_view_evaluate_javascript_finish( #endif - WEBKIT_WEB_VIEW(object), result, &error); - if (!js_result) { - fl_method_call_respond_error(call, "failed to evaluate javascript.", - error->message, nullptr, nullptr); - g_error_free(error); - } else { - auto *js_value = jsc_value_to_json( + WEBKIT_WEB_VIEW(object), result, &error); + if (!js_result) { + fl_method_call_respond_error(call, "failed to evaluate javascript.", + error->message, nullptr, nullptr); + g_error_free(error); + } else { + auto *js_value = jsc_value_to_json( #ifdef WEBKIT_OLD_USED - webkit_javascript_result_get_js_value + webkit_javascript_result_get_js_value #endif - (js_result), - 0); - fl_method_call_respond_success( - call, js_value ? fl_value_new_string(js_value) : nullptr, - nullptr); - } - g_object_unref(call); - }, - g_object_ref(call)); -} \ No newline at end of file + (js_result), + 0); + fl_method_call_respond_success( + call, js_value ? fl_value_new_string(js_value) : nullptr, + nullptr); + } + g_object_unref(call); + }, + g_object_ref(call)); +} + +void WebviewWindow::RegisterJavaScriptChannel(const std::string &name) { + WebKitUserContentManager *manager = + webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(webview_)); + + webkit_user_content_manager_register_script_message_handler(manager, name.c_str()); + + struct HandlerData { + WebviewWindow *self; + std::string name; + }; + + HandlerData *data = new HandlerData{this, name}; + + g_signal_connect_data( + manager, + ("script-message-received::" + name).c_str(), + G_CALLBACK(+[](WebKitUserContentManager *manager, + WebKitJavascriptResult *result, + gpointer user_data) { + HandlerData *data = static_cast(user_data); + WebviewWindow *self = data->self; + const std::string &handler_name = data->name; + + JSCValue *value = webkit_javascript_result_get_js_value(result); + + if (jsc_value_is_string(value)) { + gchar *str_value = jsc_value_to_string(value); + if (str_value != nullptr) { + FlValue *args = fl_value_new_map(); + fl_value_set_string(args, "name", + fl_value_new_string(handler_name.c_str())); + fl_value_set_string(args, "body", fl_value_new_string(str_value)); + fl_value_set_string(args, "id", fl_value_new_int(self->window_id_)); + + fl_method_channel_invoke_method( + self->method_channel_, + "onJavaScriptMessage", + args, + nullptr, // cancellable + nullptr, // callback + nullptr); // user_data + + g_free(str_value); + } + } + }), + data, + +[](gpointer user_data, GClosure *) { + delete static_cast(user_data); + }, + static_cast(0)); +} + +void WebviewWindow::UnregisterJavaScriptChannel(const std::string &name) { + WebKitUserContentManager *manager = + webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(webview_)); + + webkit_user_content_manager_unregister_script_message_handler(manager, name.c_str()); +} diff --git a/packages/desktop_webview_window/linux/webview_window.h b/packages/desktop_webview_window/linux/webview_window.h index 6b413bbd..8ff8becf 100644 --- a/packages/desktop_webview_window/linux/webview_window.h +++ b/packages/desktop_webview_window/linux/webview_window.h @@ -24,49 +24,54 @@ void get_cookies_callback(WebKitCookieManager *manager, GAsyncResult *res, GList *get_cookies_sync(WebKitWebView *web_view); class WebviewWindow { - public: - WebviewWindow(FlMethodChannel *method_channel, int64_t window_id, - std::function on_close_callback, - const std::string &title, int width, int height, - int title_bar_height); +public: + WebviewWindow(FlMethodChannel *method_channel, int64_t window_id, + std::function on_close_callback, + const std::string &title, int width, int height, + int title_bar_height); - virtual ~WebviewWindow(); + virtual ~WebviewWindow(); - void Navigate(const char *url); + void Navigate(const char *url); - void RunJavaScriptWhenContentReady(const char *java_script); + void RunJavaScriptWhenContentReady(const char *java_script); - void Close(); + void Close(); - void SetApplicationNameForUserAgent(const std::string &app_name); + void SetApplicationNameForUserAgent(const std::string &app_name); - void OnLoadChanged(WebKitLoadEvent load_event); + void OnLoadChanged(WebKitLoadEvent load_event); - void GoBack(); + void GoBack(); - void GoForward(); + void GoForward(); - void Reload(); + void Reload(); - void StopLoading(); + void StopLoading(); - FlValue* GetAllCookies(); + FlValue *GetAllCookies(); - gboolean DecidePolicy(WebKitPolicyDecision *decision, - WebKitPolicyDecisionType type); + gboolean DecidePolicy(WebKitPolicyDecision *decision, + WebKitPolicyDecisionType type); - void EvaluateJavaScript(const char *java_script, FlMethodCall *call); + void EvaluateJavaScript(const char *java_script, FlMethodCall *call); - private: - FlMethodChannel *method_channel_; - int64_t window_id_; - std::function on_close_callback_; + void RegisterJavaScriptChannel(const std::string &name); - std::string default_user_agent_; + void UnregisterJavaScriptChannel(const std::string &name); - GtkWidget *window_ = nullptr; - GtkWidget *webview_ = nullptr; - GtkBox *box_ = nullptr; + +private: + FlMethodChannel *method_channel_; + int64_t window_id_; + std::function on_close_callback_; + + std::string default_user_agent_; + + GtkWidget *window_ = nullptr; + GtkWidget *webview_ = nullptr; + GtkBox *box_ = nullptr; }; #endif // WEBVIEW_WINDOW_LINUX_WEBVIEW_WINDOW_H_ diff --git a/packages/desktop_webview_window/pubspec.yaml b/packages/desktop_webview_window/pubspec.yaml index f066bb2f..1c785351 100644 --- a/packages/desktop_webview_window/pubspec.yaml +++ b/packages/desktop_webview_window/pubspec.yaml @@ -1,6 +1,6 @@ name: desktop_webview_window description: Show a webview window on your flutter desktop application. -version: 0.2.4 +version: 0.2.5 homepage: https://github.com/MixinNetwork/flutter-plugins/tree/main/packages/desktop_webview_window environment: @@ -15,12 +15,8 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^1.0.0 + flutter_lints: ">=1.0.0" -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. flutter: plugin: platforms: