Skip to content

Commit 3feae1d

Browse files
authored
[webview_flutter] Add NavigationDelegate and onWebResourceError (flutter-tizen#36)
* The NavigationDelegate handler decides how to handle navigation actions * When the handler is null, all navigation actions are allowed * Implement the onWebResourceError callback to report web resource loading error * The callback's error codes use ones provided by lightweight-web-engine on tizen Signed-off-by: Seungsoo Lee <[email protected]>
1 parent 42b63f8 commit 3feae1d

File tree

3 files changed

+190
-9
lines changed

3 files changed

+190
-9
lines changed

packages/webview_flutter/tizen/src/webview.cc

+178-7
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,99 @@ extern "C" size_t LWE_EXPORT createWebViewInstance(
2626
const std::function<void(::LWE::WebContainer*, bool isRendered)>&
2727
renderedCb);
2828

29+
template <typename T = flutter::EncodableValue>
30+
class NavigationRequestResult : public flutter::MethodResult<T> {
31+
public:
32+
NavigationRequestResult(std::string url, WebView* webView)
33+
: url_(url), webView_(webView) {}
34+
35+
void SuccessInternal(const T* shouldLoad) override {
36+
if (std::holds_alternative<bool>(*shouldLoad)) {
37+
if (std::get<bool>(*shouldLoad)) {
38+
LoadUrl();
39+
}
40+
}
41+
}
42+
43+
void ErrorInternal(const std::string& error_code,
44+
const std::string& error_message,
45+
const T* error_details) override {
46+
throw std::invalid_argument("navigationRequest calls must succeed [code:" +
47+
error_code + "][msg:" + error_message + "]");
48+
}
49+
50+
void NotImplementedInternal() override {
51+
throw std::invalid_argument(
52+
"navigationRequest must be implemented by the webview method channel");
53+
}
54+
55+
private:
56+
void LoadUrl() {
57+
if (webView_ && webView_->GetWebViewInstance()) {
58+
webView_->GetWebViewInstance()->LoadURL(url_);
59+
}
60+
}
61+
62+
std::string url_;
63+
WebView* webView_;
64+
};
65+
66+
enum RequestErrorType {
67+
NoError,
68+
UnknownError,
69+
HostLookupError,
70+
UnsupportedAuthSchemeError,
71+
AuthenticationError,
72+
ProxyAuthenticationError,
73+
ConnectError,
74+
IOError,
75+
TimeoutError,
76+
RedirectLoopError,
77+
UnsupportedSchemeError,
78+
FailedSSLHandshakeError,
79+
BadURLError,
80+
FileError,
81+
FileNotFoundError,
82+
TooManyRequestError,
83+
};
84+
85+
static std::string ErrorCodeToString(int errorCode) {
86+
switch (errorCode) {
87+
case RequestErrorType::AuthenticationError:
88+
return "authentication";
89+
case RequestErrorType::BadURLError:
90+
return "badUrl";
91+
case RequestErrorType::ConnectError:
92+
return "connect";
93+
case RequestErrorType::FailedSSLHandshakeError:
94+
return "failedSslHandshake";
95+
case RequestErrorType::FileError:
96+
return "file";
97+
case RequestErrorType::FileNotFoundError:
98+
return "fileNotFound";
99+
case RequestErrorType::HostLookupError:
100+
return "hostLookup";
101+
case RequestErrorType::IOError:
102+
return "io";
103+
case RequestErrorType::ProxyAuthenticationError:
104+
return "proxyAuthentication";
105+
case RequestErrorType::RedirectLoopError:
106+
return "redirectLoop";
107+
case RequestErrorType::TimeoutError:
108+
return "timeout";
109+
case RequestErrorType::TooManyRequestError:
110+
return "tooManyRequests";
111+
case RequestErrorType::UnknownError:
112+
return "unknown";
113+
case RequestErrorType::UnsupportedAuthSchemeError:
114+
return "unsupportedAuthScheme";
115+
case RequestErrorType::UnsupportedSchemeError:
116+
return "unsupportedScheme";
117+
}
118+
std::string message = "Could not find a string for errorCode: " + errorCode;
119+
throw std::invalid_argument(message);
120+
}
121+
29122
std::string ExtractStringFromMap(const flutter::EncodableValue& arguments,
30123
const char* key) {
31124
if (std::holds_alternative<flutter::EncodableMap>(arguments)) {
@@ -63,7 +156,9 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int viewId,
63156
webViewInstance_(nullptr),
64157
width_(width),
65158
height_(height),
66-
tbmSurface_(nullptr) {
159+
tbmSurface_(nullptr),
160+
isMouseLButtonDown_(false),
161+
hasNavigationDelegate_(false) {
67162
SetTextureId(FlutterRegisterExternalTexture(textureRegistrar_));
68163
InitWebView();
69164

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

180+
auto settings = params[flutter::EncodableValue("settings")];
181+
if (std::holds_alternative<flutter::EncodableMap>(settings)) {
182+
auto settingList = std::get<flutter::EncodableMap>(settings);
183+
if (settingList.size() > 0) {
184+
ApplySettings(settingList);
185+
}
186+
}
187+
85188
auto names = params[flutter::EncodableValue("javascriptChannelNames")];
86189
if (std::holds_alternative<flutter::EncodableList>(names)) {
87190
auto nameList = std::get<flutter::EncodableList>(names);
@@ -99,8 +202,7 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int viewId,
99202
map.insert(
100203
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
101204
flutter::EncodableValue("url"), flutter::EncodableValue(url)));
102-
std::unique_ptr<flutter::EncodableValue> args =
103-
std::make_unique<flutter::EncodableValue>(map);
205+
auto args = std::make_unique<flutter::EncodableValue>(map);
104206
channel_->InvokeMethod("onPageStarted", std::move(args));
105207
});
106208
webViewInstance_->RegisterOnPageLoadedHandler(
@@ -110,14 +212,81 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int viewId,
110212
map.insert(
111213
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
112214
flutter::EncodableValue("url"), flutter::EncodableValue(url)));
113-
std::unique_ptr<flutter::EncodableValue> args =
114-
std::make_unique<flutter::EncodableValue>(map);
215+
auto args = std::make_unique<flutter::EncodableValue>(map);
216+
channel_->InvokeMethod("onPageFinished", std::move(args));
217+
});
218+
webViewInstance_->RegisterOnReceivedErrorHandler(
219+
[this](LWE::WebContainer* container, LWE::ResourceError e) {
220+
flutter::EncodableMap map;
221+
map.insert(
222+
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
223+
flutter::EncodableValue("errorCode"),
224+
flutter::EncodableValue(e.GetErrorCode())));
225+
map.insert(
226+
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
227+
flutter::EncodableValue("description"),
228+
flutter::EncodableValue(e.GetDescription())));
229+
map.insert(
230+
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
231+
flutter::EncodableValue("errorType"),
232+
flutter::EncodableValue(ErrorCodeToString(e.GetErrorCode()))));
233+
map.insert(
234+
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
235+
flutter::EncodableValue("failingUrl"),
236+
flutter::EncodableValue(e.GetUrl())));
237+
auto args = std::make_unique<flutter::EncodableValue>(map);
115238
channel_->InvokeMethod("onPageFinished", std::move(args));
116239
});
117240

241+
webViewInstance_->RegisterShouldOverrideUrlLoadingHandler(
242+
[this](LWE::WebContainer* view, const std::string& url) -> bool {
243+
if (!hasNavigationDelegate_) {
244+
return false;
245+
}
246+
flutter::EncodableMap map;
247+
map.insert(
248+
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
249+
flutter::EncodableValue("url"), flutter::EncodableValue(url)));
250+
map.insert(
251+
std::make_pair<flutter::EncodableValue, flutter::EncodableValue>(
252+
flutter::EncodableValue("isForMainFrame"),
253+
flutter::EncodableValue(true)));
254+
auto args = std::make_unique<flutter::EncodableValue>(map);
255+
auto onResult =
256+
std::make_unique<NavigationRequestResult<flutter::EncodableValue>>(
257+
url, this);
258+
channel_->InvokeMethod("navigationRequest", std::move(args),
259+
std::move(onResult));
260+
261+
return true;
262+
});
263+
118264
webViewInstance_->LoadURL(currentUrl_);
119265
}
120266

267+
void WebView::ApplySettings(flutter::EncodableMap settings) {
268+
for (auto const& [key, val] : settings) {
269+
if (std::holds_alternative<std::string>(key)) {
270+
std::string k = std::get<std::string>(key);
271+
if ("jsMode" == k) {
272+
// TODO: Not implemented
273+
} else if ("hasNavigationDelegate" == k) {
274+
if (std::holds_alternative<bool>(val)) {
275+
hasNavigationDelegate_ = std::get<bool>(val);
276+
}
277+
} else if ("debuggingEnabled" == k) {
278+
// TODO: Not implemented
279+
} else if ("gestureNavigationEnabled" == k) {
280+
// TODO: Not implemented
281+
} else if ("userAgent" == k) {
282+
// TODO: Not implemented
283+
} else {
284+
throw std::invalid_argument("Unknown WebView setting: " + k);
285+
}
286+
}
287+
}
288+
}
289+
121290
/**
122291
* Added as a JavaScript interface to the WebView for any JavaScript channel
123292
* that the Dart code sets up.
@@ -155,8 +324,10 @@ std::string WebView::GetChannelName() {
155324
void WebView::Dispose() {
156325
FlutterUnregisterExternalTexture(textureRegistrar_, GetTextureId());
157326

158-
webViewInstance_->Destroy();
159-
webViewInstance_ = nullptr;
327+
if (webViewInstance_) {
328+
webViewInstance_->Destroy();
329+
webViewInstance_ = nullptr;
330+
}
160331
}
161332

162333
void WebView::Resize(double width, double height) {

packages/webview_flutter/tizen/src/webview.h

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class WebView : public PlatformView {
3737

3838
virtual void SetSoftwareKeyboardContext(Ecore_IMF_Context* context) override;
3939

40+
LWE::WebContainer* GetWebViewInstance() { return webViewInstance_; }
41+
4042
private:
4143
void HandleMethodCall(
4244
const flutter::MethodCall<flutter::EncodableValue>& method_call,
@@ -46,6 +48,7 @@ class WebView : public PlatformView {
4648
void InitWebView();
4749

4850
void RegisterJavaScriptChannelName(const std::string& name);
51+
void ApplySettings(flutter::EncodableMap);
4952

5053
FlutterTextureRegistrar* textureRegistrar_;
5154
LWE::WebContainer* webViewInstance_;
@@ -54,6 +57,7 @@ class WebView : public PlatformView {
5457
double height_;
5558
tbm_surface_h tbmSurface_;
5659
bool isMouseLButtonDown_;
60+
bool hasNavigationDelegate_;
5761
std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel_;
5862
};
5963

packages/webview_flutter/tizen/src/webview_factory.cc

+8-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,14 @@ PlatformView* WebViewFactory::Create(int viewId, double width, double height,
3636
if (std::holds_alternative<flutter::EncodableMap>(decodedValue)) {
3737
params = std::get<flutter::EncodableMap>(decodedValue);
3838
}
39-
return new WebView(GetPluginRegistrar(), viewId, textureRegistrar_, width,
40-
height, params);
39+
40+
try {
41+
return new WebView(GetPluginRegistrar(), viewId, textureRegistrar_, width,
42+
height, params);
43+
} catch (const std::invalid_argument& ex) {
44+
LOG_ERROR("[Exception] %s\n", ex.what());
45+
return nullptr;
46+
}
4147
}
4248

4349
void WebViewFactory::Dispose() { LWE::LWE::Finalize(); }

0 commit comments

Comments
 (0)