Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[webview_flutter] Add NavigationDelegate and onWebResourceError #36

Merged
merged 1 commit into from
Feb 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 178 additions & 7 deletions packages/webview_flutter/tizen/src/webview.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,99 @@ extern "C" size_t LWE_EXPORT createWebViewInstance(
const std::function<void(::LWE::WebContainer*, bool isRendered)>&
renderedCb);

template <typename T = flutter::EncodableValue>
class NavigationRequestResult : public flutter::MethodResult<T> {
public:
NavigationRequestResult(std::string url, WebView* webView)
: url_(url), webView_(webView) {}

void SuccessInternal(const T* shouldLoad) override {
if (std::holds_alternative<bool>(*shouldLoad)) {
if (std::get<bool>(*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<flutter::EncodableMap>(arguments)) {
Expand Down Expand Up @@ -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();

Expand All @@ -82,6 +177,14 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int viewId,
currentUrl_ = "about:blank";
}

auto settings = params[flutter::EncodableValue("settings")];
if (std::holds_alternative<flutter::EncodableMap>(settings)) {
auto settingList = std::get<flutter::EncodableMap>(settings);
if (settingList.size() > 0) {
ApplySettings(settingList);
bbrto21 marked this conversation as resolved.
Show resolved Hide resolved
}
}

auto names = params[flutter::EncodableValue("javascriptChannelNames")];
if (std::holds_alternative<flutter::EncodableList>(names)) {
auto nameList = std::get<flutter::EncodableList>(names);
Expand All @@ -99,8 +202,7 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int viewId,
map.insert(
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
flutter::EncodableValue("url"), flutter::EncodableValue(url)));
std::unique_ptr<flutter::EncodableValue> args =
std::make_unique<flutter::EncodableValue>(map);
auto args = std::make_unique<flutter::EncodableValue>(map);
channel_->InvokeMethod("onPageStarted", std::move(args));
});
webViewInstance_->RegisterOnPageLoadedHandler(
Expand All @@ -110,14 +212,81 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int viewId,
map.insert(
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
flutter::EncodableValue("url"), flutter::EncodableValue(url)));
std::unique_ptr<flutter::EncodableValue> args =
std::make_unique<flutter::EncodableValue>(map);
auto args = std::make_unique<flutter::EncodableValue>(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, flutter::EncodableValue>(
flutter::EncodableValue("errorCode"),
flutter::EncodableValue(e.GetErrorCode())));
map.insert(
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
flutter::EncodableValue("description"),
flutter::EncodableValue(e.GetDescription())));
map.insert(
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
flutter::EncodableValue("errorType"),
flutter::EncodableValue(ErrorCodeToString(e.GetErrorCode()))));
map.insert(
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
flutter::EncodableValue("failingUrl"),
flutter::EncodableValue(e.GetUrl())));
auto args = std::make_unique<flutter::EncodableValue>(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, flutter::EncodableValue>(
flutter::EncodableValue("url"), flutter::EncodableValue(url)));
map.insert(
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
flutter::EncodableValue("isForMainFrame"),
flutter::EncodableValue(true)));
auto args = std::make_unique<flutter::EncodableValue>(map);
auto onResult =
std::make_unique<NavigationRequestResult<flutter::EncodableValue>>(
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<std::string>(key)) {
std::string k = std::get<std::string>(key);
if ("jsMode" == k) {
// TODO: Not implemented
} else if ("hasNavigationDelegate" == k) {
if (std::holds_alternative<bool>(val)) {
hasNavigationDelegate_ = std::get<bool>(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.
Expand Down Expand 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) {
Expand Down
4 changes: 4 additions & 0 deletions packages/webview_flutter/tizen/src/webview.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<flutter::EncodableValue>& method_call,
Expand All @@ -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_;
Expand All @@ -54,6 +57,7 @@ class WebView : public PlatformView {
double height_;
tbm_surface_h tbmSurface_;
bool isMouseLButtonDown_;
bool hasNavigationDelegate_;
std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel_;
};

Expand Down
10 changes: 8 additions & 2 deletions packages/webview_flutter/tizen/src/webview_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,14 @@ PlatformView* WebViewFactory::Create(int viewId, double width, double height,
if (std::holds_alternative<flutter::EncodableMap>(decodedValue)) {
params = std::get<flutter::EncodableMap>(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(); }