From 856a516908b724cfde2f6a50c15418e7bebbd138 Mon Sep 17 00:00:00 2001 From: Maurice Parrish <10687576+bparrishMines@users.noreply.github.com> Date: Thu, 14 Sep 2023 11:29:21 -0400 Subject: [PATCH 1/2] useragent platform implementations --- .../webview_flutter_android/CHANGELOG.md | 6 +++- .../GeneratedAndroidWebView.java | 30 ++++++++++++++++ .../WebSettingsHostApiImpl.java | 7 ++++ .../webviewflutter/WebSettingsTest.java | 8 +++++ .../webview_flutter_test.dart | 15 +------- .../lib/src/android_webview.dart | 5 +++ .../lib/src/android_webview.g.dart | 28 +++++++++++++++ .../lib/src/android_webview_api_impls.dart | 5 +++ .../lib/src/android_webview_controller.dart | 3 ++ .../pigeons/android_webview.dart | 2 ++ .../webview_flutter_android/pubspec.yaml | 4 +-- .../test/android_webview_controller_test.dart | 14 ++++++++ ...android_webview_controller_test.mocks.dart | 33 +++++++++++++++-- ...oid_webview_cookie_manager_test.mocks.dart | 23 ++++++++++-- .../test/android_webview_test.dart | 7 ++++ .../test/android_webview_test.mocks.dart | 8 +++++ .../webview_android_widget_test.mocks.dart | 8 +++++ .../test/test_android_webview.g.dart | 25 +++++++++++++ .../webview_flutter_wkwebview/CHANGELOG.md | 4 +++ .../webview_flutter_test.dart | 29 ++++++++++----- .../ios/RunnerTests/FWFWebViewHostApiTests.m | 21 ++++++++++- .../ios/Classes/FWFGeneratedWebKitApis.h | 9 +++-- .../ios/Classes/FWFGeneratedWebKitApis.m | 35 +++++++++++++++---- .../ios/Classes/FWFWebViewHostApi.m | 16 ++++++--- .../lib/src/common/web_kit.g.dart | 23 ++++++++++++ .../lib/src/web_kit/web_kit.dart | 7 ++++ .../lib/src/web_kit/web_kit_api_impls.dart | 5 +++ .../lib/src/webkit_webview_controller.dart | 11 ++++++ .../pigeons/web_kit.dart | 5 ++- .../webview_flutter_wkwebview/pubspec.yaml | 4 +-- .../web_kit_cookie_manager_test.mocks.dart | 4 ++- .../web_kit_webview_widget_test.mocks.dart | 22 +++++++++++- .../test/src/common/test_web_kit.g.dart | 25 +++++++++++++ .../src/foundation/foundation_test.mocks.dart | 4 ++- .../test/src/ui_kit/ui_kit_test.mocks.dart | 10 +++++- .../test/src/web_kit/web_kit_test.dart | 10 +++++- .../test/src/web_kit/web_kit_test.mocks.dart | 10 +++++- .../test/webkit_webview_controller_test.dart | 15 ++++++++ .../webkit_webview_controller_test.mocks.dart | 12 ++++++- ...kit_webview_cookie_manager_test.mocks.dart | 4 ++- .../webkit_webview_widget_test.mocks.dart | 4 ++- 41 files changed, 465 insertions(+), 55 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index 73d025347971..b24a9aa4b6e1 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.11.0 + +* Adds support for `PlatformWebViewController.getUserAgent`. + ## 3.10.0 * Adds support for playing video in fullscreen. See @@ -19,7 +23,7 @@ ## 3.9.2 * Fixes bug where `PlatformWebViewWidget` doesn't rebuild when the controller or PlatformView - implementation flag changes. + implementation flag changes. ## 3.9.1 diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index 567e201b859c..8f19f5e15f87 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -1604,6 +1604,9 @@ public interface WebSettingsHostApi { void setTextZoom(@NonNull Long instanceId, @NonNull Long textZoom); + @NonNull + String getUserAgentString(@NonNull Long instanceId); + /** The codec used by WebSettingsHostApi. */ static @NonNull MessageCodec getCodec() { return new StandardMessageCodec(); @@ -1993,6 +1996,33 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable WebSetting channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.webview_flutter_android.WebSettingsHostApi.getUserAgentString", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + try { + String output = + api.getUserAgentString( + (instanceIdArg == null) ? null : instanceIdArg.longValue()); + wrapped.add(0, output); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } } } /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java index 3a6b151fa711..8eac2ed6a0c5 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java @@ -132,4 +132,11 @@ public void setTextZoom(@NonNull Long instanceId, @NonNull Long textZoom) { final WebSettings webSettings = Objects.requireNonNull(instanceManager.getInstance(instanceId)); webSettings.setTextZoom(textZoom.intValue()); } + + @NonNull + @Override + public String getUserAgentString(@NonNull Long instanceId) { + final WebSettings webSettings = Objects.requireNonNull(instanceManager.getInstance(instanceId)); + return webSettings.getUserAgentString(); + } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java index 4a2997669885..47d98ecce4f0 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java @@ -4,6 +4,7 @@ package io.flutter.plugins.webviewflutter; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -117,4 +118,11 @@ public void setTextZoom() { testHostApiImpl.setTextZoom(0L, 100L); verify(mockWebSettings).setTextZoom(100); } + + @Test + public void getUserAgentString() { + final String userAgent = "str"; + when(mockWebSettings.getUserAgentString()).thenReturn(userAgent); + assertEquals(testHostApiImpl.getUserAgentString(0L), userAgent); + } } diff --git a/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart index 0e805dd2aef4..a42ba65ab613 100644 --- a/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart @@ -342,7 +342,7 @@ Future main() async { await pageFinished.future; - final String customUserAgent = await _getUserAgent(controller); + final String? customUserAgent = await controller.getUserAgent(); expect(customUserAgent, 'Custom_User_Agent1'); }); @@ -1312,19 +1312,6 @@ Future main() async { ); } -/// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests. -Future _getUserAgent(PlatformWebViewController controller) async { - return _runJavaScriptReturningResult(controller, 'navigator.userAgent;'); -} - -Future _runJavaScriptReturningResult( - PlatformWebViewController controller, - String js, -) async { - return jsonDecode(await controller.runJavaScriptReturningResult(js) as String) - as String; -} - class ResizableWebView extends StatefulWidget { const ResizableWebView({ super.key, diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index 5ed2fc0351ef..611809f1c095 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -694,6 +694,11 @@ class WebSettings extends JavaObject { return api.setSetTextZoomFromInstance(this, textZoom); } + /// Gets the WebView's user-agent string. + Future getUserAgentString() { + return api.getUserAgentStringFromInstance(this); + } + @override WebSettings copy() { return WebSettings.detached( diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart index 99e1e7f4e104..c43171cc8918 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart @@ -1424,6 +1424,34 @@ class WebSettingsHostApi { return; } } + + Future getUserAgentString(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.webview_flutter_android.WebSettingsHostApi.getUserAgentString', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_instanceId]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as String?)!; + } + } } class JavaScriptChannelHostApi { diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index 2c773fd9e190..4f764517781a 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -552,6 +552,11 @@ class WebSettingsHostApiImpl extends WebSettingsHostApi { enabled, ); } + + /// Helper method to convert instances ids to objects. + Future getUserAgentStringFromInstance(WebSettings instance) { + return getUserAgentString(instanceManager.getIdentifier(instance)!); + } } /// Host api implementation for [JavaScriptChannel]. diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart index bc1da74bf952..c54bf051b443 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart @@ -566,6 +566,9 @@ class AndroidWebViewController extends PlatformWebViewController { _onShowCustomWidgetCallback = onShowCustomWidget; _onHideCustomWidgetCallback = onHideCustomWidget; } + + @override + Future getUserAgent() => _webView.settings.getUserAgentString(); } /// Android implementation of [PlatformWebViewPermissionRequest]. diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart index c19a2b226b0d..21896abba7a1 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -253,6 +253,8 @@ abstract class WebSettingsHostApi { void setAllowFileAccess(int instanceId, bool enabled); void setTextZoom(int instanceId, int textZoom); + + String getUserAgentString(int instanceId); } @HostApi(dartHostTestHandler: 'TestJavaScriptChannelHostApi') diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 6b4942ae204d..8242abd17f05 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_android description: A Flutter plugin that provides a WebView widget on Android. repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 3.10.0 +version: 3.11.0 environment: sdk: ">=2.19.0 <4.0.0" @@ -20,7 +20,7 @@ flutter: dependencies: flutter: sdk: flutter - webview_flutter_platform_interface: ^2.4.0 + webview_flutter_platform_interface: ^2.6.0 dev_dependencies: build_runner: ^2.1.4 diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart index c350be64f2cf..51aa4df7246e 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart @@ -1150,6 +1150,20 @@ void main() { verify(mockWebView.settings).called(1); verify(mockSettings.setUserAgentString('Test Framework')).called(1); }); + + test('getUserAgent', () async { + final MockWebSettings mockSettings = MockWebSettings(); + final AndroidWebViewController controller = createControllerWithMocks( + mockSettings: mockSettings, + ); + + const String userAgent = 'str'; + + when(mockSettings.getUserAgentString()) + .thenAnswer((_) => Future.value(userAgent)); + + expect(await controller.getUserAgent(), userAgent); + }); }); test('setMediaPlaybackRequiresUserGesture', () async { diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.mocks.dart index b6d6e2c574a8..ccfeef7f4eb5 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.mocks.dart @@ -739,8 +739,8 @@ class MockAndroidWebViewController extends _i1.Mock ) as _i9.Future); @override _i9.Future setCustomWidgetCallbacks({ - _i8.OnShowCustomWidgetCallback? onShowCustomWidget, - _i8.OnHideCustomWidgetCallback? onHideCustomWidget, + required _i8.OnShowCustomWidgetCallback? onShowCustomWidget, + required _i8.OnHideCustomWidgetCallback? onHideCustomWidget, }) => (super.noSuchMethod( Invocation.method( @@ -754,6 +754,26 @@ class MockAndroidWebViewController extends _i1.Mock returnValue: _i9.Future.value(), returnValueForMissingStub: _i9.Future.value(), ) as _i9.Future); + @override + _i9.Future getUserAgent() => (super.noSuchMethod( + Invocation.method( + #getUserAgent, + [], + ), + returnValue: _i9.Future.value(), + returnValueForMissingStub: _i9.Future.value(), + ) as _i9.Future); + @override + _i9.Future setOnConsoleMessage( + void Function(_i3.JavaScriptConsoleMessage)? onConsoleMessage) => + (super.noSuchMethod( + Invocation.method( + #setOnConsoleMessage, + [onConsoleMessage], + ), + returnValue: _i9.Future.value(), + returnValueForMissingStub: _i9.Future.value(), + ) as _i9.Future); } /// A class which mocks [AndroidWebViewProxy]. @@ -1929,6 +1949,15 @@ class MockWebSettings extends _i1.Mock implements _i2.WebSettings { returnValueForMissingStub: _i9.Future.value(), ) as _i9.Future); @override + _i9.Future getUserAgentString() => (super.noSuchMethod( + Invocation.method( + #getUserAgentString, + [], + ), + returnValue: _i9.Future.value(''), + returnValueForMissingStub: _i9.Future.value(''), + ) as _i9.Future); + @override _i2.WebSettings copy() => (super.noSuchMethod( Invocation.method( #copy, diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.mocks.dart index b23bcaa24a2a..5df5cf214696 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.mocks.dart @@ -475,8 +475,8 @@ class MockAndroidWebViewController extends _i1.Mock ) as _i5.Future); @override _i5.Future setCustomWidgetCallbacks({ - _i6.OnShowCustomWidgetCallback? onShowCustomWidget, - _i6.OnHideCustomWidgetCallback? onHideCustomWidget, + required _i6.OnShowCustomWidgetCallback? onShowCustomWidget, + required _i6.OnHideCustomWidgetCallback? onHideCustomWidget, }) => (super.noSuchMethod( Invocation.method( @@ -490,6 +490,25 @@ class MockAndroidWebViewController extends _i1.Mock returnValue: _i5.Future.value(), returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); + @override + _i5.Future getUserAgent() => (super.noSuchMethod( + Invocation.method( + #getUserAgent, + [], + ), + returnValue: _i5.Future.value(), + ) as _i5.Future); + @override + _i5.Future setOnConsoleMessage( + void Function(_i3.JavaScriptConsoleMessage)? onConsoleMessage) => + (super.noSuchMethod( + Invocation.method( + #setOnConsoleMessage, + [onConsoleMessage], + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); } /// A class which mocks [TestInstanceManagerHostApi]. diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart index da03052c7f22..12cac3f7cae9 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart @@ -528,6 +528,13 @@ void main() { 100, )); }); + + test('getUserAgentString', () async { + const String userAgent = 'str'; + when(mockPlatformHostApi.getUserAgentString(webSettingsInstanceId)) + .thenReturn(userAgent); + expect(await webSettings.getUserAgentString(), userAgent); + }); }); group('JavaScriptChannel', () { diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart index fecf8140a114..7ae7c00588b6 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart @@ -701,6 +701,14 @@ class MockTestWebSettingsHostApi extends _i1.Mock ), returnValueForMissingStub: null, ); + @override + String getUserAgentString(int? instanceId) => (super.noSuchMethod( + Invocation.method( + #getUserAgentString, + [instanceId], + ), + returnValue: '', + ) as String); } /// A class which mocks [TestWebStorageHostApi]. diff --git a/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.mocks.dart index c52703812fe6..ff849020d18d 100644 --- a/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.mocks.dart @@ -280,6 +280,14 @@ class MockWebSettings extends _i1.Mock implements _i2.WebSettings { returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); @override + _i5.Future getUserAgentString() => (super.noSuchMethod( + Invocation.method( + #getUserAgentString, + [], + ), + returnValue: _i5.Future.value(''), + ) as _i5.Future); + @override _i2.WebSettings copy() => (super.noSuchMethod( Invocation.method( #copy, diff --git a/packages/webview_flutter/webview_flutter_android/test/test_android_webview.g.dart b/packages/webview_flutter/webview_flutter_android/test/test_android_webview.g.dart index b88ea8a8c2dd..4aa694f31629 100644 --- a/packages/webview_flutter/webview_flutter_android/test/test_android_webview.g.dart +++ b/packages/webview_flutter/webview_flutter_android/test/test_android_webview.g.dart @@ -999,6 +999,8 @@ abstract class TestWebSettingsHostApi { void setTextZoom(int instanceId, int textZoom); + String getUserAgentString(int instanceId); + static void setup(TestWebSettingsHostApi? api, {BinaryMessenger? binaryMessenger}) { { @@ -1365,6 +1367,29 @@ abstract class TestWebSettingsHostApi { }); } } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.webview_flutter_android.WebSettingsHostApi.getUserAgentString', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.webview_flutter_android.WebSettingsHostApi.getUserAgentString was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = (args[0] as int?); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.webview_flutter_android.WebSettingsHostApi.getUserAgentString was null, expected non-null int.'); + final String output = api.getUserAgentString(arg_instanceId!); + return [output]; + }); + } + } } } diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index 384b16b06536..7bee9043e72c 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.8.0 + +* Adds support for `PlatformWebViewController.getUserAgent`. + ## 3.7.4 * Adds pub topics to package metadata. diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart index 66567accda36..ba6b4ea40674 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart @@ -292,8 +292,27 @@ Future main() async { }, )); - final String customUserAgent2 = await _getUserAgent(controller); - expect(customUserAgent2, 'Custom_User_Agent1'); + final String? customUserAgent = await controller.getUserAgent(); + expect(customUserAgent, 'Custom_User_Agent1'); + }); + + testWidgets( + 'getUserAgent returns a default value when custom value is not set', + (WidgetTester tester) async { + final PlatformWebViewController controller = PlatformWebViewController( + const PlatformWebViewControllerCreationParams(), + ); + + await tester.pumpWidget(Builder( + builder: (BuildContext context) { + return PlatformWebViewWidget( + PlatformWebViewWidgetCreationParams(controller: controller), + ).build(context); + }, + )); + + final String? userAgent = await controller.getUserAgent(); + expect(userAgent, isNotNull); }); group('Video playback policy', () { @@ -1198,12 +1217,6 @@ Future main() async { ); } -/// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests. -Future _getUserAgent(PlatformWebViewController controller) async { - return await controller.runJavaScriptReturningResult('navigator.userAgent;') - as String; -} - class ResizableWebView extends StatefulWidget { const ResizableWebView({ super.key, diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFWebViewHostApiTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFWebViewHostApiTests.m index a89bf338c3fe..a46c20f0df8e 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFWebViewHostApiTests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFWebViewHostApiTests.m @@ -88,7 +88,7 @@ - (void)testSetCustomUserAgent { instanceManager:instanceManager]; FlutterError *error; - [hostAPI setUserAgentForWebViewWithIdentifier:@0 userAgent:@"userA" error:&error]; + [hostAPI setCustomUserAgentForWebViewWithIdentifier:@0 userAgent:@"userA" error:&error]; OCMVerify([mockWebView setCustomUserAgent:@"userA"]); XCTAssertNil(error); } @@ -480,4 +480,23 @@ - (void)testSetInspectable API_AVAILABLE(ios(16.4), macos(13.3)) { OCMVerify([mockWebView setInspectable:YES]); XCTAssertNil(error); } + +- (void)testCustomUserAgent { + FWFWebView *mockWebView = OCMClassMock([FWFWebView class]); + + NSString *userAgent = @"str"; + OCMStub([mockWebView customUserAgent]).andReturn(userAgent); + + FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init]; + [instanceManager addDartCreatedInstance:mockWebView withIdentifier:0]; + + FWFWebViewHostApiImpl *hostAPI = [[FWFWebViewHostApiImpl alloc] + initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger)) + instanceManager:instanceManager]; + + FlutterError *error; + XCTAssertEqualObjects([hostAPI customUserAgentForWebViewWithIdentifier:@0 error:&error], + userAgent); + XCTAssertNil(error); +} @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h index 5158dcd9689c..11c49d24b541 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h @@ -744,9 +744,9 @@ NSObject *FWFWKWebViewHostApiGetCodec(void); - (void)setAllowsBackForwardForWebViewWithIdentifier:(NSNumber *)identifier isAllowed:(NSNumber *)allow error:(FlutterError *_Nullable *_Nonnull)error; -- (void)setUserAgentForWebViewWithIdentifier:(NSNumber *)identifier - userAgent:(nullable NSString *)userAgent - error:(FlutterError *_Nullable *_Nonnull)error; +- (void)setCustomUserAgentForWebViewWithIdentifier:(NSNumber *)identifier + userAgent:(nullable NSString *)userAgent + error:(FlutterError *_Nullable *_Nonnull)error; - (void)evaluateJavaScriptForWebViewWithIdentifier:(NSNumber *)identifier javaScriptString:(NSString *)javaScriptString completion:(void (^)(id _Nullable, @@ -754,6 +754,9 @@ NSObject *FWFWKWebViewHostApiGetCodec(void); - (void)setInspectableForWebViewWithIdentifier:(NSNumber *)identifier inspectable:(NSNumber *)inspectable error:(FlutterError *_Nullable *_Nonnull)error; +- (nullable NSString *)customUserAgentForWebViewWithIdentifier:(NSNumber *)identifier + error:(FlutterError *_Nullable *_Nonnull) + error; @end extern void FWFWKWebViewHostApiSetup(id binaryMessenger, diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m index d8d4e2972eeb..cc58067418e9 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m @@ -2466,19 +2466,19 @@ void FWFWKWebViewHostApiSetup(id binaryMessenger, binaryMessenger:binaryMessenger codec:FWFWKWebViewHostApiGetCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(setUserAgentForWebViewWithIdentifier: - userAgent:error:)], + NSCAssert([api respondsToSelector:@selector + (setCustomUserAgentForWebViewWithIdentifier:userAgent:error:)], @"FWFWKWebViewHostApi api (%@) doesn't respond to " - @"@selector(setUserAgentForWebViewWithIdentifier:userAgent:error:)", + @"@selector(setCustomUserAgentForWebViewWithIdentifier:userAgent:error:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; NSNumber *arg_identifier = GetNullableObjectAtIndex(args, 0); NSString *arg_userAgent = GetNullableObjectAtIndex(args, 1); FlutterError *error; - [api setUserAgentForWebViewWithIdentifier:arg_identifier - userAgent:arg_userAgent - error:&error]; + [api setCustomUserAgentForWebViewWithIdentifier:arg_identifier + userAgent:arg_userAgent + error:&error]; callback(wrapResult(nil, error)); }]; } else { @@ -2539,6 +2539,29 @@ void FWFWKWebViewHostApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + @"dev.flutter.pigeon.webview_flutter_wkwebview.WKWebViewHostApi.getCustomUserAgent" + binaryMessenger:binaryMessenger + codec:FWFWKWebViewHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(customUserAgentForWebViewWithIdentifier:error:)], + @"FWFWKWebViewHostApi api (%@) doesn't respond to " + @"@selector(customUserAgentForWebViewWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSNumber *arg_identifier = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSString *output = [api customUserAgentForWebViewWithIdentifier:arg_identifier + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } } NSObject *FWFWKUIDelegateHostApiGetCodec(void) { static FlutterStandardMessageCodec *sSharedObject = nil; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFWebViewHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFWebViewHostApi.m index 924b9bba4bca..eb30b773d1f2 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFWebViewHostApi.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFWebViewHostApi.m @@ -134,10 +134,11 @@ - (void)loadRequestForWebViewWithIdentifier:(nonnull NSNumber *)identifier [[self webViewForIdentifier:identifier] loadRequest:urlRequest]; } -- (void)setUserAgentForWebViewWithIdentifier:(nonnull NSNumber *)identifier - userAgent:(nullable NSString *)userAgent - error:(FlutterError *_Nullable __autoreleasing *_Nonnull) - error { +- (void)setCustomUserAgentForWebViewWithIdentifier:(nonnull NSNumber *)identifier + userAgent:(nullable NSString *)userAgent + error: + (FlutterError *_Nullable __autoreleasing *_Nonnull) + error { [[self webViewForIdentifier:identifier] setCustomUserAgent:userAgent]; } @@ -299,4 +300,11 @@ - (void)setUIDelegateForWebViewWithIdentifier:(nonnull NSNumber *)identifier error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { return [[self webViewForIdentifier:identifier] title]; } + +- (nullable NSString *) + customUserAgentForWebViewWithIdentifier:(nonnull NSNumber *)identifier + error: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return [[self webViewForIdentifier:identifier] customUserAgent]; +} @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart index 25649a01099f..b0eaadeb739f 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart @@ -2584,6 +2584,29 @@ class WKWebViewHostApi { return; } } + + Future getCustomUserAgent(int arg_identifier) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.webview_flutter_wkwebview.WKWebViewHostApi.getCustomUserAgent', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_identifier]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return (replyList[0] as String?); + } + } } /// Mirror of WKUIDelegate. diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart index 714739c7a6f5..db9f41c28519 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart @@ -1125,6 +1125,13 @@ class WKWebView extends UIView { ); } + /// The custom user agent string. + /// + /// Represents [WKWebView.customUserAgent](https://developer.apple.com/documentation/webkit/wkwebview/1414950-customuseragent?language=objc). + Future getCustomUserAgent() { + return _webViewApi.getCustomUserAgentForInstances(this); + } + @override WKWebView copy() { return WKWebView.detached( diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart index ccc87377cb04..ee545d45b718 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart @@ -1078,6 +1078,11 @@ class WKWebViewHostApiImpl extends WKWebViewHostApi { ); } + /// Calls [getCustomUserAgent] with the ids of the provided object instances. + Future getCustomUserAgentForInstances(WKWebView instance) { + return getCustomUserAgent(instanceManager.getIdentifier(instance)!); + } + /// Calls [setNavigationDelegate] with the ids of the provided object instances. Future setNavigationDelegateForInstances( WKWebView instance, 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 764ed11d6aa8..4a682148da93 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 @@ -558,6 +558,17 @@ class WebKitWebViewController extends PlatformWebViewController { Future setInspectable(bool inspectable) { return _webView.setInspectable(inspectable); } + + @override + Future getUserAgent() async { + final String? customUserAgent = await _webView.getCustomUserAgent(); + if (customUserAgent != null) { + return customUserAgent; + } + + return (await _webView.evaluateJavaScript('navigator.userAgent;') + as String?)!; + } } /// An implementation of [JavaScriptChannelParams] with the WebKit api. diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart b/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart index dea5080e556a..8e9e16ff425d 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart @@ -688,7 +688,7 @@ abstract class WKWebViewHostApi { @ObjCSelector('setAllowsBackForwardForWebViewWithIdentifier:isAllowed:') void setAllowsBackForwardNavigationGestures(int identifier, bool allow); - @ObjCSelector('setUserAgentForWebViewWithIdentifier:userAgent:') + @ObjCSelector('setCustomUserAgentForWebViewWithIdentifier:userAgent:') void setCustomUserAgent(int identifier, String? userAgent); @ObjCSelector('evaluateJavaScriptForWebViewWithIdentifier:javaScriptString:') @@ -697,6 +697,9 @@ abstract class WKWebViewHostApi { @ObjCSelector('setInspectableForWebViewWithIdentifier:inspectable:') void setInspectable(int identifier, bool inspectable); + + @ObjCSelector('customUserAgentForWebViewWithIdentifier:') + String? getCustomUserAgent(int identifier); } /// Mirror of WKUIDelegate. diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index 2c888669fa10..5f99bc9d25fa 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.7.4 +version: 3.8.0 environment: sdk: ">=2.19.0 <4.0.0" @@ -20,7 +20,7 @@ dependencies: flutter: sdk: flutter path: ^1.8.0 - webview_flutter_platform_interface: ^2.4.0 + webview_flutter_platform_interface: ^2.6.0 dev_dependencies: build_runner: ^2.1.5 diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.mocks.dart index b88d686b205d..5d0eede3b0ec 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.mocks.dart @@ -1,7 +1,9 @@ -// Mocks generated by Mockito 5.4.0 from annotations +// Mocks generated by Mockito 5.4.1 from annotations // in webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.dart. // Do not manually edit this file. +// @dart=2.19 + // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i3; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.mocks.dart index 3c4210e8419b..8de47910fef3 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.mocks.dart @@ -1,7 +1,9 @@ -// Mocks generated by Mockito 5.4.0 from annotations +// Mocks generated by Mockito 5.4.1 from annotations // in webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart. // Do not manually edit this file. +// @dart=2.19 + // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i5; import 'dart:math' as _i2; @@ -650,6 +652,14 @@ class MockWKWebView extends _i1.Mock implements _i4.WKWebView { returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); @override + _i5.Future getCustomUserAgent() => (super.noSuchMethod( + Invocation.method( + #getCustomUserAgent, + [], + ), + returnValue: _i5.Future.value(), + ) as _i5.Future); + @override _i4.WKWebView copy() => (super.noSuchMethod( Invocation.method( #copy, @@ -760,6 +770,16 @@ class MockWKWebViewConfiguration extends _i1.Mock returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); @override + _i5.Future setLimitsNavigationsToAppBoundDomains(bool? limit) => + (super.noSuchMethod( + Invocation.method( + #setLimitsNavigationsToAppBoundDomains, + [limit], + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); + @override _i5.Future setMediaTypesRequiringUserActionForPlayback( Set<_i4.WKAudiovisualMediaType>? types) => (super.noSuchMethod( diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart index ee9065ea6689..03e5b6cbca5e 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart @@ -1160,6 +1160,8 @@ abstract class TestWKWebViewHostApi { void setInspectable(int identifier, bool inspectable); + String? getCustomUserAgent(int identifier); + static void setup(TestWKWebViewHostApi? api, {BinaryMessenger? binaryMessenger}) { { @@ -1633,6 +1635,29 @@ abstract class TestWKWebViewHostApi { }); } } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.webview_flutter_wkwebview.WKWebViewHostApi.getCustomUserAgent', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKWebViewHostApi.getCustomUserAgent was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKWebViewHostApi.getCustomUserAgent was null, expected non-null int.'); + final String? output = api.getCustomUserAgent(arg_identifier!); + return [output]; + }); + } + } } } diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart index a648fc65a4dc..60cb608302b2 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart @@ -1,7 +1,9 @@ -// Mocks generated by Mockito 5.4.0 from annotations +// Mocks generated by Mockito 5.4.1 from annotations // in webview_flutter_wkwebview/test/src/foundation/foundation_test.dart. // Do not manually edit this file. +// @dart=2.19 + // ignore_for_file: no_leading_underscores_for_library_prefixes import 'package:mockito/mockito.dart' as _i1; import 'package:webview_flutter_wkwebview/src/common/web_kit.g.dart' as _i3; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/ui_kit/ui_kit_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/ui_kit/ui_kit_test.mocks.dart index 65fdc41b275f..81ef6a8ca9d6 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/ui_kit/ui_kit_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/ui_kit/ui_kit_test.mocks.dart @@ -1,7 +1,9 @@ -// Mocks generated by Mockito 5.4.0 from annotations +// Mocks generated by Mockito 5.4.1 from annotations // in webview_flutter_wkwebview/test/src/ui_kit/ui_kit_test.dart. // Do not manually edit this file. +// @dart=2.19 + // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i4; @@ -336,6 +338,12 @@ class MockTestWKWebViewHostApi extends _i1.Mock ), returnValueForMissingStub: null, ); + @override + String? getCustomUserAgent(int? identifier) => + (super.noSuchMethod(Invocation.method( + #getCustomUserAgent, + [identifier], + )) as String?); } /// A class which mocks [TestUIScrollViewHostApi]. diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart index 055f342ab786..98a70de7b328 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart @@ -833,7 +833,7 @@ void main() { )); }); - test('customUserAgent', () { + test('setCustomUserAgent', () { webView.setCustomUserAgent('hello'); verify(mockPlatformHostApi.setCustomUserAgent( webViewInstanceId, @@ -841,6 +841,14 @@ void main() { )); }); + test('getCustomUserAgent', () { + const String userAgent = 'str'; + when( + mockPlatformHostApi.getCustomUserAgent(webViewInstanceId), + ).thenReturn(userAgent); + expect(webView.getCustomUserAgent(), completion(userAgent)); + }); + test('evaluateJavaScript', () { when(mockPlatformHostApi.evaluateJavaScript(webViewInstanceId, 'gogo')) .thenAnswer((_) => Future.value('stopstop')); diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.mocks.dart index e92132bdeb24..2343af2f17ff 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.mocks.dart @@ -1,7 +1,9 @@ -// Mocks generated by Mockito 5.4.0 from annotations +// Mocks generated by Mockito 5.4.1 from annotations // in webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart. // Do not manually edit this file. +// @dart=2.19 + // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i3; @@ -565,6 +567,12 @@ class MockTestWKWebViewHostApi extends _i1.Mock ), returnValueForMissingStub: null, ); + @override + String? getCustomUserAgent(int? identifier) => + (super.noSuchMethod(Invocation.method( + #getCustomUserAgent, + [identifier], + )) as String?); } /// A class which mocks [TestWKWebsiteDataStoreHostApi]. 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 2cd20e0f6889..fcfa4c4b620c 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 @@ -823,6 +823,21 @@ void main() { ); }); + test('getUserAgent', () { + final MockWKWebView mockWebView = MockWKWebView(); + + final WebKitWebViewController controller = createControllerWithMocks( + createMockWebView: (_, {dynamic observeValue}) => mockWebView, + ); + + const String userAgent = 'str'; + + when(mockWebView.getCustomUserAgent()).thenAnswer( + (_) => Future.value(userAgent), + ); + expect(controller.getUserAgent(), completion(userAgent)); + }); + test('setPlatformNavigationDelegate', () { final MockWKWebView mockWebView = MockWKWebView(); diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.mocks.dart index 84f1587f45a3..7dd1917612e3 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.mocks.dart @@ -1,7 +1,9 @@ -// Mocks generated by Mockito 5.4.0 from annotations +// Mocks generated by Mockito 5.4.1 from annotations // in webview_flutter_wkwebview/test/webkit_webview_controller_test.dart. // Do not manually edit this file. +// @dart=2.19 + // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i6; import 'dart:math' as _i3; @@ -747,6 +749,14 @@ class MockWKWebView extends _i1.Mock implements _i5.WKWebView { returnValueForMissingStub: _i6.Future.value(), ) as _i6.Future); @override + _i6.Future getCustomUserAgent() => (super.noSuchMethod( + Invocation.method( + #getCustomUserAgent, + [], + ), + returnValue: _i6.Future.value(), + ) as _i6.Future); + @override _i5.WKWebView copy() => (super.noSuchMethod( Invocation.method( #copy, diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.mocks.dart index 95818c3cefae..042631982cf5 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.mocks.dart @@ -1,7 +1,9 @@ -// Mocks generated by Mockito 5.4.0 from annotations +// Mocks generated by Mockito 5.4.1 from annotations // in webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.dart. // Do not manually edit this file. +// @dart=2.19 + // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i3; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.mocks.dart index b171e28a3bfb..8d104c1ed79d 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.mocks.dart @@ -1,7 +1,9 @@ -// Mocks generated by Mockito 5.4.0 from annotations +// Mocks generated by Mockito 5.4.1 from annotations // in webview_flutter_wkwebview/test/webkit_webview_widget_test.dart. // Do not manually edit this file. +// @dart=2.19 + // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i3; From 09df0db9a9f9da2e0d9979768d0ecc062fb63c5e Mon Sep 17 00:00:00 2001 From: Maurice Parrish <10687576+bparrishMines@users.noreply.github.com> Date: Fri, 22 Sep 2023 17:50:13 -0400 Subject: [PATCH 2/2] fix pubspec version --- .../webview_flutter/webview_flutter_wkwebview/CHANGELOG.md | 3 +-- .../webview_flutter/webview_flutter_wkwebview/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index d691215162a9..0b0101494c28 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -4,8 +4,7 @@ ## 3.8.0 -* Adds support to register a callback to receive JavaScript console messages. See - `WebKitWebViewController.setOnConsoleMessage`. +* Adds support to register a callback to receive JavaScript console messages. See `WebKitWebViewController.setOnConsoleMessage`. ## 3.7.4 diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index 5f99bc9d25fa..685c96ec6999 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.8.0 +version: 3.9.0 environment: sdk: ">=2.19.0 <4.0.0"