Skip to content
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
7 changes: 7 additions & 0 deletions packages/webview_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 0.12.0

* Add `getCookies` to the cookie manager using the EWK and WV cookie getters.
* Add `setCookie` to the cookie manager on the WV backend.
* Apply `tizenEnginePolicy` before WV initialization.
* Fix cookie operations using a destroyed WebView.

## 0.11.1

* Update minimum supported SDK version to Flutter 3.38/Dart 3.10.
Expand Down
8 changes: 5 additions & 3 deletions packages/webview_flutter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ This package is not an _endorsed_ implementation of `webview_flutter`. Therefore
```yaml
dependencies:
webview_flutter: ^4.14.1
webview_flutter_tizen: ^0.11.1
webview_flutter_tizen: ^0.12.0
```

## Example
Expand Down Expand Up @@ -71,11 +71,13 @@ The plugin chooses a backend from the platform version reported by the device:
| 10.1 | WV API, EWK wrapper mode |
| 11.0 and later | WV API, standalone mode |

The WV backends are experimental. `WebViewController.tizenEnginePolicy` has no WV equivalent, so it is ignored (with a warning) on Tizen 10.1 and later.
The WV backends are experimental. `WebViewController.tizenEnginePolicy` calls `wv_set_version_policy()` before WV engine initialization. The first WV view's setting applies to the engine for its lifetime.

## Cookies

- `WebViewCookieManager.getCookies` throws `UnimplementedError`: neither backend can read cookies yet. On the EWK backend the web engine's cookie API returns nothing, a defect being fixed; on the WV backends that API is not yet in the platform library.
- `WebViewCookieManager.getCookies` calls the EWK or WV cookie getter. On the EWK backend (Tizen 10.0 and earlier), the getter currently returns no cookies because of an engine defect.
- `WebViewCookieManager.setCookie` uses the WV cookie manager. EWK has no cookie setter, so it throws `UnimplementedError` on the EWK backend.
- Cookie operations need a WebView that has been created, and fail before the first one is.

## Note

Expand Down
43 changes: 35 additions & 8 deletions packages/webview_flutter/lib/src/tizen_webview_cookie_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,49 @@ class TizenWebViewCookieManager extends PlatformWebViewCookieManager {
}

@override
Future<List<WebViewCookie>> getCookies(Uri url) {
throw UnimplementedError(
'This version of `TizenWebViewCookieManager` currently has no '
'implementation for getCookies method.',
Future<List<WebViewCookie>> getCookies(Uri url) async {
final String? cookies = await _cookieManagerChannel.invokeMethod<String>(
'getCookies',
url.toString(),
);
if (cookies == null || cookies.isEmpty) {
return <WebViewCookie>[];
}
return cookies
.split(';')
.map((String cookie) => cookie.trim())
.where((String cookie) => cookie.isNotEmpty)
.map((String cookie) {
final int separator = cookie.indexOf('=');
return WebViewCookie(
name: separator < 0 ? cookie : cookie.substring(0, separator),
value: separator < 0 ? '' : cookie.substring(separator + 1),
domain: url.host,
);
})
.toList();
}

@override
Future<void> setCookie(WebViewCookie cookie) async {
if (!_isValidPath(cookie.path)) {
throw ArgumentError('The path property for the provided cookie was not given a legal value.');
}
throw UnimplementedError(
'This version of `TizenWebViewCookieManager` currently has no '
'implementation for setCookie method.',
);
final String host = cookie.domain.startsWith('.') ? cookie.domain.substring(1) : cookie.domain;
final url = Uri(scheme: 'https', host: host, path: cookie.path).toString();
final line =
'${Uri.encodeComponent(cookie.name)}=${Uri.encodeComponent(cookie.value)}; path=${cookie.path}';
try {
await _cookieManagerChannel.invokeMethod<void>('setCookie', <String, String>{
'url': url,
'cookie': line,
});
} on PlatformException catch (e) {
if (e.code == 'Unsupported') {
throw UnimplementedError('setCookie is not supported by this web engine.');
}
rethrow;
}
}

bool _isValidPath(String path) {
Expand Down
2 changes: 1 addition & 1 deletion packages/webview_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: webview_flutter_tizen
description: Tizen implementation of the webview_flutter plugin.
homepage: https://github.com/flutter-tizen/plugins
repository: https://github.com/flutter-tizen/plugins/tree/main/packages/webview_flutter
version: 0.11.1
version: 0.12.0

environment:
sdk: ^3.10.0
Expand Down
7 changes: 7 additions & 0 deletions packages/webview_flutter/tizen/inc/ftpw_webview_flutter.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ void ftpw_webview_flutter_ewk_view_javascript_prompt_reply(void *o,
const char *result);
unsigned char ftpw_webview_flutter_ewk_view_main_frame_scrollbar_visible_set(
void *obj, unsigned char enabled);
char *ftpw_webview_flutter_ewk_view_get_cookies_for_url(void *view,
const char *url);
void ftpw_webview_flutter_ewk_set_arguments(int argc, char **argv);
int ftpw_webview_flutter_ewk_set_version_policy(int preference);
void ftpw_webview_flutter_ewk_settings_ime_panel_enabled_set(
Expand All @@ -177,12 +179,15 @@ const char *ftpw_webview_flutter_ewk_console_message_text_get(
int ftpw_webview_flutter_wv_init(void);
int ftpw_webview_flutter_wv_shutdown(void);
int ftpw_webview_flutter_wv_set_arguments(int argc, const char **argv);
int ftpw_webview_flutter_wv_set_version_policy(int preference);
void *ftpw_webview_flutter_wv_view_create(void);
void ftpw_webview_flutter_wv_view_destroy(void *view);
void ftpw_webview_flutter_wv_view_resize(void *view, int w, int h);
bool ftpw_webview_flutter_wv_view_focus_set(void *view, int focused);
bool ftpw_webview_flutter_wv_view_url_set(void *view, const char *url);
const char *ftpw_webview_flutter_wv_view_url_get(void *view);
char *ftpw_webview_flutter_wv_view_get_cookies_for_url(void *view,
const char *url);
bool ftpw_webview_flutter_wv_view_url_request_set(void *view, const char *url,
wv_http_method_e method,
void *headers,
Expand Down Expand Up @@ -263,6 +268,8 @@ int ftpw_webview_flutter_wv_context_web_storage_delete_all(void *context);
int ftpw_webview_flutter_wv_context_cache_clear(void *context);
int ftpw_webview_flutter_wv_cookie_manager_accept_policy_set(void *manager);
int ftpw_webview_flutter_wv_cookie_manager_cookies_clear(void *manager);
void ftpw_webview_flutter_wv_cookie_manager_set_cookie_for_url(
void *manager, const char *cookie_line, const char *url);
bool ftpw_webview_flutter_wv_settings_javascript_enabled_set(void *settings,
bool enable);
void ftpw_webview_flutter_wv_settings_ime_panel_enabled_set(void *settings,
Expand Down
Binary file not shown.
Binary file not shown.
Binary file modified packages/webview_flutter/tizen/lib/i586/libftpw_webview_flutter.so
Binary file not shown.
Binary file not shown.
10 changes: 10 additions & 0 deletions packages/webview_flutter/tizen/src/ewk_webview_backend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,16 @@ bool EwkWebViewBackend::ClearCookies() {
return false;
}

std::string EwkWebViewBackend::GetCookies(const std::string& url) {
return TakeEngineString(
ftpw_webview_flutter_ewk_view_get_cookies_for_url(view_, url.c_str()));
}

bool EwkWebViewBackend::SetCookie(const std::string& /*cookie_line*/,
const std::string& /*url*/) {
return false;
}

void EwkWebViewBackend::OnFrameRendered(void* data, Evas_Object* obj,
void* event_info) {
if (event_info) {
Expand Down
3 changes: 3 additions & 0 deletions packages/webview_flutter/tizen/src/ewk_webview_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ class EwkWebViewBackend : public WebViewBackend {
void JavaScriptPromptReply(const std::string& result) override;
void SetScrollbarVisible(bool visible) override;
bool ClearCookies() override;
std::string GetCookies(const std::string& url) override;
bool SetCookie(const std::string& cookie_line,
const std::string& url) override;

static void GlobalInitialize();

Expand Down
87 changes: 39 additions & 48 deletions packages/webview_flutter/tizen/src/webview.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <glib.h>
#include <tbm_surface.h>

#include <algorithm>
#include <functional>
#include <map>
#include <vector>
Expand Down Expand Up @@ -86,6 +87,8 @@ bool GetValueFromEncodableMap(const flutter::EncodableValue* arguments,

} // namespace

std::vector<WebView*> WebView::webviews_;

WebView::WebView(flutter::PluginRegistrar* registrar, int view_id,
flutter::TextureRegistrar* texture_registrar, double width,
double height, const flutter::EncodableValue& params,
Expand All @@ -96,11 +99,6 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int view_id,
height_(height),
window_(window) {
backend_ = WebViewBackendFactory::Create(this);
if (!backend_) {
LOG_ERROR("Failed to create a webview backend.");
return;
}

tbm_pool_ = std::make_shared<SingleBufferPool>(width, height);

texture_variant_ =
Expand Down Expand Up @@ -128,14 +126,7 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int view_id,
GetPluginRegistrar()->messenger(), GetNavigationDelegateChannelName(),
&flutter::StandardMethodCodec::GetInstance());

auto cookie_channel = std::make_unique<FlMethodChannel>(
GetPluginRegistrar()->messenger(),
"plugins.flutter.io/tizen_cookie_manager",
&flutter::StandardMethodCodec::GetInstance());
cookie_channel->SetMethodCallHandler(
[webview = this](const auto& call, auto result) {
webview->HandleCookieMethodCall(call, std::move(result));
});
webviews_.push_back(this);
}

WebView::~WebView() { Dispose(); }
Expand Down Expand Up @@ -164,9 +155,8 @@ void WebView::Dispose() {
}
*is_alive_ = false;

if (!backend_) {
return;
}
webviews_.erase(std::remove(webviews_.begin(), webviews_.end(), this),
webviews_.end());

std::shared_ptr<BufferPool> pool;
{
Expand Down Expand Up @@ -200,17 +190,9 @@ void WebView::InitializeEngine() { WebViewBackendFactory::InitializeEngine(); }

void WebView::ShutdownEngine() { WebViewBackendFactory::ShutdownEngine(); }

void WebView::Offset(double left, double top) {
if (!backend_) {
return;
}
backend_->Offset(left, top);
}
void WebView::Offset(double left, double top) { backend_->Offset(left, top); }

void WebView::Resize(double width, double height) {
if (!backend_) {
return;
}
width_ = width;
height_ = height;

Expand All @@ -224,36 +206,20 @@ void WebView::Resize(double width, double height) {

void WebView::Touch(int event_type, int button_type, double x, double y,
double dx, double dy) {
if (!backend_) {
return;
}
backend_->Touch(event_type, button_type, x, y, dx, dy);
}

bool WebView::SendKey(const char* key, const char* string, const char* compose,
uint32_t modifiers, uint32_t scan_code, bool is_down) {
if (!backend_) {
return false;
}
if (!IsFocused()) {
return false;
}
return backend_->SendKey(key, string, compose, modifiers, scan_code, is_down);
}

void WebView::Resume() {
if (!backend_) {
return;
}
backend_->Resume();
}
void WebView::Resume() { backend_->Resume(); }

void WebView::Stop() {
if (!backend_) {
return;
}
backend_->Stop();
}
void WebView::Stop() { backend_->Stop(); }

void WebView::SetDirection(int direction) {
// TODO: Implement if necessary.
Expand Down Expand Up @@ -289,7 +255,8 @@ void WebView::HandleWebViewMethodCall(const FlMethodCall& method_call,
}

if (!webview_created_) {
if (!backend_->Create(width_, height_, window_, engine_policy_)) {
if (!WebViewBackendFactory::EnsureEngineInitialized(engine_policy_) ||
!backend_->Create(width_, height_, window_, engine_policy_)) {
result->Error("Invalid operation",
"The webview instance initialize failed.");
return;
Expand Down Expand Up @@ -523,20 +490,44 @@ void WebView::HandleWebViewMethodCall(const FlMethodCall& method_call,

void WebView::HandleCookieMethodCall(const FlMethodCall& method_call,
std::unique_ptr<FlMethodResult> result) {
if (!webview_created_) {
result->Error("Invalid operation",
"The webview instance has not been initialized.");
auto it = std::find_if(webviews_.rbegin(), webviews_.rend(),
[](WebView* view) { return view->webview_created_; });
if (it == webviews_.rend()) {
result->Error("Invalid operation", "No webview instance is available.");
return;
}
WebView* webview = *it;

const std::string& method_name = method_call.method_name();

if (method_name == "clearCookies") {
if (backend_->ClearCookies()) {
if (webview->backend_->ClearCookies()) {
result->Success(flutter::EncodableValue(true));
} else {
result->Error("Operation failed", "Failed to get cookie manager");
}
} else if (method_name == "getCookies") {
const auto* url = std::get_if<std::string>(method_call.arguments());
if (!url) {
result->Error("Invalid argument", "The argument must be a string.");
return;
}
result->Success(
flutter::EncodableValue(webview->backend_->GetCookies(*url)));
} else if (method_name == "setCookie") {
std::string url;
std::string cookie;
if (!GetValueFromEncodableMap(method_call.arguments(), "url", &url) ||
!GetValueFromEncodableMap(method_call.arguments(), "cookie", &cookie)) {
result->Error("Invalid argument", "The URL and cookie must be strings.");
return;
}
if (webview->backend_->SetCookie(cookie, url)) {
result->Success();
} else {
result->Error("Unsupported",
"Setting cookies is not supported by this webview engine.");
}
} else {
result->NotImplemented();
}
Expand Down
11 changes: 9 additions & 2 deletions packages/webview_flutter/tizen/src/webview.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <memory>
#include <mutex>
#include <string>
#include <vector>

#include "webview_backend.h"

Expand Down Expand Up @@ -60,11 +61,14 @@ class WebView : public PlatformView, public WebViewBackend::Delegate {
// Must be called exactly once, after every WebView has been destroyed.
static void ShutdownEngine();

// NOTE: Cookies are shared by the web context, so calls go to the most
// recently created WebView that has been initialized.
static void HandleCookieMethodCall(const FlMethodCall& method_call,
std::unique_ptr<FlMethodResult> result);

private:
void HandleWebViewMethodCall(const FlMethodCall& method_call,
std::unique_ptr<FlMethodResult> result);
void HandleCookieMethodCall(const FlMethodCall& method_call,
std::unique_ptr<FlMethodResult> result);

template <typename T>
void SetBackgroundColor(const T& color);
Expand Down Expand Up @@ -95,6 +99,9 @@ class WebView : public PlatformView, public WebViewBackend::Delegate {
const std::string& default_text,
const std::string& url) override;

// Live WebViews, in creation order. Only touched on the platform thread.
static std::vector<WebView*> webviews_;

std::unique_ptr<WebViewBackend> backend_;
bool webview_created_ = false;
flutter::TextureRegistrar* texture_registrar_;
Expand Down
11 changes: 11 additions & 0 deletions packages/webview_flutter/tizen/src/webview_backend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <algorithm>
#include <atomic>
#include <cstdlib>
#include <mutex>
#include <vector>

Expand Down Expand Up @@ -81,3 +82,13 @@ void WebViewBackend::FlushPendingTeardowns() {
}
}
}

std::string WebViewBackend::TakeEngineString(char* value) {
// The engine returns NULL when the URL has no cookies.
if (!value) {
return std::string();
}
std::string result(value);
free(value);
return result;
}
Loading
Loading