From 6927ef8f318d6ee372d703d41ff2e061c91e0f58 Mon Sep 17 00:00:00 2001 From: Lukas Heinze <116069779+Iri-Hor@users.noreply.github.com> Date: Wed, 8 Nov 2023 04:50:40 +0100 Subject: [PATCH] [desktop-webview-window] Control URL requests made by the webview (Breaking!) (#296) * commit * commit * commit2 * revert main * cleanup * rename * changes * changes * changes * change how to set callback * extend launch by a switch allowing to decide whether the OnUrlRequestEvent is to be triggered or not --- .../example/lib/main.dart | 4 +- .../lib/desktop_webview_window.dart | 4 +- .../lib/src/webview.dart | 8 ++-- .../lib/src/webview_impl.dart | 30 +++++++------ .../windows/web_view.cc | 42 +++++++++++++++---- .../desktop_webview_window/windows/web_view.h | 4 ++ .../windows/web_view_window_plugin.cc | 2 + 7 files changed, 62 insertions(+), 32 deletions(-) diff --git a/packages/desktop_webview_window/example/lib/main.dart b/packages/desktop_webview_window/example/lib/main.dart index 5541796b..6304a18a 100644 --- a/packages/desktop_webview_window/example/lib/main.dart +++ b/packages/desktop_webview_window/example/lib/main.dart @@ -138,13 +138,15 @@ class _MyAppState extends State { ..setBrightness(Brightness.dark) ..setApplicationNameForUserAgent(" WebviewExample/1.0.0") ..launch(_controller.text) - ..addOnUrlRequestCallback((url) { + ..setOnUrlRequestCallback((url) { debugPrint('url: $url'); final uri = Uri.parse(url); if (uri.path == '/login_success') { debugPrint('login success. token: ${uri.queryParameters['token']}'); webview.close(); } + // grant navigation request + return true; }) ..onClose.whenComplete(() { debugPrint("on close"); diff --git a/packages/desktop_webview_window/lib/desktop_webview_window.dart b/packages/desktop_webview_window/lib/desktop_webview_window.dart index b2aae0ab..bc1cddea 100644 --- a/packages/desktop_webview_window/lib/desktop_webview_window.dart +++ b/packages/desktop_webview_window/lib/desktop_webview_window.dart @@ -139,12 +139,12 @@ class WebviewWindow { break; case "onUrlRequested": final url = args['url'] as String; - webview.notifyUrlChanged(url); + final ret = webview.notifyUrlChanged(url); await _otherIsolateMessageHandler.invokeMethod('onUrlRequested', { 'webViewId': viewId, 'url': url, }); - break; + return ret; case "onWebMessageReceived": final message = args['message'] as String; webview.notifyWebMessageReceived(message); diff --git a/packages/desktop_webview_window/lib/src/webview.dart b/packages/desktop_webview_window/lib/src/webview.dart index 544c497f..9a95f1c3 100644 --- a/packages/desktop_webview_window/lib/src/webview.dart +++ b/packages/desktop_webview_window/lib/src/webview.dart @@ -10,7 +10,7 @@ typedef OnHistoryChangedCallback = void Function( /// Callback when WebView start to load a URL. /// [url] is the URL string. -typedef OnUrlRequestCallback = void Function(String url); +typedef OnUrlRequestCallback = bool Function(String url); /// Callback when WebView receives a web message /// [message] constains the webmessage @@ -35,7 +35,7 @@ abstract class Webview { void setPromptHandler(PromptHandler? handler); /// Navigates to the given URL. - void launch(String url); + void launch(String url, {bool triggerOnUrlRequestEvent=true}); /// change webview theme. /// @@ -74,9 +74,7 @@ abstract class Webview { /// Register a callback that will be invoked when the webview history changes. void setOnHistoryChangedCallback(OnHistoryChangedCallback? callback); - void addOnUrlRequestCallback(OnUrlRequestCallback callback); - - void removeOnUrlRequestCallback(OnUrlRequestCallback callback); + void setOnUrlRequestCallback(OnUrlRequestCallback? callback); void addOnWebMessageReceivedCallback(OnWebMessageReceivedCallback callback); diff --git a/packages/desktop_webview_window/lib/src/webview_impl.dart b/packages/desktop_webview_window/lib/src/webview_impl.dart index d207ecdc..7d372c2e 100644 --- a/packages/desktop_webview_window/lib/src/webview_impl.dart +++ b/packages/desktop_webview_window/lib/src/webview_impl.dart @@ -22,9 +22,9 @@ class WebviewImpl extends Webview { OnHistoryChangedCallback? _onHistoryChanged; - final ValueNotifier _isNaivgating = ValueNotifier(false); + final ValueNotifier _isNavigating = ValueNotifier(false); - final Set _onUrlRequestCallbacks = {}; + OnUrlRequestCallback? _onUrlRequestCallback = null; final Set _onWebMessageReceivedCallbacks = {}; @@ -57,12 +57,14 @@ class WebviewImpl extends Webview { } void onNavigationStarted() { - _isNaivgating.value = true; + _isNavigating.value = true; } - void notifyUrlChanged(String url) { - for (final callback in _onUrlRequestCallbacks) { - callback(url); + bool notifyUrlChanged(String url) { + if(_onUrlRequestCallback != null) { + return _onUrlRequestCallback!(url); + } else { + return true; } } @@ -73,11 +75,11 @@ class WebviewImpl extends Webview { } void onNavigationCompleted() { - _isNaivgating.value = false; + _isNavigating.value = false; } @override - ValueListenable get isNavigating => _isNaivgating; + ValueListenable get isNavigating => _isNavigating; @override void registerJavaScriptMessageHandler( @@ -121,10 +123,11 @@ class WebviewImpl extends Webview { } @override - void launch(String url) async { + void launch(String url, {bool triggerOnUrlRequestEvent=true}) async { await channel.invokeMethod("launch", { "url": url, "viewId": viewId, + "triggerOnUrlRequestEvent": triggerOnUrlRequestEvent, }); } @@ -223,13 +226,8 @@ class WebviewImpl extends Webview { } @override - void addOnUrlRequestCallback(OnUrlRequestCallback callback) { - _onUrlRequestCallbacks.add(callback); - } - - @override - void removeOnUrlRequestCallback(OnUrlRequestCallback callback) { - _onUrlRequestCallbacks.remove(callback); + void setOnUrlRequestCallback(OnUrlRequestCallback? callback) { + _onUrlRequestCallback = callback; } @override diff --git a/packages/desktop_webview_window/windows/web_view.cc b/packages/desktop_webview_window/windows/web_view.cc index 09254eb4..394adad1 100644 --- a/packages/desktop_webview_window/windows/web_view.cc +++ b/packages/desktop_webview_window/windows/web_view.cc @@ -8,6 +8,8 @@ #include #include +#include "flutter/method_result_functions.h" + #include "web_view.h" #include "utils.h" #include "strconv.h" @@ -144,14 +146,34 @@ void WebView::OnWebviewControllerCreated() { std::make_unique(flutter::EncodableMap{ {flutter::EncodableValue("id"), flutter::EncodableValue(web_view_id_)}, })); - LPWSTR uri; - args->get_Uri(&uri); - method_channel_->InvokeMethod( - "onUrlRequested", - std::make_unique(flutter::EncodableMap{ - {flutter::EncodableValue("id"), flutter::EncodableValue(web_view_id_)}, - {flutter::EncodableValue("url"), flutter::EncodableValue(wide_to_utf8(std::wstring(uri)))}, - })); + + if (triggerOnUrlRequestedEvent) { + LPWSTR uri; + args->get_Uri(&uri); + + auto result_handler = std::make_unique>( + [uri, sender, this](const flutter::EncodableValue* success_value) { + const bool letPass = std::get(*success_value); + if (letPass) { + this->setTriggerOnUrlRequestedEvent(false); + sender->Navigate(uri); + } + }, + nullptr, nullptr); + + method_channel_->InvokeMethod( + "onUrlRequested", + std::make_unique(flutter::EncodableMap{ + {flutter::EncodableValue("id"), flutter::EncodableValue(web_view_id_)}, + {flutter::EncodableValue("url"), flutter::EncodableValue(wide_to_utf8(std::wstring(uri)))}, + }), std::move(result_handler)); + + // navigation is canceled here and retriggered later from the callback passed to the method channel + args->put_Cancel(true); + } else { + args->put_Cancel(false); + triggerOnUrlRequestedEvent = true; + } return S_OK; } ).Get(), nullptr); @@ -323,6 +345,10 @@ void WebView::PostWebMessageAsJson(const std::wstring& webmessage, } } +void WebView::setTriggerOnUrlRequestedEvent(const bool value) { + this->triggerOnUrlRequestedEvent = value; +} + WebView::~WebView() { if (webview_) { webview_->Stop(); diff --git a/packages/desktop_webview_window/windows/web_view.h b/packages/desktop_webview_window/windows/web_view.h index 8ab81437..6cc94380 100644 --- a/packages/desktop_webview_window/windows/web_view.h +++ b/packages/desktop_webview_window/windows/web_view.h @@ -60,6 +60,8 @@ class WebView { void PostWebMessageAsJson(const std::wstring &webmessage, std::unique_ptr> completer); + void setTriggerOnUrlRequestedEvent(const bool value); + private: wil::unique_hwnd view_window_; @@ -79,6 +81,8 @@ class WebView { std::wstring user_data_folder_; + bool triggerOnUrlRequestedEvent{true}; + void OnWebviewControllerCreated(); [[nodiscard]] bool CanGoBack() const; diff --git a/packages/desktop_webview_window/windows/web_view_window_plugin.cc b/packages/desktop_webview_window/windows/web_view_window_plugin.cc index e8caa9db..8607666b 100644 --- a/packages/desktop_webview_window/windows/web_view_window_plugin.cc +++ b/packages/desktop_webview_window/windows/web_view_window_plugin.cc @@ -86,6 +86,7 @@ void WebviewWindowPlugin::HandleMethodCall( auto window_id = arguments->at(flutter::EncodableValue("viewId")).LongValue(); auto url = std::get(arguments->at(flutter::EncodableValue("url"))); + auto triggerOnUrlRequestEvent = std::get(arguments->at(flutter::EncodableValue("triggerOnUrlRequestEvent"))); if (!windows_.count(window_id)) { result->Error("0", "can not find webview window for id"); @@ -95,6 +96,7 @@ void WebviewWindowPlugin::HandleMethodCall( result->Error("0", "webview window not ready"); return; } + windows_[window_id]->GetWebView()->setTriggerOnUrlRequestedEvent(triggerOnUrlRequestEvent); windows_[window_id]->GetWebView()->Navigate(utf8_to_wide(url)); result->Success(); } else if (method_call.method_name() == "addScriptToExecuteOnDocumentCreated") {