diff --git a/packages/webview_flutter_lwe/CHANGELOG.md b/packages/webview_flutter_lwe/CHANGELOG.md index 8cce9820e..b83c5c375 100644 --- a/packages/webview_flutter_lwe/CHANGELOG.md +++ b/packages/webview_flutter_lwe/CHANGELOG.md @@ -1,3 +1,15 @@ +## 0.5.0 + +* Implement `onUrlChange` for the navigation delegate. +* Fix navigation delegate callbacks being dropped when the navigation delegate + is replaced after the WebView is created. +* Fix a crash on the raster thread when a WebView is disposed while a frame is + still being composited. +* Fix a use-after-free when navigation-delegate or JavaScript-channel callbacks + run after the WebView has been disposed. +* Add 1 integration test case. +* Update lightweight web engine (1.3.40). + ## 0.4.1 * Remove Ecore API. diff --git a/packages/webview_flutter_lwe/README.md b/packages/webview_flutter_lwe/README.md index f4efc638a..92078ebcf 100644 --- a/packages/webview_flutter_lwe/README.md +++ b/packages/webview_flutter_lwe/README.md @@ -21,7 +21,7 @@ This package is not an _endorsed_ implementation of `webview_flutter`. Therefore ```yaml dependencies: webview_flutter: ^4.13.1 - webview_flutter_lwe: ^0.4.1 + webview_flutter_lwe: ^0.4.2 ``` ## Example diff --git a/packages/webview_flutter_lwe/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter_lwe/example/integration_test/webview_flutter_test.dart index 161345f91..bf7de8a64 100644 --- a/packages/webview_flutter_lwe/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter_lwe/example/integration_test/webview_flutter_test.dart @@ -447,6 +447,36 @@ Future main() async { final String? currentUrl = await controller.currentUrl(); expect(currentUrl, secondaryUrl); }); + + testWidgets('can receive url changes', (WidgetTester tester) async { + final Completer pageLoaded = Completer(); + + final WebViewController controller = WebViewController(); + unawaited(controller.setJavaScriptMode(JavaScriptMode.unrestricted)); + unawaited( + controller.setNavigationDelegate( + NavigationDelegate(onPageFinished: (_) => pageLoaded.complete()), + ), + ); + unawaited(controller.loadRequest(Uri.parse(blankPageEncoded))); + + await tester.pumpWidget(WebViewWidget(controller: controller)); + + await pageLoaded.future; + + final Completer urlChangeCompleter = Completer(); + await controller.setNavigationDelegate( + NavigationDelegate( + onUrlChange: (UrlChange change) { + urlChangeCompleter.complete(change.url); + }, + ), + ); + + await controller.runJavaScript('location.href = "$primaryUrl"'); + + await expectLater(urlChangeCompleter.future, completion(primaryUrl)); + }); }); } diff --git a/packages/webview_flutter_lwe/lib/src/lwe_webview_controller.dart b/packages/webview_flutter_lwe/lib/src/lwe_webview_controller.dart index 9a0f9ebbf..91fb54fa9 100644 --- a/packages/webview_flutter_lwe/lib/src/lwe_webview_controller.dart +++ b/packages/webview_flutter_lwe/lib/src/lwe_webview_controller.dart @@ -25,9 +25,11 @@ class LweWebViewController extends PlatformWebViewController { final LweWebView _webview; late LweNavigationDelegate _lweNavigationDelegate; + int? _viewId; /// Called when [TizenView] is created. void onCreate(int viewId) { + _viewId = viewId; if (_webview.hasNavigationDelegate) { _lweNavigationDelegate.onCreate(viewId); } @@ -142,6 +144,15 @@ class LweWebViewController extends PlatformWebViewController { ) async { _lweNavigationDelegate = handler; _webview.hasNavigationDelegate = true; + // If the view has already been created, the previous delegate's method + // call handler is the one currently bound to the platform channel. Bind + // the new delegate now so its callbacks (e.g. onUrlChange, onPageFinished) + // are the ones invoked; otherwise events would keep going to the old + // delegate and be dropped. + final int? viewId = _viewId; + if (viewId != null) { + handler.onCreate(viewId); + } } @override @@ -382,15 +393,21 @@ class LweNavigationDelegate extends PlatformNavigationDelegate { /// Creates a new [LweNavigationDelegate]. LweNavigationDelegate(super.params) : super.implementation(); - late final MethodChannel _navigationDelegateChannel; + late MethodChannel _navigationDelegateChannel; + int? _viewId; PageEventCallback? _onPageFinished; PageEventCallback? _onPageStarted; ProgressCallback? _onProgress; WebResourceErrorCallback? _onWebResourceError; NavigationRequestCallback? _onNavigationRequest; + UrlChangeCallback? _onUrlChange; /// Called when [TizenView] is created. void onCreate(int viewId) { + if (_viewId == viewId) { + return; + } + _viewId = viewId; _navigationDelegateChannel = MethodChannel( kLweNavigationDelegateChannelName + viewId.toString(), ); @@ -431,6 +448,11 @@ class LweNavigationDelegate extends PlatformNavigationDelegate { ); } return null; + case 'onUrlChange': + if (_onUrlChange != null) { + _onUrlChange!(UrlChange(url: arguments['url']! as String)); + } + return null; } throw MissingPluginException( @@ -506,10 +528,7 @@ class LweNavigationDelegate extends PlatformNavigationDelegate { @override Future setOnUrlChange(UrlChangeCallback onUrlChange) async { - throw UnimplementedError( - 'This version of `LweNavigationDelegate` currently has no ' - 'implementation for `setOnUrlChange`', - ); + _onUrlChange = onUrlChange; } @override diff --git a/packages/webview_flutter_lwe/pubspec.yaml b/packages/webview_flutter_lwe/pubspec.yaml index 15653efc9..6296073d3 100644 --- a/packages/webview_flutter_lwe/pubspec.yaml +++ b/packages/webview_flutter_lwe/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_lwe description: Tizen implementation of the webview_flutter plugin backed by Lightweight Web Engine. homepage: https://github.com/flutter-tizen/plugins repository: https://github.com/flutter-tizen/plugins/tree/master/packages/webview_flutter_lwe -version: 0.4.1 +version: 0.5.0 environment: sdk: ^3.8.0 diff --git a/packages/webview_flutter_lwe/tizen/lib/aarch64/libclipper.so b/packages/webview_flutter_lwe/tizen/lib/aarch64/libclipper.so index c9fcdb1bc..22597ab7c 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/aarch64/libclipper.so and b/packages/webview_flutter_lwe/tizen/lib/aarch64/libclipper.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/aarch64/liblightweight-web-engine.flutter-impl.so b/packages/webview_flutter_lwe/tizen/lib/aarch64/liblightweight-web-engine.flutter-impl.so index a1c6f0e7a..803ff2fec 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/aarch64/liblightweight-web-engine.flutter-impl.so and b/packages/webview_flutter_lwe/tizen/lib/aarch64/liblightweight-web-engine.flutter-impl.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/aarch64/liblightweight-web-engine.flutter.so b/packages/webview_flutter_lwe/tizen/lib/aarch64/liblightweight-web-engine.flutter.so index 342fb49eb..e40f78bdf 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/aarch64/liblightweight-web-engine.flutter.so and b/packages/webview_flutter_lwe/tizen/lib/aarch64/liblightweight-web-engine.flutter.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/aarch64/libmp4parse.so b/packages/webview_flutter_lwe/tizen/lib/aarch64/libmp4parse.so index d81f8735e..472bb31c5 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/aarch64/libmp4parse.so and b/packages/webview_flutter_lwe/tizen/lib/aarch64/libmp4parse.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/aarch64/libskia_matrix.so b/packages/webview_flutter_lwe/tizen/lib/aarch64/libskia_matrix.so index 8b08ffcb4..76976887f 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/aarch64/libskia_matrix.so and b/packages/webview_flutter_lwe/tizen/lib/aarch64/libskia_matrix.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/aarch64/libtuv.so b/packages/webview_flutter_lwe/tizen/lib/aarch64/libtuv.so index 66f09c33d..be208621e 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/aarch64/libtuv.so and b/packages/webview_flutter_lwe/tizen/lib/aarch64/libtuv.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/aarch64/libwebm.so b/packages/webview_flutter_lwe/tizen/lib/aarch64/libwebm.so index 715ebc92d..a24b79b2d 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/aarch64/libwebm.so and b/packages/webview_flutter_lwe/tizen/lib/aarch64/libwebm.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/aarch64/libwebp_lwe.so b/packages/webview_flutter_lwe/tizen/lib/aarch64/libwebp_lwe.so index cd3c1a9e0..e632dcc71 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/aarch64/libwebp_lwe.so and b/packages/webview_flutter_lwe/tizen/lib/aarch64/libwebp_lwe.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/aarch64/libwebsockets_lwe.so b/packages/webview_flutter_lwe/tizen/lib/aarch64/libwebsockets_lwe.so new file mode 100644 index 000000000..9c11f9b49 Binary files /dev/null and b/packages/webview_flutter_lwe/tizen/lib/aarch64/libwebsockets_lwe.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/armel/libclipper.so b/packages/webview_flutter_lwe/tizen/lib/armel/libclipper.so index a2be96150..29301d806 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/armel/libclipper.so and b/packages/webview_flutter_lwe/tizen/lib/armel/libclipper.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/armel/liblightweight-web-engine.flutter-impl.so b/packages/webview_flutter_lwe/tizen/lib/armel/liblightweight-web-engine.flutter-impl.so index a900c9ceb..d77609dc7 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/armel/liblightweight-web-engine.flutter-impl.so and b/packages/webview_flutter_lwe/tizen/lib/armel/liblightweight-web-engine.flutter-impl.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/armel/liblightweight-web-engine.flutter.so b/packages/webview_flutter_lwe/tizen/lib/armel/liblightweight-web-engine.flutter.so index cf06c2959..e499c3a78 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/armel/liblightweight-web-engine.flutter.so and b/packages/webview_flutter_lwe/tizen/lib/armel/liblightweight-web-engine.flutter.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/armel/libmp4parse.so b/packages/webview_flutter_lwe/tizen/lib/armel/libmp4parse.so index 7f78668e2..954c0b903 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/armel/libmp4parse.so and b/packages/webview_flutter_lwe/tizen/lib/armel/libmp4parse.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/armel/libskia_matrix.so b/packages/webview_flutter_lwe/tizen/lib/armel/libskia_matrix.so index 123414ba5..70ec2f276 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/armel/libskia_matrix.so and b/packages/webview_flutter_lwe/tizen/lib/armel/libskia_matrix.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/armel/libtuv.so b/packages/webview_flutter_lwe/tizen/lib/armel/libtuv.so index a2dcedca6..4edc8dcde 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/armel/libtuv.so and b/packages/webview_flutter_lwe/tizen/lib/armel/libtuv.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/armel/libwebm.so b/packages/webview_flutter_lwe/tizen/lib/armel/libwebm.so index 5f433ff7c..07e4db17a 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/armel/libwebm.so and b/packages/webview_flutter_lwe/tizen/lib/armel/libwebm.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/armel/libwebp_lwe.so b/packages/webview_flutter_lwe/tizen/lib/armel/libwebp_lwe.so index 9505c819e..fbf8a6806 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/armel/libwebp_lwe.so and b/packages/webview_flutter_lwe/tizen/lib/armel/libwebp_lwe.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/armel/libwebsockets_lwe.so b/packages/webview_flutter_lwe/tizen/lib/armel/libwebsockets_lwe.so new file mode 100644 index 000000000..242e6cd31 Binary files /dev/null and b/packages/webview_flutter_lwe/tizen/lib/armel/libwebsockets_lwe.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/i586/libclipper.so b/packages/webview_flutter_lwe/tizen/lib/i586/libclipper.so index 7b30d96a9..1641100fc 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/i586/libclipper.so and b/packages/webview_flutter_lwe/tizen/lib/i586/libclipper.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/i586/liblightweight-web-engine.flutter-impl.so b/packages/webview_flutter_lwe/tizen/lib/i586/liblightweight-web-engine.flutter-impl.so index dcb17c99e..b3def255a 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/i586/liblightweight-web-engine.flutter-impl.so and b/packages/webview_flutter_lwe/tizen/lib/i586/liblightweight-web-engine.flutter-impl.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/i586/liblightweight-web-engine.flutter.so b/packages/webview_flutter_lwe/tizen/lib/i586/liblightweight-web-engine.flutter.so index 673f8f407..ca7217793 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/i586/liblightweight-web-engine.flutter.so and b/packages/webview_flutter_lwe/tizen/lib/i586/liblightweight-web-engine.flutter.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/i586/libmp4parse.so b/packages/webview_flutter_lwe/tizen/lib/i586/libmp4parse.so index 8ecedd1b3..1f5dab7fc 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/i586/libmp4parse.so and b/packages/webview_flutter_lwe/tizen/lib/i586/libmp4parse.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/i586/libskia_matrix.so b/packages/webview_flutter_lwe/tizen/lib/i586/libskia_matrix.so index 145049b45..bbd6502c2 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/i586/libskia_matrix.so and b/packages/webview_flutter_lwe/tizen/lib/i586/libskia_matrix.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/i586/libtuv.so b/packages/webview_flutter_lwe/tizen/lib/i586/libtuv.so index e12fdd777..c4e4fff73 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/i586/libtuv.so and b/packages/webview_flutter_lwe/tizen/lib/i586/libtuv.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/i586/libwebm.so b/packages/webview_flutter_lwe/tizen/lib/i586/libwebm.so index bbc7e3748..19643ead1 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/i586/libwebm.so and b/packages/webview_flutter_lwe/tizen/lib/i586/libwebm.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/i586/libwebp_lwe.so b/packages/webview_flutter_lwe/tizen/lib/i586/libwebp_lwe.so index 55d5cba60..968c0a71c 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/i586/libwebp_lwe.so and b/packages/webview_flutter_lwe/tizen/lib/i586/libwebp_lwe.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/i586/libwebsockets_lwe.so b/packages/webview_flutter_lwe/tizen/lib/i586/libwebsockets_lwe.so new file mode 100644 index 000000000..261ecf7f5 Binary files /dev/null and b/packages/webview_flutter_lwe/tizen/lib/i586/libwebsockets_lwe.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/x86_64/libclipper.so b/packages/webview_flutter_lwe/tizen/lib/x86_64/libclipper.so index d08fe6e84..dc2ee8774 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/x86_64/libclipper.so and b/packages/webview_flutter_lwe/tizen/lib/x86_64/libclipper.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/x86_64/liblightweight-web-engine.flutter-impl.so b/packages/webview_flutter_lwe/tizen/lib/x86_64/liblightweight-web-engine.flutter-impl.so index 0244d612c..efa76abe3 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/x86_64/liblightweight-web-engine.flutter-impl.so and b/packages/webview_flutter_lwe/tizen/lib/x86_64/liblightweight-web-engine.flutter-impl.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/x86_64/liblightweight-web-engine.flutter.so b/packages/webview_flutter_lwe/tizen/lib/x86_64/liblightweight-web-engine.flutter.so index 62d5454a8..94e37dd81 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/x86_64/liblightweight-web-engine.flutter.so and b/packages/webview_flutter_lwe/tizen/lib/x86_64/liblightweight-web-engine.flutter.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/x86_64/libmp4parse.so b/packages/webview_flutter_lwe/tizen/lib/x86_64/libmp4parse.so index 7c5938f81..f64867de4 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/x86_64/libmp4parse.so and b/packages/webview_flutter_lwe/tizen/lib/x86_64/libmp4parse.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/x86_64/libskia_matrix.so b/packages/webview_flutter_lwe/tizen/lib/x86_64/libskia_matrix.so index 7812b9866..b6e435d8b 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/x86_64/libskia_matrix.so and b/packages/webview_flutter_lwe/tizen/lib/x86_64/libskia_matrix.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/x86_64/libtuv.so b/packages/webview_flutter_lwe/tizen/lib/x86_64/libtuv.so index b96ad69c8..dde3d38ff 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/x86_64/libtuv.so and b/packages/webview_flutter_lwe/tizen/lib/x86_64/libtuv.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/x86_64/libwebm.so b/packages/webview_flutter_lwe/tizen/lib/x86_64/libwebm.so index 16b3cf827..51a93385a 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/x86_64/libwebm.so and b/packages/webview_flutter_lwe/tizen/lib/x86_64/libwebm.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/x86_64/libwebp_lwe.so b/packages/webview_flutter_lwe/tizen/lib/x86_64/libwebp_lwe.so index 15ffe5ec8..aa4b6b8cb 100644 Binary files a/packages/webview_flutter_lwe/tizen/lib/x86_64/libwebp_lwe.so and b/packages/webview_flutter_lwe/tizen/lib/x86_64/libwebp_lwe.so differ diff --git a/packages/webview_flutter_lwe/tizen/lib/x86_64/libwebsockets_lwe.so b/packages/webview_flutter_lwe/tizen/lib/x86_64/libwebsockets_lwe.so new file mode 100644 index 000000000..658fde06d Binary files /dev/null and b/packages/webview_flutter_lwe/tizen/lib/x86_64/libwebsockets_lwe.so differ diff --git a/packages/webview_flutter_lwe/tizen/src/webview.cc b/packages/webview_flutter_lwe/tizen/src/webview.cc index 59d50e70e..87e0350fc 100644 --- a/packages/webview_flutter_lwe/tizen/src/webview.cc +++ b/packages/webview_flutter_lwe/tizen/src/webview.cc @@ -37,8 +37,12 @@ extern "C" size_t LWE_EXPORT createWebViewInstance( class NavigationRequestResult : public FlMethodResult { public: - NavigationRequestResult(std::string url, WebView* webview) - : url_(url), webview_(webview) {} + // Dart resolves "navigationRequest" asynchronously, so this result may + // complete after the WebView has been disposed. |alive| (the WebView's + // is_alive_ flag) is checked before dereferencing |webview_|. + NavigationRequestResult(std::string url, WebView* webview, + std::shared_ptr alive) + : url_(url), webview_(webview), alive_(std::move(alive)) {} void SuccessInternal(const flutter::EncodableValue* should_load) override { if (std::holds_alternative(*should_load)) { @@ -60,6 +64,9 @@ class NavigationRequestResult : public FlMethodResult { private: void LoadUrl() { + if (!*alive_) { + return; + } if (webview_ && webview_->GetWebViewInstance()) { webview_->GetWebViewInstance()->LoadURL(url_); } @@ -67,6 +74,7 @@ class NavigationRequestResult : public FlMethodResult { std::string url_; WebView* webview_; + std::shared_ptr alive_; }; template @@ -125,7 +133,7 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int view_id, InitWebView(); - dispatcher_ = std::make_unique(); + dispatcher_ = std::make_shared(); webview_channel_ = std::make_unique( GetPluginRegistrar()->messenger(), GetWebViewChannelName(), @@ -153,9 +161,16 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int view_id, flutter::EncodableMap args = { {flutter::EncodableValue("url"), flutter::EncodableValue(url)}}; - dispatcher_->dispatchTaskOnMainThread([this, args]() { + dispatcher_->dispatchTaskOnMainThread([this, args, + alive = is_alive_]() { + if (!*alive) return; navigation_delegate_channel_->InvokeMethod( "onPageStarted", std::make_unique(args)); + // The lightweight web engine has no dedicated URL-change + // callback, so report a URL change whenever a navigation + // starts. + navigation_delegate_channel_->InvokeMethod( + "onUrlChange", std::make_unique(args)); }); }); webview_instance_->RegisterOnPageLoadedHandler( @@ -163,18 +178,22 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int view_id, flutter::EncodableMap args = { {flutter::EncodableValue("url"), flutter::EncodableValue(url)}}; - dispatcher_->dispatchTaskOnMainThread([this, args]() { - navigation_delegate_channel_->InvokeMethod( - "onPageFinished", - std::make_unique(args)); - }); + dispatcher_->dispatchTaskOnMainThread( + [this, args, alive = is_alive_]() { + if (!*alive) return; + navigation_delegate_channel_->InvokeMethod( + "onPageFinished", + std::make_unique(args)); + }); }); webview_instance_->RegisterOnProgressChangedHandler( [this](LWE::WebContainer* container, int progress) { flutter::EncodableMap args = {{flutter::EncodableValue("progress"), flutter::EncodableValue(progress)}}; - dispatcher_->dispatchTaskOnMainThread([this, args]() { + dispatcher_->dispatchTaskOnMainThread([this, args, + alive = is_alive_]() { + if (!*alive) return; navigation_delegate_channel_->InvokeMethod( "onProgress", std::make_unique(args)); }); @@ -189,11 +208,13 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int view_id, {flutter::EncodableValue("failingUrl"), flutter::EncodableValue(error.GetUrl())}, }; - dispatcher_->dispatchTaskOnMainThread([this, args]() { - navigation_delegate_channel_->InvokeMethod( - "onWebResourceError", - std::make_unique(args)); - }); + dispatcher_->dispatchTaskOnMainThread( + [this, args, alive = is_alive_]() { + if (!*alive) return; + navigation_delegate_channel_->InvokeMethod( + "onWebResourceError", + std::make_unique(args)); + }); }); webview_instance_->RegisterShouldOverrideUrlLoadingHandler( [this](LWE::WebContainer* view, const std::string& url) -> bool { @@ -206,13 +227,16 @@ WebView::WebView(flutter::PluginRegistrar* registrar, int view_id, flutter::EncodableValue(true)}, }; - dispatcher_->dispatchTaskOnMainThread([this, args, url]() { - auto result = std::make_unique(url, this); - navigation_delegate_channel_->InvokeMethod( - "navigationRequest", - std::make_unique(args), - std::move(result)); - }); + dispatcher_->dispatchTaskOnMainThread( + [this, args, url, alive = is_alive_]() { + if (!*alive) return; + auto result = + std::make_unique(url, this, alive); + navigation_delegate_channel_->InvokeMethod( + "navigationRequest", + std::make_unique(args), + std::move(result)); + }); return true; }); } @@ -231,7 +255,8 @@ void WebView::RegisterJavaScriptChannelName(const std::string& name) { {flutter::EncodableValue("message"), flutter::EncodableValue(message)}, }; - dispatcher_->dispatchTaskOnMainThread([this, args]() { + dispatcher_->dispatchTaskOnMainThread([this, args, alive = is_alive_]() { + if (!*alive) return; webview_channel_->InvokeMethod( "javaScriptChannelMessage", std::make_unique(args)); @@ -257,12 +282,39 @@ std::string WebView::GetNavigationDelegateChannelName() { } void WebView::Dispose() { - texture_registrar_->UnregisterTexture(GetTextureId(), nullptr); + // Set this first so that dispatcher_ callbacks already queued on the main + // loop bail out instead of touching a destroyed WebView. + *is_alive_ = false; + // Stop the web engine first so its renderer thread stops writing into the + // shared TBM surfaces before anything is torn down. if (webview_instance_) { webview_instance_->Destroy(); webview_instance_ = nullptr; } + + // Detach the buffers under the lock so that the raster thread stops handing + // out buffers that are about to be released. + std::shared_ptr pool; + { + std::lock_guard lock(mutex_); + is_disposing_ = true; + working_surface_ = nullptr; + candidate_surface_ = nullptr; + rendered_surface_ = nullptr; + pool = std::move(tbm_pool_); + } + + // The callback runs on the render thread only after the raster thread is + // done with the TBM surfaces, so the pool is destroyed in a main-thread + // task. dispatcher_ is captured as a shared_ptr copy because the WebView + // may already be destroyed by the time the callback fires. + texture_registrar_->UnregisterTexture( + GetTextureId(), [pool, dispatcher = dispatcher_]() { + dispatcher->dispatchTaskOnMainThread([pool]() { + // The pool destructor frees all TBM surfaces. + }); + }); } void WebView::Resize(double width, double height) { @@ -802,6 +854,9 @@ void WebView::HandleCookieMethodCall(const FlMethodCall& method_call, FlutterDesktopGpuSurfaceDescriptor* WebView::ObtainGpuSurface(size_t width, size_t height) { std::lock_guard lock(mutex_); + if (is_disposing_ || !tbm_pool_) { + return nullptr; + } if (!candidate_surface_) { if (rendered_surface_) { return rendered_surface_->GpuSurface(); diff --git a/packages/webview_flutter_lwe/tizen/src/webview.h b/packages/webview_flutter_lwe/tizen/src/webview.h index eae0a6eab..b14712d1e 100644 --- a/packages/webview_flutter_lwe/tizen/src/webview.h +++ b/packages/webview_flutter_lwe/tizen/src/webview.h @@ -80,7 +80,16 @@ class WebView : public PlatformView { BufferUnit* rendered_surface_ = nullptr; bool is_mouse_lbutton_down_ = false; bool has_navigation_delegate_ = false; - std::unique_ptr dispatcher_; + bool is_disposing_ = false; + // Set to false at the start of Dispose(). Every dispatcher_ callback that + // captures `this` also captures a copy of this shared_ptr, so a callback + // still queued on the main-loop when the WebView is disposed can check it + // and bail out instead of dereferencing an already-destroyed WebView. + std::shared_ptr is_alive_ = std::make_shared(true); + // Shared (not unique) so a pending dispose callback can keep the + // dispatcher alive by holding its own reference after the WebView that + // created it has been destroyed. + std::shared_ptr dispatcher_; std::unique_ptr webview_channel_; std::unique_ptr navigation_delegate_channel_; std::unique_ptr texture_variant_;