diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index 3ece3a82e1df..b464989abeea 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,3 +1,6 @@ +## 4.14.0 +* Adds support for configuring Web Authentication in `AndroidWebViewController` with `setWebAuthenticationSupport` to enable Passkey and other related Authentication. + ## 4.13.0 * Adds new method for accessing a native `WebView` from a `FlutterPluginBinding`. diff --git a/packages/webview_flutter/webview_flutter_android/README.md b/packages/webview_flutter/webview_flutter_android/README.md index 256adfe28002..ca40224b000a 100644 --- a/packages/webview_flutter/webview_flutter_android/README.md +++ b/packages/webview_flutter/webview_flutter_android/README.md @@ -84,6 +84,33 @@ Add intent filters to your AndroidManifest.xml to discover and invoke Android pa ``` +## Enable Web Authentication in WebView + +WebAuthentication (WebAuthn) can be configured by calling +`AndroidWebViewController.setWebAuthenticationSupport` after checking +`AndroidWebViewController.isWebViewFeatureSupported`. + +The WebAuthentication support level can be set to one of three values: +- **[WebAuthenticationSupport.none]**: Disables all WebAuthn requests +- **[WebAuthenticationSupport.forApp]**: Allows WebAuthn for the embedded application (default) +- **[WebAuthenticationSupport.forBrowser]**: Allows WebAuthn for any website (browser-like behavior) + + +```dart +final bool webAuthenticationSupported = await androidController.isWebViewFeatureSupported( + WebViewFeatureType.webAuthentication, +); + +if (webAuthenticationSupported) { + // Enable WebAuthn for the embedded app + await androidController.setWebAuthenticationSupport(WebAuthenticationSupport.forApp); + // Or for browser-like behavior supporting any website: + // await androidController.setWebAuthenticationSupport( + // WebAuthenticationSupport.forBrowser, + // ); +} +``` + ## Fullscreen Video To display a video as fullscreen, an app must manually handle the notification that the current page diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/AndroidWebkitLibrary.g.kt b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/AndroidWebkitLibrary.g.kt index e5b528d49079..651b288a49db 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/AndroidWebkitLibrary.g.kt +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/AndroidWebkitLibrary.g.kt @@ -6826,6 +6826,8 @@ abstract class PigeonApiWebSettingsCompat( ) { abstract fun setPaymentRequestEnabled(webSettings: android.webkit.WebSettings, enabled: Boolean) + abstract fun setWebAuthenticationSupport(webSettings: android.webkit.WebSettings, support: Long) + companion object { @Suppress("LocalVariableName") fun setUpMessageHandlers(binaryMessenger: BinaryMessenger, api: PigeonApiWebSettingsCompat?) { @@ -6854,6 +6856,30 @@ abstract class PigeonApiWebSettingsCompat( channel.setMessageHandler(null) } } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.webview_flutter_android.WebSettingsCompat.setWebAuthenticationSupport", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val webSettingsArg = args[0] as android.webkit.WebSettings + val supportArg = args[1] as Long + val wrapped: List = + try { + api.setWebAuthenticationSupport(webSettingsArg, supportArg) + listOf(null) + } catch (exception: Throwable) { + AndroidWebkitLibraryPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsCompatProxyApi.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsCompatProxyApi.java index 295b61fd4903..fa35c75cc848 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsCompatProxyApi.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsCompatProxyApi.java @@ -29,4 +29,28 @@ public WebSettingsCompatProxyApi(@NonNull ProxyApiRegistrar pigeonRegistrar) { public void setPaymentRequestEnabled(@NonNull WebSettings webSettings, boolean enabled) { WebSettingsCompat.setPaymentRequestEnabled(webSettings, enabled); } + + /** + * This method should only be called if {@link WebViewFeatureProxyApi#isFeatureSupported(String)} + * with WEB_AUTHENTICATION returns true. + * + *

The {@code support} parameter is a {@code long} to accommodate Dart's integer type, but is + * safely converted to {@code int} for the underlying Android API call. {@link + * Math#toIntExact(long)} is used to verify the value fits in the {@code int} range and throw + * {@link ArithmeticException} if it overflows. This is safe because the valid support levels are + * constants (0, 1, 2) that are well within the integer range. + * + *

Note: {@link Math#toIntExact(long)} requires API level 24 or higher. This is compatible with + * this plugin's minimum SDK version. + * + * @param webSettings the WebSettings instance + * @param support the WebAuthentication support level (0, 1, or 2) + * @throws ArithmeticException if {@code support} exceeds {@link Integer#MAX_VALUE} + */ + @SuppressLint("RequiresFeature") + @Override + public void setWebAuthenticationSupport(@NonNull WebSettings webSettings, long support) { + final int supportValue = Math.toIntExact(support); + WebSettingsCompat.setWebAuthenticationSupport(webSettings, supportValue); + } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsCompatTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsCompatTest.java index 2b959c0238cb..f5475dfb8640 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsCompatTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsCompatTest.java @@ -4,6 +4,7 @@ package io.flutter.plugins.webviewflutter; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; @@ -36,4 +37,38 @@ public void setPaymentRequestEnabled() { fail(e.toString()); } } + + @Test + public void setWebAuthenticationSupport() { + final PigeonApiWebSettingsCompat api = + new TestProxyApiRegistrar().getPigeonApiWebSettingsCompat(); + + final WebSettings webSettings = mock(WebSettings.class); + + try (MockedStatic mockedStatic = mockStatic(WebSettingsCompat.class); + MockedStatic mockedWebViewFeature = mockStatic(WebViewFeature.class)) { + mockedWebViewFeature + .when(() -> WebViewFeature.isFeatureSupported(WebViewFeature.WEB_AUTHENTICATION)) + .thenReturn(true); + api.setWebAuthenticationSupport(webSettings, 2L); + mockedStatic.verify(() -> WebSettingsCompat.setWebAuthenticationSupport(webSettings, 2)); + } + } + + @Test + public void setWebAuthenticationSupportWithLongOutsideIntRangeThrows() { + final PigeonApiWebSettingsCompat api = + new TestProxyApiRegistrar().getPigeonApiWebSettingsCompat(); + + final WebSettings webSettings = mock(WebSettings.class); + + try (MockedStatic mockedWebViewFeature = mockStatic(WebViewFeature.class)) { + mockedWebViewFeature + .when(() -> WebViewFeature.isFeatureSupported(WebViewFeature.WEB_AUTHENTICATION)) + .thenReturn(true); + assertThrows( + ArithmeticException.class, + () -> api.setWebAuthenticationSupport(webSettings, Integer.MAX_VALUE + 1L)); + } + } } diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/main.dart b/packages/webview_flutter/webview_flutter_android/example/lib/main.dart index c74b76f8256a..e3ca433ee5ff 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/main.dart @@ -329,6 +329,7 @@ enum MenuOptions { videoExample, logExample, basicAuthentication, + webAuthentication, javaScriptAlert, viewportMeta, } @@ -383,6 +384,8 @@ class SampleMenu extends StatelessWidget { _onLogExample(); case MenuOptions.basicAuthentication: _promptForUrl(context); + case MenuOptions.webAuthentication: + _onWebAuthenticationExample(context); case MenuOptions.javaScriptAlert: _onJavaScriptAlertExample(context); case MenuOptions.viewportMeta: @@ -443,6 +446,10 @@ class SampleMenu extends StatelessWidget { value: MenuOptions.basicAuthentication, child: Text('Basic Authentication Example'), ), + const PopupMenuItem( + value: MenuOptions.webAuthentication, + child: Text('Web Authentication Example'), + ), const PopupMenuItem( value: MenuOptions.javaScriptAlert, child: Text('JavaScript Alert Example'), @@ -564,6 +571,30 @@ class SampleMenu extends StatelessWidget { ); } + Future _onWebAuthenticationExample(BuildContext context) async { + final androidController = webViewController as AndroidWebViewController; + final bool supported = await androidController.isWebViewFeatureSupported( + WebViewFeatureType.webAuthentication, + ); + + if (!supported) { + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Web Authentication is not supported on this device.')), + ); + } + return; + } + + await androidController.setWebAuthenticationSupport(WebAuthenticationSupport.forApp); + + if (context.mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Web Authentication enabled.'))); + } + } + Future _onDoPostRequest() { return webViewController.loadRequest( LoadRequestParams( diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/readme_excerpts.dart b/packages/webview_flutter/webview_flutter_android/example/lib/readme_excerpts.dart index c67d4eedecb6..5c6d47b28bc0 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/readme_excerpts.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/readme_excerpts.dart @@ -20,6 +20,26 @@ Future enablePaymentRequest() async { // #enddocregion payment_request_example } +/// Example function for README demonstration of Web Authentication support. +Future enableWebAuthentication() async { + final controller = PlatformWebViewController(AndroidWebViewControllerCreationParams()); + final androidController = controller as AndroidWebViewController; + // #docregion web_authentication_example + final bool webAuthenticationSupported = await androidController.isWebViewFeatureSupported( + WebViewFeatureType.webAuthentication, + ); + + if (webAuthenticationSupported) { + // Enable WebAuthn for the embedded app + await androidController.setWebAuthenticationSupport(WebAuthenticationSupport.forApp); + // Or for browser-like behavior supporting any website: + // await androidController.setWebAuthenticationSupport( + // WebAuthenticationSupport.forBrowser, + // ); + } + // #enddocregion web_authentication_example +} + /// Example function for README demonstration of geolocation permissions for /// a use case where the content is always trusted (for example, it only shows /// content from a domain controlled by the app developer) and geolocation diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webkit.g.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webkit.g.dart index 5b05123527d4..ec5388fd6a23 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webkit.g.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webkit.g.dart @@ -217,6 +217,9 @@ class PigeonOverrides { /// Overrides [WebSettingsCompat.setPaymentRequestEnabled]. static Future Function(WebSettings, bool)? webSettingsCompat_setPaymentRequestEnabled; + /// Overrides [WebSettingsCompat.setWebAuthenticationSupport]. + static Future Function(WebSettings, int)? webSettingsCompat_setWebAuthenticationSupport; + /// Overrides [WebViewFeature.isFeatureSupported]. static Future Function(String)? webViewFeature_isFeatureSupported; @@ -232,6 +235,7 @@ class PigeonOverrides { flutterAssetManager_instance = null; webStorage_instance = null; webSettingsCompat_setPaymentRequestEnabled = null; + webSettingsCompat_setWebAuthenticationSupport = null; webViewFeature_isFeatureSupported = null; } } @@ -7188,6 +7192,35 @@ class WebSettingsCompat extends PigeonInternalProxyApiBaseClass { _extractReplyValueOrThrow(pigeonVar_replyList, pigeonVar_channelName, isNullValid: true); } + static Future setWebAuthenticationSupport( + WebSettings webSettings, + int support, { + BinaryMessenger? pigeon_binaryMessenger, + PigeonInstanceManager? pigeon_instanceManager, + }) async { + if (PigeonOverrides.webSettingsCompat_setWebAuthenticationSupport != null) { + return PigeonOverrides.webSettingsCompat_setWebAuthenticationSupport!(webSettings, support); + } + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = _PigeonInternalProxyApiBaseCodec( + pigeon_instanceManager ?? PigeonInstanceManager.instance, + ); + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const pigeonVar_channelName = + 'dev.flutter.pigeon.webview_flutter_android.WebSettingsCompat.setWebAuthenticationSupport'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([ + webSettings, + support, + ]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow(pigeonVar_replyList, pigeonVar_channelName, isNullValid: true); + } + @override WebSettingsCompat pigeon_copy() { return WebSettingsCompat.pigeon_detached( diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webkit_constants.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webkit_constants.dart index 419d6e22ca9b..5760d088bd6a 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webkit_constants.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webkit_constants.dart @@ -126,4 +126,9 @@ class WebViewFeatureConstants { /// /// See https://developer.android.com/reference/androidx/webkit/WebViewFeature#PAYMENT_REQUEST. static const String paymentRequest = 'PAYMENT_REQUEST'; + + /// This feature covers [WebSettingsCompat.setWebAuthenticationSupport]. + /// + /// See https://developer.android.com/reference/androidx/webkit/WebViewFeature#WEB_AUTHENTICATION. + static const String webAuthentication = 'WEB_AUTHENTICATION'; } 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 70d8a0aac5ff..e654baac8c9e 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 @@ -790,10 +790,42 @@ class AndroidWebViewController extends PlatformWebViewController { Future isWebViewFeatureSupported(WebViewFeatureType featureType) { final String feature = switch (featureType) { WebViewFeatureType.paymentRequest => WebViewFeatureConstants.paymentRequest, + WebViewFeatureType.webAuthentication => WebViewFeatureConstants.webAuthentication, }; return android_webview.WebViewFeature.isFeatureSupported(feature); } + /// Sets the WebAuthentication support level for this WebView. + /// + /// This method configures which contexts can use WebAuthn APIs in the WebView. + /// Callers should check [isWebViewFeatureSupported] before calling this + /// method. + /// + /// **Parameters:** + /// * [support] - The desired WebAuthentication support level: + /// - [WebAuthenticationSupport.none]: Disables all WebAuthn requests + /// - [WebAuthenticationSupport.forApp]: Allows WebAuthn for the embedded app + /// - [WebAuthenticationSupport.forBrowser]: Allows WebAuthn for any website + /// + /// **Example:** + /// ```dart + /// final isSupported = await controller + /// .isWebViewFeatureSupported(WebViewFeatureType.webAuthentication); + /// if (isSupported) { + /// await controller.setWebAuthenticationSupport( + /// WebAuthenticationSupport.forApp, + /// ); + /// } + /// ``` + /// + /// See https://developer.android.com/reference/androidx/webkit/WebSettingsCompat#setWebAuthenticationSupport. + Future setWebAuthenticationSupport(WebAuthenticationSupport support) async { + await android_webview.WebSettingsCompat.setWebAuthenticationSupport( + _webView.settings, + support.value, + ); + } + /// Sets whether the WebView should enable the Payment Request API. /// /// This method uses [android_webview.WebSettingsCompat.setPaymentRequestEnabled] @@ -960,6 +992,41 @@ enum WebViewFeatureType { /// /// This feature covers [WebSettingsCompat.setPaymentRequestEnabled]. paymentRequest, + + /// Feature for isFeatureSupported. + /// + /// This feature covers [WebSettingsCompat.setWebAuthenticationSupport]. + webAuthentication, +} + +/// Support levels for [android_webview.WebSettingsCompat.setWebAuthenticationSupport]. +/// +/// This enum provides a type-safe way to specify the WebAuthentication support +/// level for a WebView. +/// +/// See https://developer.android.com/reference/androidx/webkit/WebSettingsCompat#setWebAuthenticationSupport. +enum WebAuthenticationSupport { + /// Disables WebAuthn requests from WebView. + /// + /// No WebAuthn APIs are available to web content in the WebView. + none(0), + + /// Allows WebAuthn requests for the embedded app. + /// + /// WebAuthn is available for Relying Party IDs that are registered for the + /// embedding application. + forApp(1), + + /// Allows WebAuthn calls for any website. + /// + /// WebAuthn is available for any Relying Party ID. This is the typical + /// configuration for a browser-like experience. + forBrowser(2); + + const WebAuthenticationSupport(this.value); + + /// The platform integer expected by `WebSettingsCompat`. + final int value; } /// Parameters received when the `WebView` should show a file selector. diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webkit.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webkit.dart index d4f758224ca3..5ed5a57fd72c 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webkit.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webkit.dart @@ -1004,6 +1004,9 @@ abstract class Certificate { abstract class WebSettingsCompat { @static void setPaymentRequestEnabled(WebSettings webSettings, bool enabled); + + @static + void setWebAuthenticationSupport(WebSettings webSettings, int support); } /// Utility class for checking which WebView Support Library features are supported on the device. diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 0aa602bf8976..7b5d83779c7a 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: 4.13.0 +version: 4.14.0 environment: sdk: ^3.12.0 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 12cb351323f7..8808866aad31 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 @@ -96,6 +96,7 @@ void main() { android_webview.WebSettings? mockSettings, Future Function(String)? isWebViewFeatureSupported, Future Function(android_webview.WebSettings, bool)? setPaymentRequestEnabled, + Future Function(android_webview.WebSettings, int)? setWebAuthenticationSupport, }) { final android_webview.WebView nonNullMockWebView = mockWebView ?? MockWebView(); @@ -254,6 +255,8 @@ void main() { isWebViewFeatureSupported ?? (_) async => false; android_webview.PigeonOverrides.webSettingsCompat_setPaymentRequestEnabled = setPaymentRequestEnabled ?? (_, _) async {}; + android_webview.PigeonOverrides.webSettingsCompat_setWebAuthenticationSupport = + setWebAuthenticationSupport ?? (_, _) async {}; final creationParams = AndroidWebViewControllerCreationParams( androidWebStorage: mockWebStorage ?? MockWebStorage(), @@ -1840,6 +1843,25 @@ void main() { expect(expectedIsWebViewFeatureEnabled, result); }); + test('isWebViewFeatureSupported webAuthentication', () async { + String? captured; + const expectedIsWebViewFeatureEnabled = true; + + final AndroidWebViewController controller = createControllerWithMocks( + isWebViewFeatureSupported: (String feature) async { + captured = feature; + return expectedIsWebViewFeatureEnabled; + }, + ); + + final bool result = await controller.isWebViewFeatureSupported( + WebViewFeatureType.webAuthentication, + ); + + expect(WebViewFeatureConstants.webAuthentication, captured); + expect(expectedIsWebViewFeatureEnabled, result); + }); + test('setPaymentRequestEnabled', () async { android_webview.WebSettings? capturedSettings; bool? capturedEnabled; @@ -1862,6 +1884,170 @@ void main() { expect(expectedEnabled, capturedEnabled); }); + test('setWebAuthenticationSupport with forApp', () async { + android_webview.WebSettings? capturedSettings; + int? capturedSupport; + + final mockWebView = MockWebView(); + final mockSettings = MockWebSettings(); + final AndroidWebViewController controller = createControllerWithMocks( + mockWebView: mockWebView, + mockSettings: mockSettings, + setWebAuthenticationSupport: (android_webview.WebSettings settings, int support) async { + capturedSettings = settings; + capturedSupport = support; + }, + ); + + await controller.setWebAuthenticationSupport(WebAuthenticationSupport.forApp); + + expect(mockSettings, capturedSettings); + expect(WebAuthenticationSupport.forApp.value, capturedSupport); + }); + + test('setWebAuthenticationSupport with forBrowser', () async { + android_webview.WebSettings? capturedSettings; + int? capturedSupport; + + final mockWebView = MockWebView(); + final mockSettings = MockWebSettings(); + final AndroidWebViewController controller = createControllerWithMocks( + mockWebView: mockWebView, + mockSettings: mockSettings, + setWebAuthenticationSupport: (android_webview.WebSettings settings, int support) async { + capturedSettings = settings; + capturedSupport = support; + }, + ); + + await controller.setWebAuthenticationSupport(WebAuthenticationSupport.forBrowser); + + expect(mockSettings, capturedSettings); + expect(WebAuthenticationSupport.forBrowser.value, capturedSupport); + }); + + test('setWebAuthenticationSupport with none', () async { + android_webview.WebSettings? capturedSettings; + int? capturedSupport; + + final mockWebView = MockWebView(); + final mockSettings = MockWebSettings(); + final AndroidWebViewController controller = createControllerWithMocks( + mockWebView: mockWebView, + mockSettings: mockSettings, + setWebAuthenticationSupport: (android_webview.WebSettings settings, int support) async { + capturedSettings = settings; + capturedSupport = support; + }, + ); + + await controller.setWebAuthenticationSupport(WebAuthenticationSupport.none); + + expect(mockSettings, capturedSettings); + expect(WebAuthenticationSupport.none.value, capturedSupport); + }); + + test('setWebAuthenticationSupport propagates unsupported errors', () async { + final expectedError = UnsupportedError('WEB_AUTHENTICATION is not supported'); + + final mockWebView = MockWebView(); + final mockSettings = MockWebSettings(); + final AndroidWebViewController controller = createControllerWithMocks( + mockWebView: mockWebView, + mockSettings: mockSettings, + setWebAuthenticationSupport: (android_webview.WebSettings settings, int support) async { + throw expectedError; + }, + ); + + await expectLater( + controller.setWebAuthenticationSupport(WebAuthenticationSupport.forApp), + throwsA(same(expectedError)), + ); + }); + + test('setWebAuthenticationSupport with forApp', () async { + android_webview.WebSettings? capturedSettings; + int? capturedSupport; + + final mockWebView = MockWebView(); + final mockSettings = MockWebSettings(); + final AndroidWebViewController controller = createControllerWithMocks( + mockWebView: mockWebView, + mockSettings: mockSettings, + setWebAuthenticationSupport: (android_webview.WebSettings settings, int support) async { + capturedSettings = settings; + capturedSupport = support; + }, + ); + + await controller.setWebAuthenticationSupport(WebAuthenticationSupport.forApp); + + expect(mockSettings, capturedSettings); + expect(WebAuthenticationSupport.forApp.value, capturedSupport); + }); + + test('setWebAuthenticationSupport with forBrowser', () async { + android_webview.WebSettings? capturedSettings; + int? capturedSupport; + + final mockWebView = MockWebView(); + final mockSettings = MockWebSettings(); + final AndroidWebViewController controller = createControllerWithMocks( + mockWebView: mockWebView, + mockSettings: mockSettings, + setWebAuthenticationSupport: (android_webview.WebSettings settings, int support) async { + capturedSettings = settings; + capturedSupport = support; + }, + ); + + await controller.setWebAuthenticationSupport(WebAuthenticationSupport.forBrowser); + + expect(mockSettings, capturedSettings); + expect(WebAuthenticationSupport.forBrowser.value, capturedSupport); + }); + + test('setWebAuthenticationSupport with none', () async { + android_webview.WebSettings? capturedSettings; + int? capturedSupport; + + final mockWebView = MockWebView(); + final mockSettings = MockWebSettings(); + final AndroidWebViewController controller = createControllerWithMocks( + mockWebView: mockWebView, + mockSettings: mockSettings, + setWebAuthenticationSupport: (android_webview.WebSettings settings, int support) async { + capturedSettings = settings; + capturedSupport = support; + }, + ); + + await controller.setWebAuthenticationSupport(WebAuthenticationSupport.none); + + expect(mockSettings, capturedSettings); + expect(WebAuthenticationSupport.none.value, capturedSupport); + }); + + test('setWebAuthenticationSupport propagates unsupported errors', () async { + final expectedError = UnsupportedError('WEB_AUTHENTICATION is not supported'); + + final mockWebView = MockWebView(); + final mockSettings = MockWebSettings(); + final AndroidWebViewController controller = createControllerWithMocks( + mockWebView: mockWebView, + mockSettings: mockSettings, + setWebAuthenticationSupport: (android_webview.WebSettings settings, int support) async { + throw expectedError; + }, + ); + + await expectLater( + controller.setWebAuthenticationSupport(WebAuthenticationSupport.forApp), + throwsA(same(expectedError)), + ); + }); + test('setInsetsForWebContentToIgnore', () async { final mockWebView = MockWebView(); final AndroidWebViewController controller = createControllerWithMocks(mockWebView: mockWebView); 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 ac71113886f4..c4c72286f5b2 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 @@ -778,6 +778,15 @@ class MockAndroidWebViewController extends _i1.Mock implements _i7.AndroidWebVie ) as _i8.Future); + @override + _i8.Future setWebAuthenticationSupport(_i7.WebAuthenticationSupport? support) => + (super.noSuchMethod( + Invocation.method(#setWebAuthenticationSupport, [support]), + returnValue: _i8.Future.value(), + returnValueForMissingStub: _i8.Future.value(), + ) + as _i8.Future); + @override _i8.Future setPaymentRequestEnabled(bool? enabled) => (super.noSuchMethod( @@ -786,6 +795,15 @@ class MockAndroidWebViewController extends _i1.Mock implements _i7.AndroidWebVie returnValueForMissingStub: _i8.Future.value(), ) as _i8.Future); + + @override + _i8.Future setInsetsForWebContentToIgnore(List<_i7.AndroidWebViewInsets>? insets) => + (super.noSuchMethod( + Invocation.method(#setInsetsForWebContentToIgnore, [insets]), + returnValue: _i8.Future.value(), + returnValueForMissingStub: _i8.Future.value(), + ) + as _i8.Future); } /// A class which mocks [AndroidWebViewWidgetCreationParams]. 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 81e158f91e54..12e125135c23 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 @@ -585,6 +585,15 @@ class MockAndroidWebViewController extends _i1.Mock implements _i6.AndroidWebVie ) as _i5.Future); + @override + _i5.Future setWebAuthenticationSupport(_i6.WebAuthenticationSupport? support) => + (super.noSuchMethod( + Invocation.method(#setWebAuthenticationSupport, [support]), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) + as _i5.Future); + @override _i5.Future setPaymentRequestEnabled(bool? enabled) => (super.noSuchMethod( @@ -593,4 +602,13 @@ class MockAndroidWebViewController extends _i1.Mock implements _i6.AndroidWebVie returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); + + @override + _i5.Future setInsetsForWebContentToIgnore(List<_i6.AndroidWebViewInsets>? insets) => + (super.noSuchMethod( + Invocation.method(#setInsetsForWebContentToIgnore, [insets]), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) + as _i5.Future); }