diff --git a/packages/webview_flutter/tizen/src/webview.cc b/packages/webview_flutter/tizen/src/webview.cc index 8f7f50564..38553e142 100644 --- a/packages/webview_flutter/tizen/src/webview.cc +++ b/packages/webview_flutter/tizen/src/webview.cc @@ -26,6 +26,99 @@ extern "C" size_t LWE_EXPORT createWebViewInstance( const std::function& renderedCb); +template +class NavigationRequestResult : public flutter::MethodResult { + public: + NavigationRequestResult(std::string url, WebView* webView) + : url_(url), webView_(webView) {} + + void SuccessInternal(const T* shouldLoad) override { + if (std::holds_alternative(*shouldLoad)) { + if (std::get(*shouldLoad)) { + LoadUrl(); + } + } + } + + void ErrorInternal(const std::string& error_code, + const std::string& error_message, + const T* error_details) override { + throw std::invalid_argument("navigationRequest calls must succeed [code:" + + error_code + "][msg:" + error_message + "]"); + } + + void NotImplementedInternal() override { + throw std::invalid_argument( + "navigationRequest must be implemented by the webview method channel"); + } + + private: + void LoadUrl() { + if (webView_ && webView_->GetWebViewInstance()) { + webView_->GetWebViewInstance()->LoadURL(url_); + } + } + + std::string url_; + WebView* webView_; +}; + +enum RequestErrorType { + NoError, + UnknownError, + HostLookupError, + UnsupportedAuthSchemeError, + AuthenticationError, + ProxyAuthenticationError, + ConnectError, + IOError, + TimeoutError, + RedirectLoopError, + UnsupportedSchemeError, + FailedSSLHandshakeError, + BadURLError, + FileError, + FileNotFoundError, + TooManyRequestError, +}; + +static std::string ErrorCodeToString(int errorCode) { + switch (errorCode) { + case RequestErrorType::AuthenticationError: + return "authentication"; + case RequestErrorType::BadURLError: + return "badUrl"; + case RequestErrorType::ConnectError: + return "connect"; + case RequestErrorType::FailedSSLHandshakeError: + return "failedSslHandshake"; + case RequestErrorType::FileError: + return "file"; + case RequestErrorType::FileNotFoundError: + return "fileNotFound"; + case RequestErrorType::HostLookupError: + return "hostLookup"; + case RequestErrorType::IOError: + return "io"; + case RequestErrorType::ProxyAuthenticationError: + return "proxyAuthentication"; + case RequestErrorType::RedirectLoopError: + return "redirectLoop"; + case RequestErrorType::TimeoutError: + return "timeout"; + case RequestErrorType::TooManyRequestError: + return "tooManyRequests"; + case RequestErrorType::UnknownError: + return "unknown"; + case RequestErrorType::UnsupportedAuthSchemeError: + return "unsupportedAuthScheme"; + case RequestErrorType::UnsupportedSchemeError: + return "unsupportedScheme"; + } + std::string message = "Could not find a string for errorCode: " + errorCode; + throw std::invalid_argument(message); +} + std::string ExtractStringFromMap(const flutter::EncodableValue& arguments, const char* key) { if (std::holds_alternative(arguments)) { @@ -63,7 +156,9 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int viewId, webViewInstance_(nullptr), width_(width), height_(height), - tbmSurface_(nullptr) { + tbmSurface_(nullptr), + isMouseLButtonDown_(false), + hasNavigationDelegate_(false) { SetTextureId(FlutterRegisterExternalTexture(textureRegistrar_)); InitWebView(); @@ -82,6 +177,14 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int viewId, currentUrl_ = "about:blank"; } + auto settings = params[flutter::EncodableValue("settings")]; + if (std::holds_alternative(settings)) { + auto settingList = std::get(settings); + if (settingList.size() > 0) { + ApplySettings(settingList); + } + } + auto names = params[flutter::EncodableValue("javascriptChannelNames")]; if (std::holds_alternative(names)) { auto nameList = std::get(names); @@ -99,8 +202,7 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int viewId, map.insert( std::make_pair( flutter::EncodableValue("url"), flutter::EncodableValue(url))); - std::unique_ptr args = - std::make_unique(map); + auto args = std::make_unique(map); channel_->InvokeMethod("onPageStarted", std::move(args)); }); webViewInstance_->RegisterOnPageLoadedHandler( @@ -110,14 +212,81 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int viewId, map.insert( std::make_pair( flutter::EncodableValue("url"), flutter::EncodableValue(url))); - std::unique_ptr args = - std::make_unique(map); + auto args = std::make_unique(map); + channel_->InvokeMethod("onPageFinished", std::move(args)); + }); + webViewInstance_->RegisterOnReceivedErrorHandler( + [this](LWE::WebContainer* container, LWE::ResourceError e) { + flutter::EncodableMap map; + map.insert( + std::make_pair( + flutter::EncodableValue("errorCode"), + flutter::EncodableValue(e.GetErrorCode()))); + map.insert( + std::make_pair( + flutter::EncodableValue("description"), + flutter::EncodableValue(e.GetDescription()))); + map.insert( + std::make_pair( + flutter::EncodableValue("errorType"), + flutter::EncodableValue(ErrorCodeToString(e.GetErrorCode())))); + map.insert( + std::make_pair( + flutter::EncodableValue("failingUrl"), + flutter::EncodableValue(e.GetUrl()))); + auto args = std::make_unique(map); channel_->InvokeMethod("onPageFinished", std::move(args)); }); + webViewInstance_->RegisterShouldOverrideUrlLoadingHandler( + [this](LWE::WebContainer* view, const std::string& url) -> bool { + if (!hasNavigationDelegate_) { + return false; + } + flutter::EncodableMap map; + map.insert( + std::make_pair( + flutter::EncodableValue("url"), flutter::EncodableValue(url))); + map.insert( + std::make_pair( + flutter::EncodableValue("isForMainFrame"), + flutter::EncodableValue(true))); + auto args = std::make_unique(map); + auto onResult = + std::make_unique>( + url, this); + channel_->InvokeMethod("navigationRequest", std::move(args), + std::move(onResult)); + + return true; + }); + webViewInstance_->LoadURL(currentUrl_); } +void WebView::ApplySettings(flutter::EncodableMap settings) { + for (auto const& [key, val] : settings) { + if (std::holds_alternative(key)) { + std::string k = std::get(key); + if ("jsMode" == k) { + // TODO: Not implemented + } else if ("hasNavigationDelegate" == k) { + if (std::holds_alternative(val)) { + hasNavigationDelegate_ = std::get(val); + } + } else if ("debuggingEnabled" == k) { + // TODO: Not implemented + } else if ("gestureNavigationEnabled" == k) { + // TODO: Not implemented + } else if ("userAgent" == k) { + // TODO: Not implemented + } else { + throw std::invalid_argument("Unknown WebView setting: " + k); + } + } + } +} + /** * Added as a JavaScript interface to the WebView for any JavaScript channel * that the Dart code sets up. @@ -155,8 +324,10 @@ std::string WebView::GetChannelName() { void WebView::Dispose() { FlutterUnregisterExternalTexture(textureRegistrar_, GetTextureId()); - webViewInstance_->Destroy(); - webViewInstance_ = nullptr; + if (webViewInstance_) { + webViewInstance_->Destroy(); + webViewInstance_ = nullptr; + } } void WebView::Resize(double width, double height) { diff --git a/packages/webview_flutter/tizen/src/webview.h b/packages/webview_flutter/tizen/src/webview.h index bed8aef24..4502d9ca5 100644 --- a/packages/webview_flutter/tizen/src/webview.h +++ b/packages/webview_flutter/tizen/src/webview.h @@ -37,6 +37,8 @@ class WebView : public PlatformView { virtual void SetSoftwareKeyboardContext(Ecore_IMF_Context* context) override; + LWE::WebContainer* GetWebViewInstance() { return webViewInstance_; } + private: void HandleMethodCall( const flutter::MethodCall& method_call, @@ -46,6 +48,7 @@ class WebView : public PlatformView { void InitWebView(); void RegisterJavaScriptChannelName(const std::string& name); + void ApplySettings(flutter::EncodableMap); FlutterTextureRegistrar* textureRegistrar_; LWE::WebContainer* webViewInstance_; @@ -54,6 +57,7 @@ class WebView : public PlatformView { double height_; tbm_surface_h tbmSurface_; bool isMouseLButtonDown_; + bool hasNavigationDelegate_; std::unique_ptr> channel_; }; diff --git a/packages/webview_flutter/tizen/src/webview_factory.cc b/packages/webview_flutter/tizen/src/webview_factory.cc index 83100d204..80cc02c2d 100644 --- a/packages/webview_flutter/tizen/src/webview_factory.cc +++ b/packages/webview_flutter/tizen/src/webview_factory.cc @@ -36,8 +36,14 @@ PlatformView* WebViewFactory::Create(int viewId, double width, double height, if (std::holds_alternative(decodedValue)) { params = std::get(decodedValue); } - return new WebView(GetPluginRegistrar(), viewId, textureRegistrar_, width, - height, params); + + try { + return new WebView(GetPluginRegistrar(), viewId, textureRegistrar_, width, + height, params); + } catch (const std::invalid_argument& ex) { + LOG_ERROR("[Exception] %s\n", ex.what()); + return nullptr; + } } void WebViewFactory::Dispose() { LWE::LWE::Finalize(); }