diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index 7b74c5e0f9e..11e10486544 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.16.3 + +* Fixes re-registering existing channels while removing Javascript channels. + ## 3.16.2 * Updates README to remove contributor-focused documentation. diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart index a1f149ecdd1..ae254ef52fe 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart @@ -742,12 +742,16 @@ window.addEventListener("error", function(e) { _javaScriptChannelParams.keys.forEach( _webView.configuration.userContentController.removeScriptMessageHandler, ); - - _javaScriptChannelParams.remove(removedJavaScriptChannel); + final Map remainingChannelParams = + Map.from( + _javaScriptChannelParams, + ); + remainingChannelParams.remove(removedJavaScriptChannel); + _javaScriptChannelParams.clear(); await Future.wait(>[ for (final JavaScriptChannelParams params - in _javaScriptChannelParams.values) + in remainingChannelParams.values) addJavaScriptChannel(params), // Zoom is disabled with a WKUserScript, so this adds it back if it was // removed above. diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index 658c46071e7..735efa3f86e 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_wkwebview description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control. repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_wkwebview issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 3.16.2 +version: 3.16.3 environment: sdk: ^3.5.0 diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart index d7aab4b5426..4e1208641e8 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart @@ -860,6 +860,72 @@ void main() { verifyNoMoreInteractions(mockUserContentController); }); + test('removeJavaScriptChannel multiple times', () async { + final WebKitProxy webKitProxy = WebKitProxy( + createScriptMessageHandler: ({ + required void Function( + WKUserContentController userContentController, + WKScriptMessage message, + ) didReceiveScriptMessage, + }) { + return WKScriptMessageHandler.detached( + didReceiveScriptMessage: didReceiveScriptMessage, + ); + }, + ); + + final WebKitJavaScriptChannelParams javaScriptChannelParams1 = + WebKitJavaScriptChannelParams( + name: 'name1', + onMessageReceived: (JavaScriptMessage message) {}, + webKitProxy: webKitProxy, + ); + + final WebKitJavaScriptChannelParams javaScriptChannelParams2 = + WebKitJavaScriptChannelParams( + name: 'name2', + onMessageReceived: (JavaScriptMessage message) {}, + webKitProxy: webKitProxy, + ); + + final MockWKUserContentController mockUserContentController = + MockWKUserContentController(); + + final WebKitWebViewController controller = createControllerWithMocks( + mockUserContentController: mockUserContentController, + ); + + await controller.addJavaScriptChannel(javaScriptChannelParams1); + await controller.addJavaScriptChannel(javaScriptChannelParams2); + reset(mockUserContentController); + + await controller.removeJavaScriptChannel('name1'); + + verify(mockUserContentController.removeAllUserScripts()); + verify(mockUserContentController.removeScriptMessageHandler('name1')); + verify(mockUserContentController.removeScriptMessageHandler('name2')); + + verify(mockUserContentController.addScriptMessageHandler( + argThat(isA()), + 'name2', + )); + + final WKUserScript userScript = + verify(mockUserContentController.addUserScript(captureAny)) + .captured + .single as WKUserScript; + expect(userScript.source, 'window.name2 = webkit.messageHandlers.name2;'); + expect( + userScript.injectionTime, + WKUserScriptInjectionTime.atDocumentStart, + ); + + await controller.removeJavaScriptChannel('name2'); + verify(mockUserContentController.removeAllUserScripts()); + verify(mockUserContentController.removeScriptMessageHandler('name2')); + verifyNoMoreInteractions(mockUserContentController); + }); + test('removeJavaScriptChannel with zoom disabled', () async { final WebKitProxy webKitProxy = WebKitProxy( createScriptMessageHandler: ({