Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
517e9d4
Implement http basic auth
JeroenWeener Aug 10, 2023
967879b
Apply feedback
JeroenWeener Aug 28, 2023
c8624c0
Create HttpAuthHandlerTest.java
JeroenWeener Aug 29, 2023
4f3574d
Format java files
JeroenWeener Aug 29, 2023
1e7f785
Regenerate build_runner files
JeroenWeener Aug 29, 2023
131bc56
Implement feedback
JeroenWeener Sep 11, 2023
bc01be4
Remove redundant key in `Info.plist`
JeroenWeener Sep 11, 2023
67aa00e
Update example apps
JeroenWeener Sep 11, 2023
32496d0
Implement http basic auth
JeroenWeener Aug 10, 2023
aeb8708
Apply feedback
JeroenWeener Aug 28, 2023
fffc4c7
Create HttpAuthHandlerTest.java
JeroenWeener Aug 29, 2023
b455040
Format java files
JeroenWeener Aug 29, 2023
2aa9bfe
Regenerate build_runner files
JeroenWeener Aug 29, 2023
db286ba
Implement feedback
JeroenWeener Sep 11, 2023
467feb3
Remove redundant key in `Info.plist`
JeroenWeener Sep 11, 2023
dad8ae6
Update example apps
JeroenWeener Sep 11, 2023
6f3d802
Merge branch 'webview-auth-request' of https://github.com/andreisas06…
JeroenWeener Nov 1, 2023
0fef591
Add platform interface dev dependency to example
JeroenWeener Nov 1, 2023
b2a4fbb
Merge branch 'main' into webview-auth-request
JeroenWeener Nov 1, 2023
ce35d9b
Update packages/webview_flutter/webview_flutter_platform_interface/li…
bparrishMines Nov 8, 2023
fc32898
Merge branch 'main' of github.com:flutter/packages into webview-auth-…
bparrishMines Nov 8, 2023
4673e65
Merge branch 'webview-auth-request' of github.com:andreisas06/package…
bparrishMines Nov 8, 2023
580521a
Fix some lints, errros and call on errors
bparrishMines Nov 8, 2023
d1f305b
fix lints
bparrishMines Nov 8, 2023
a3f74be
fix tests
bparrishMines Nov 8, 2023
ed3798f
add onProceed and onCancel back
bparrishMines Nov 8, 2023
154c1f8
dont require realm to be nonnull
bparrishMines Nov 8, 2023
3c61dbc
add line back
bparrishMines Nov 8, 2023
7cf0d7e
Merge remote-tracking branch 'upstream/main' into webview-auth-request
JeroenWeener Nov 21, 2023
a21f29a
Update changelogs
JeroenWeener Nov 21, 2023
284d455
Separate android changes
JeroenWeener Nov 21, 2023
c27986a
Delete packages/webview_flutter/webview_flutter_wkwebview/example/ios…
JeroenWeener Nov 21, 2023
e8634e1
Delete packages/webview_flutter/webview_flutter_wkwebview/example/ios…
JeroenWeener Nov 21, 2023
b28fd8a
Delete packages/webview_flutter/webview_flutter_wkwebview/ios/Classes…
JeroenWeener Nov 21, 2023
a886dd8
Delete packages/webview_flutter/webview_flutter_wkwebview/ios/Classes…
JeroenWeener Nov 21, 2023
a580f4c
Delete packages/webview_flutter/webview_flutter_wkwebview/ios/Classes…
JeroenWeener Nov 21, 2023
e43cb52
Delete packages/webview_flutter/webview_flutter_wkwebview/ios/Classes…
JeroenWeener Nov 21, 2023
fbcd3f9
Delete packages/webview_flutter/webview_flutter_wkwebview/ios/Classes…
JeroenWeener Nov 21, 2023
7f95e52
Delete packages/webview_flutter/webview_flutter_wkwebview/ios/Classes…
JeroenWeener Nov 21, 2023
279d3db
Delete packages/webview_flutter/webview_flutter_wkwebview/example/ios…
JeroenWeener Nov 21, 2023
5c8ecc1
Update pubspecs
JeroenWeener Nov 28, 2023
60fe593
cancel by default
bparrishMines Dec 5, 2023
605833c
Merge branch 'main' of github.com:flutter/packages into webview-auth-…
bparrishMines Dec 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implement http basic auth
  • Loading branch information
JeroenWeener committed Nov 1, 2023
commit 32496d054f4b5060370bc7c11d555eca65983370
4 changes: 4 additions & 0 deletions packages/webview_flutter/webview_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 4.5.0

* Adds support for HTTP basic authentication. See `NavigationDelegate(onReceivedHttpAuthRequest)`.

## 4.4.1

* Exposes `JavaScriptLogLevel` from platform interface.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ Future<void> main() async {
request.response.writeln('${request.headers}');
} else if (request.uri.path == '/favicon.ico') {
request.response.statusCode = HttpStatus.notFound;
} else if (request.uri.path == '/http-basic-authentication') {
final bool isAuthenticating = request.headers['Authorization'] != null;
if (isAuthenticating) {
request.response.writeln('Authorized');
} else {
request.response.headers
.add('WWW-Authenticate', 'Basic realm="Test realm"');
request.response.statusCode = HttpStatus.unauthorized;
}
} else {
fail('unexpected request: ${request.method} ${request.uri}');
}
Expand All @@ -41,6 +50,7 @@ Future<void> main() async {
final String primaryUrl = '$prefixUrl/hello.txt';
final String secondaryUrl = '$prefixUrl/secondary.txt';
final String headersUrl = '$prefixUrl/headers';
final String basicAuthUrl = '$prefixUrl/http-basic-authentication';

testWidgets('loadRequest', (WidgetTester tester) async {
final Completer<void> pageFinished = Completer<void>();
Expand All @@ -49,12 +59,9 @@ Future<void> main() async {
unawaited(controller.setNavigationDelegate(
NavigationDelegate(onPageFinished: (_) => pageFinished.complete()),
));
unawaited(controller.loadRequest(Uri.parse(primaryUrl)));

await tester.pumpWidget(WebViewWidget(controller: controller));

unawaited(controller.loadRequest(Uri.parse(primaryUrl)));
await pageFinished.future;

final String? currentUrl = await controller.currentUrl();
expect(currentUrl, primaryUrl);
});
Expand Down Expand Up @@ -761,6 +768,49 @@ Future<void> main() async {

await expectLater(urlChangeCompleter.future, completion(secondaryUrl));
});

testWidgets('can receive HTTP basic auth requests',
(WidgetTester tester) async {
final Completer<void> authRequested = Completer<void>();
final WebViewController controller = WebViewController();

unawaited(
controller.setNavigationDelegate(
NavigationDelegate(
onHttpBasicAuthRequest: (HttpBasicAuthRequest request) =>
authRequested.complete(),
),
),
);

await tester.pumpWidget(WebViewWidget(controller: controller));

unawaited(controller.loadRequest(Uri.parse(basicAuthUrl)));

await expectLater(authRequested.future, completes);
});

testWidgets('can reply to HTTP basic auth requests',
(WidgetTester tester) async {
final WebViewController controller = WebViewController();
final Completer<void> pageFinished = Completer<void>();

unawaited(
controller.setNavigationDelegate(
NavigationDelegate(
onHttpBasicAuthRequest: (HttpBasicAuthRequest request) =>
request.onProceed('user', 'pass'),
onPageFinished: (_) => pageFinished.complete(),
),
),
);

await tester.pumpWidget(WebViewWidget(controller: controller));

unawaited(controller.loadRequest(Uri.parse(basicAuthUrl)));

await expectLater(pageFinished.future, completes);
});
});

testWidgets('target _blank opens in same window',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@
isa = PBXProject;
attributes = {
DefaultBuildSystemTypeForWorkspace = Original;
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "The Flutter Authors";
TargetAttributes = {
68BDCAE823C3F7CB00D9C032 = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
73 changes: 72 additions & 1 deletion packages/webview_flutter/webview_flutter/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ class _WebViewExampleState extends State<WebViewExample> {
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
params = WebKitWebViewControllerCreationParams(
allowsInlineMediaPlayback: true,
mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
);
} else {
params = const PlatformWebViewControllerCreationParams();
Expand Down Expand Up @@ -173,6 +172,11 @@ Page resource error:
onUrlChange: (UrlChange change) {
debugPrint('url change to ${change.url}');
},
onHttpBasicAuthRequest: (HttpBasicAuthRequest request) {
debugPrint(
'HTTP basic auth request with host ${request.host} and realm ${request.realm}');
openDialog(request);
},
),
)
..addJavaScriptChannel(
Expand Down Expand Up @@ -226,6 +230,60 @@ Page resource error:
child: const Icon(Icons.favorite),
);
}

Future<void> openDialog(HttpBasicAuthRequest httpRequest) async {
final TextEditingController usernameTextController =
TextEditingController();
final TextEditingController passwordTextController =
TextEditingController();

return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('${httpRequest.host}: ${httpRequest.realm}'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(
decoration: const InputDecoration(labelText: 'Username'),
autofocus: true,
controller: usernameTextController,
),
TextField(
decoration: const InputDecoration(labelText: 'Password'),
controller: passwordTextController,
),
],
),
),
actions: <Widget>[
// Explicitly cancel the request on iOS as the OS does not emit new
// requests when a previous request is pending.
TextButton(
onPressed: () {
httpRequest.onCancel();
Navigator.of(context).pop();
},
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
httpRequest.onProceed(
usernameTextController.text,
passwordTextController.text,
);
Navigator.of(context).pop();
},
child: const Text('Authenticate'),
),
],
);
},
);
}
}

enum MenuOptions {
Expand All @@ -243,6 +301,7 @@ enum MenuOptions {
transparentBackground,
setCookie,
logExample,
basicAuthentication,
}

class SampleMenu extends StatelessWidget {
Expand Down Expand Up @@ -302,6 +361,9 @@ class SampleMenu extends StatelessWidget {
case MenuOptions.logExample:
_onLogExample();
break;
case MenuOptions.basicAuthentication:
_basicAuthExample();
break;
}
},
itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
Expand Down Expand Up @@ -362,6 +424,10 @@ class SampleMenu extends StatelessWidget {
value: MenuOptions.logExample,
child: Text('Log example'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.basicAuthentication,
child: Text('Basic Authentication Example'),
),
],
);
}
Expand Down Expand Up @@ -515,6 +581,11 @@ class SampleMenu extends StatelessWidget {

return webViewController.loadHtmlString(kLogExamplePage);
}

Future<void> _basicAuthExample() {
return webViewController.loadRequest(Uri.parse(
'https://www.httpwatch.com/httpgallery/authentication/#showExample10'));
}
}

class NavigationControls extends StatelessWidget {
Expand Down
5 changes: 5 additions & 0 deletions packages/webview_flutter/webview_flutter/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,8 @@ flutter:
- assets/sample_video.mp4
- assets/www/index.html
- assets/www/styles/style.css

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins
dependency_overrides:
{webview_flutter_android: {path: ../../../webview_flutter/webview_flutter_android}, webview_flutter_platform_interface: {path: ../../../webview_flutter/webview_flutter_platform_interface}, webview_flutter_wkwebview: {path: ../../../webview_flutter/webview_flutter_wkwebview}}
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,9 @@ class FakeNavigationDelegate extends PlatformNavigationDelegate {

@override
Future<void> setOnUrlChange(UrlChangeCallback onUrlChange) async {}

@override
Future<void> setOnHttpBasicAuthRequest(
HttpAuthRequestCallback handler,
) async {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class NavigationDelegate {
void Function(int progress)? onProgress,
void Function(WebResourceError error)? onWebResourceError,
void Function(UrlChange change)? onUrlChange,
void Function(HttpBasicAuthRequest request)? onHttpBasicAuthRequest,
}) : this.fromPlatformCreationParams(
const PlatformNavigationDelegateCreationParams(),
onNavigationRequest: onNavigationRequest,
Expand All @@ -56,6 +57,7 @@ class NavigationDelegate {
onProgress: onProgress,
onWebResourceError: onWebResourceError,
onUrlChange: onUrlChange,
onHttpBasicAuthRequest: onHttpBasicAuthRequest,
);

/// Constructs a [NavigationDelegate] from creation params for a specific
Expand Down Expand Up @@ -98,6 +100,7 @@ class NavigationDelegate {
void Function(int progress)? onProgress,
void Function(WebResourceError error)? onWebResourceError,
void Function(UrlChange change)? onUrlChange,
void Function(HttpBasicAuthRequest request)? onHttpBasicAuthRequest,
}) : this.fromPlatform(
PlatformNavigationDelegate(params),
onNavigationRequest: onNavigationRequest,
Expand All @@ -106,6 +109,7 @@ class NavigationDelegate {
onProgress: onProgress,
onWebResourceError: onWebResourceError,
onUrlChange: onUrlChange,
onHttpBasicAuthRequest: onHttpBasicAuthRequest,
);

/// Constructs a [NavigationDelegate] from a specific platform implementation.
Expand All @@ -119,6 +123,7 @@ class NavigationDelegate {
this.onProgress,
this.onWebResourceError,
void Function(UrlChange change)? onUrlChange,
this.onHttpBasicAuthRequest,
}) {
if (onNavigationRequest != null) {
platform.setOnNavigationRequest(onNavigationRequest!);
Expand All @@ -138,6 +143,9 @@ class NavigationDelegate {
if (onUrlChange != null) {
platform.setOnUrlChange(onUrlChange);
}
if (onHttpBasicAuthRequest != null) {
platform.setOnHttpBasicAuthRequest(onHttpBasicAuthRequest!);
}
}

/// Implementation of [PlatformNavigationDelegate] for the current platform.
Expand Down Expand Up @@ -166,4 +174,7 @@ class NavigationDelegate {

/// Invoked when a resource loading error occurred.
final WebResourceErrorCallback? onWebResourceError;

/// Invoked when a resource required HTTP basic authentication.
final HttpAuthRequestCallback? onHttpBasicAuthRequest;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ library webview_flutter;

export 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'
show
HttpBasicAuthRequest,
JavaScriptConsoleMessage,
JavaScriptLogLevel,
JavaScriptMessage,
Expand Down
9 changes: 7 additions & 2 deletions packages/webview_flutter/webview_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: webview_flutter
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.4.1
version: 4.5.0

environment:
sdk: ">=2.19.0 <4.0.0"
Expand All @@ -20,7 +20,7 @@ dependencies:
flutter:
sdk: flutter
webview_flutter_android: ^3.12.0
webview_flutter_platform_interface: ^2.6.0
webview_flutter_platform_interface: ^2.7.0
webview_flutter_wkwebview: ^3.9.0

dev_dependencies:
Expand All @@ -34,3 +34,8 @@ topics:
- html
- webview
- webview-flutter

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins
dependency_overrides:
{webview_flutter_android: {path: ../../webview_flutter/webview_flutter_android}, webview_flutter_platform_interface: {path: ../../webview_flutter/webview_flutter_platform_interface}, webview_flutter_wkwebview: {path: ../../webview_flutter/webview_flutter_wkwebview}}
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,19 @@ void main() {

verify(delegate.platform.setOnUrlChange(onUrlChange));
});

test('onHttpBasicAuthRequest', () {
WebViewPlatform.instance = TestWebViewPlatform();

void onHttpBasicAuthRequest(HttpBasicAuthRequest request) {}

final NavigationDelegate delegate = NavigationDelegate(
onHttpBasicAuthRequest: onHttpBasicAuthRequest,
);

verify(
delegate.platform.setOnHttpBasicAuthRequest(onHttpBasicAuthRequest));
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,15 @@ class MockPlatformNavigationDelegate extends _i1.Mock
returnValue: _i8.Future<void>.value(),
returnValueForMissingStub: _i8.Future<void>.value(),
) as _i8.Future<void>);
@override
_i8.Future<void> setOnHttpBasicAuthRequest(
_i3.HttpAuthRequestCallback? onHttpAuthRequest) =>
(super.noSuchMethod(
Invocation.method(
#setOnHttpBasicAuthRequest,
[onHttpAuthRequest],
),
returnValue: _i8.Future<void>.value(),
returnValueForMissingStub: _i8.Future<void>.value(),
) as _i8.Future<void>);
}
Original file line number Diff line number Diff line change
Expand Up @@ -466,4 +466,15 @@ class MockPlatformNavigationDelegate extends _i1.Mock
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> setOnHttpBasicAuthRequest(
_i6.HttpAuthRequestCallback? onHttpAuthRequest) =>
(super.noSuchMethod(
Invocation.method(
#setOnHttpBasicAuthRequest,
[onHttpAuthRequest],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
}
Loading