[webview_flutter] Adds support to receive permission requests (#3543)
~~Aggregate implementation of https://github.com/flutter/flutter/issues/78147~~
Fixes https://github.com/flutter/flutter/issues/78147
Fixes https://github.com/flutter/flutter/issues/56871
diff --git a/packages/webview_flutter/webview_flutter/CHANGELOG.md b/packages/webview_flutter/webview_flutter/CHANGELOG.md
index 6193a49..3b05257 100644
--- a/packages/webview_flutter/webview_flutter/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 4.2.0
+
+* Adds support to receive permission requests. See `WebViewController(onPermissionRequest)`.
+
## 4.1.0
* Adds support to track URL changes. See `NavigationDelegate(onUrlChange)`.
diff --git a/packages/webview_flutter/webview_flutter/example/pubspec.yaml b/packages/webview_flutter/webview_flutter/example/pubspec.yaml
index 31e0d28..733acc1 100644
--- a/packages/webview_flutter/webview_flutter/example/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter/example/pubspec.yaml
@@ -17,8 +17,8 @@
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
- webview_flutter_android: ^3.5.0
- webview_flutter_wkwebview: ^3.3.0
+ webview_flutter_android: ^3.6.0
+ webview_flutter_wkwebview: ^3.4.0
dev_dependencies:
build_runner: ^2.1.5
@@ -29,7 +29,7 @@
sdk: flutter
integration_test:
sdk: flutter
- webview_flutter_platform_interface: ^2.1.0
+ webview_flutter_platform_interface: ^2.3.0
flutter:
uses-material-design: true
diff --git a/packages/webview_flutter/webview_flutter/lib/src/navigation_delegate.dart b/packages/webview_flutter/webview_flutter/lib/src/navigation_delegate.dart
index 9f3923c..9ca6981 100644
--- a/packages/webview_flutter/webview_flutter/lib/src/navigation_delegate.dart
+++ b/packages/webview_flutter/webview_flutter/lib/src/navigation_delegate.dart
@@ -37,7 +37,7 @@
class NavigationDelegate {
/// Constructs a [NavigationDelegate].
///
- /// {@template webview_fluttter.navigation_delegate.constructor}
+ /// {@template webview_fluttter.NavigationDelegate.constructor}
/// `onUrlChange`: invoked when the underlying web view changes to a new url.
/// {@endtemplate}
NavigationDelegate({
@@ -61,6 +61,8 @@
/// Constructs a [NavigationDelegate] from creation params for a specific
/// platform.
///
+ /// {@macro webview_fluttter.NavigationDelegate.constructor}
+ ///
/// {@template webview_flutter.NavigationDelegate.fromPlatformCreationParams}
/// Below is an example of setting platform-specific creation parameters for
/// iOS and Android:
@@ -87,8 +89,6 @@
/// );
/// ```
/// {@endtemplate}
- ///
- /// {@macro webview_fluttter.navigation_delegate.constructor}
NavigationDelegate.fromPlatformCreationParams(
PlatformNavigationDelegateCreationParams params, {
FutureOr<NavigationDecision> Function(NavigationRequest request)?
@@ -110,7 +110,7 @@
/// Constructs a [NavigationDelegate] from a specific platform implementation.
///
- /// {@macro webview_fluttter.navigation_delegate.constructor}
+ /// {@macro webview_fluttter.NavigationDelegate.constructor}
NavigationDelegate.fromPlatform(
this.platform, {
this.onNavigationRequest,
diff --git a/packages/webview_flutter/webview_flutter/lib/src/webview_controller.dart b/packages/webview_flutter/webview_flutter/lib/src/webview_controller.dart
index fc5e380..778e560 100644
--- a/packages/webview_flutter/webview_flutter/lib/src/webview_controller.dart
+++ b/packages/webview_flutter/webview_flutter/lib/src/webview_controller.dart
@@ -43,16 +43,33 @@
class WebViewController {
/// Constructs a [WebViewController].
///
+ /// {@template webview_fluttter.WebViewController.constructor}
+ /// `onPermissionRequest`: A callback that notifies the host application that
+ /// web content is requesting permission to access the specified resources.
+ /// To grant access for a device resource, most platforms will need to update
+ /// their app configurations for the relevant system resource.
+ ///
+ /// For Android, you will need to update your `AndroidManifest.xml`. See
+ /// https://developer.android.com/training/permissions/declaring
+ ///
+ /// For iOS, you will need to update your `Info.plist`. See
+ /// https://developer.apple.com/documentation/uikit/protecting_the_user_s_privacy/requesting_access_to_protected_resources?language=objc.
+ /// {@endtemplate}
+ ///
/// See [WebViewController.fromPlatformCreationParams] for setting parameters
/// for a specific platform.
- WebViewController()
- : this.fromPlatformCreationParams(
+ WebViewController({
+ void Function(WebViewPermissionRequest request)? onPermissionRequest,
+ }) : this.fromPlatformCreationParams(
const PlatformWebViewControllerCreationParams(),
+ onPermissionRequest: onPermissionRequest,
);
/// Constructs a [WebViewController] from creation params for a specific
/// platform.
///
+ /// {@macro webview_fluttter.WebViewController.constructor}
+ ///
/// {@template webview_flutter.WebViewController.fromPlatformCreationParams}
/// Below is an example of setting platform-specific creation parameters for
/// iOS and Android:
@@ -80,11 +97,31 @@
/// ```
/// {@endtemplate}
WebViewController.fromPlatformCreationParams(
- PlatformWebViewControllerCreationParams params,
- ) : this.fromPlatform(PlatformWebViewController(params));
+ PlatformWebViewControllerCreationParams params, {
+ void Function(WebViewPermissionRequest request)? onPermissionRequest,
+ }) : this.fromPlatform(
+ PlatformWebViewController(params),
+ onPermissionRequest: onPermissionRequest,
+ );
/// Constructs a [WebViewController] from a specific platform implementation.
- WebViewController.fromPlatform(this.platform);
+ ///
+ /// {@macro webview_fluttter.WebViewController.constructor}
+ WebViewController.fromPlatform(
+ this.platform, {
+ void Function(WebViewPermissionRequest request)? onPermissionRequest,
+ }) {
+ if (onPermissionRequest != null) {
+ platform.setOnPlatformPermissionRequest(
+ (PlatformWebViewPermissionRequest request) {
+ onPermissionRequest(WebViewPermissionRequest._(
+ request,
+ types: request.types,
+ ));
+ },
+ );
+ }
+ }
/// Implementation of [PlatformWebViewController] for the current platform.
final PlatformWebViewController platform;
@@ -319,3 +356,49 @@
return platform.setUserAgent(userAgent);
}
}
+
+/// Permissions request when web content requests access to protected resources.
+///
+/// A response MUST be provided by calling [grant], [deny], or a method from
+/// [platform].
+///
+/// ## Platform-Specific Features
+/// This class contains an underlying implementation provided by the current
+/// platform. Once a platform implementation is imported, the example below
+/// can be followed to use features provided by a platform's implementation.
+///
+/// Below is an example of accessing the platform-specific implementation for
+/// iOS and Android:
+///
+/// ```dart
+/// final WebViewPermissionRequest request = ...;
+///
+/// if (WebViewPlatform.instance is WebKitWebViewPlatform) {
+/// final WebKitWebViewPermissionRequest webKitRequest =
+/// request.platform as WebKitWebViewPermissionRequest;
+/// } else if (WebViewPlatform.instance is AndroidWebViewPlatform) {
+/// final AndroidWebViewPermissionRequest androidRequest =
+/// request.platform as AndroidWebViewPermissionRequest;
+/// }
+/// ```
+@immutable
+class WebViewPermissionRequest {
+ const WebViewPermissionRequest._(this.platform, {required this.types});
+
+ /// All resources access has been requested for.
+ final Set<WebViewPermissionResourceType> types;
+
+ /// Implementation of [PlatformWebViewPermissionRequest] for the current
+ /// platform.
+ final PlatformWebViewPermissionRequest platform;
+
+ /// Grant permission for the requested resource(s).
+ Future<void> grant() {
+ return platform.grant();
+ }
+
+ /// Deny permission for the requested resource(s).
+ Future<void> deny() {
+ return platform.deny();
+ }
+}
diff --git a/packages/webview_flutter/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/webview_flutter/lib/webview_flutter.dart
index 4c14dcd..3e85cc3 100644
--- a/packages/webview_flutter/webview_flutter/lib/webview_flutter.dart
+++ b/packages/webview_flutter/webview_flutter/lib/webview_flutter.dart
@@ -16,6 +16,7 @@
PlatformNavigationDelegateCreationParams,
PlatformWebViewControllerCreationParams,
PlatformWebViewCookieManagerCreationParams,
+ PlatformWebViewPermissionRequest,
PlatformWebViewWidgetCreationParams,
ProgressCallback,
UrlChange,
@@ -23,6 +24,7 @@
WebResourceErrorCallback,
WebResourceErrorType,
WebViewCookie,
+ WebViewPermissionResourceType,
WebViewPlatform;
export 'src/navigation_delegate.dart';
diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml
index 85846a1..05d6cd2 100644
--- a/packages/webview_flutter/webview_flutter/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter/pubspec.yaml
@@ -2,7 +2,7 @@
description: A Flutter plugin that provides a WebView widget on Android and iOS.
repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
-version: 4.1.0
+version: 4.2.0
environment:
sdk: ">=2.18.0 <4.0.0"
@@ -20,7 +20,7 @@
flutter:
sdk: flutter
webview_flutter_android: ^3.0.0
- webview_flutter_platform_interface: ^2.1.0
+ webview_flutter_platform_interface: ^2.3.0
webview_flutter_wkwebview: ^3.0.0
dev_dependencies:
diff --git a/packages/webview_flutter/webview_flutter/test/webview_controller_test.dart b/packages/webview_flutter/webview_flutter/test/webview_controller_test.dart
index f11884b..79d01ba 100644
--- a/packages/webview_flutter/webview_flutter/test/webview_controller_test.dart
+++ b/packages/webview_flutter/webview_flutter/test/webview_controller_test.dart
@@ -365,4 +365,38 @@
mockPlatformNavigationDelegate,
));
});
+
+ test('onPermissionRequest', () async {
+ bool permissionRequestCallbackCalled = false;
+
+ final MockPlatformWebViewController mockPlatformWebViewController =
+ MockPlatformWebViewController();
+ WebViewController.fromPlatform(
+ mockPlatformWebViewController,
+ onPermissionRequest: (WebViewPermissionRequest request) {
+ permissionRequestCallbackCalled = true;
+ },
+ );
+
+ final void Function(PlatformWebViewPermissionRequest request)
+ requestCallback = verify(mockPlatformWebViewController
+ .setOnPlatformPermissionRequest(captureAny))
+ .captured
+ .single as void Function(PlatformWebViewPermissionRequest request);
+
+ requestCallback(const TestPlatformWebViewPermissionRequest());
+ expect(permissionRequestCallbackCalled, isTrue);
+ });
+}
+
+class TestPlatformWebViewPermissionRequest
+ extends PlatformWebViewPermissionRequest {
+ const TestPlatformWebViewPermissionRequest()
+ : super(types: const <WebViewPermissionResourceType>{});
+
+ @override
+ Future<void> grant() async {}
+
+ @override
+ Future<void> deny() async {}
}
diff --git a/packages/webview_flutter/webview_flutter/test/webview_controller_test.mocks.dart b/packages/webview_flutter/webview_flutter/test/webview_controller_test.mocks.dart
index 27d06fd..fc24275 100644
--- a/packages/webview_flutter/webview_flutter/test/webview_controller_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter/test/webview_controller_test.mocks.dart
@@ -11,8 +11,7 @@
as _i6;
import 'package:webview_flutter_platform_interface/src/platform_webview_controller.dart'
as _i4;
-import 'package:webview_flutter_platform_interface/src/webview_platform.dart'
- as _i2;
+import 'package:webview_flutter_platform_interface/src/types/types.dart' as _i2;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
@@ -342,6 +341,18 @@
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setOnPlatformPermissionRequest(
+ void Function(_i2.PlatformWebViewPermissionRequest)?
+ onPermissionRequest) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setOnPlatformPermissionRequest,
+ [onPermissionRequest],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
}
/// A class which mocks [PlatformNavigationDelegate].
diff --git a/packages/webview_flutter/webview_flutter/test/webview_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter/test/webview_cookie_manager_test.mocks.dart
index 04e2b7f..1d7de30 100644
--- a/packages/webview_flutter/webview_flutter/test/webview_cookie_manager_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter/test/webview_cookie_manager_test.mocks.dart
@@ -8,8 +8,7 @@
import 'package:mockito/mockito.dart' as _i1;
import 'package:webview_flutter_platform_interface/src/platform_webview_cookie_manager.dart'
as _i3;
-import 'package:webview_flutter_platform_interface/src/webview_platform.dart'
- as _i2;
+import 'package:webview_flutter_platform_interface/src/types/types.dart' as _i2;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
diff --git a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
index 32f30b1..eb92ab7 100644
--- a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
@@ -30,10 +30,14 @@
// ignore: unnecessary_statements
main_file.PlatformWebViewCookieManagerCreationParams;
// ignore: unnecessary_statements
+ main_file.PlatformWebViewPermissionRequest;
+ // ignore: unnecessary_statements
main_file.PlatformWebViewWidgetCreationParams;
// ignore: unnecessary_statements
main_file.ProgressCallback;
// ignore: unnecessary_statements
+ main_file.WebViewPermissionResourceType;
+ // ignore: unnecessary_statements
main_file.WebResourceError;
// ignore: unnecessary_statements
main_file.WebResourceErrorCallback;
diff --git a/packages/webview_flutter/webview_flutter/test/webview_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter/test/webview_widget_test.mocks.dart
index 3d4c583..9d3a790 100644
--- a/packages/webview_flutter/webview_flutter/test/webview_widget_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter/test/webview_widget_test.mocks.dart
@@ -15,8 +15,7 @@
as _i6;
import 'package:webview_flutter_platform_interface/src/platform_webview_widget.dart'
as _i9;
-import 'package:webview_flutter_platform_interface/src/webview_platform.dart'
- as _i2;
+import 'package:webview_flutter_platform_interface/src/types/types.dart' as _i2;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
@@ -360,6 +359,18 @@
returnValue: _i7.Future<void>.value(),
returnValueForMissingStub: _i7.Future<void>.value(),
) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setOnPlatformPermissionRequest(
+ void Function(_i2.PlatformWebViewPermissionRequest)?
+ onPermissionRequest) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setOnPlatformPermissionRequest,
+ [onPermissionRequest],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
}
/// A class which mocks [PlatformWebViewWidget].