Skip to content

Commit 40b66fc

Browse files
[webview_flutter] Adds onHttpError callback to NavigationDelegate to catch HTTP error status codes (flutter#6378)
This is a copy of flutter/packages#3278 since it doesn't allow for contributor access. Fixes flutter#39502
1 parent 1008d9e commit 40b66fc

12 files changed

+104
-5
lines changed

packages/webview_flutter/webview_flutter/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 4.8.0
2+
3+
* Adds `onHttpError` callback to `NavigationDelegate` to catch HTTP error status codes.
4+
15
## 4.7.0
26

37
* Adds support to track scroll position changes.

packages/webview_flutter/webview_flutter/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ controller = WebViewController()
3232
},
3333
onPageStarted: (String url) {},
3434
onPageFinished: (String url) {},
35+
onHttpError: (HttpResponseError error) {},
3536
onWebResourceError: (WebResourceError error) {},
3637
onNavigationRequest: (NavigationRequest request) {
3738
if (request.url.startsWith('https://www.youtube.com/')) {

packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,65 @@ Future<void> main() async {
672672
expect(currentUrl, isNot(contains('youtube.com')));
673673
});
674674

675+
testWidgets('onHttpError', (WidgetTester tester) async {
676+
final Completer<HttpResponseError> errorCompleter =
677+
Completer<HttpResponseError>();
678+
679+
final WebViewController controller = WebViewController();
680+
unawaited(controller.setJavaScriptMode(JavaScriptMode.unrestricted));
681+
682+
final NavigationDelegate delegate = NavigationDelegate(
683+
onHttpError: (HttpResponseError error) {
684+
errorCompleter.complete(error);
685+
},
686+
);
687+
unawaited(controller.setNavigationDelegate(delegate));
688+
689+
unawaited(controller.loadRequest(
690+
Uri.parse('$prefixUrl/favicon.ico'),
691+
));
692+
693+
await tester.pumpWidget(WebViewWidget(controller: controller));
694+
695+
final HttpResponseError error = await errorCompleter.future;
696+
697+
expect(error, isNotNull);
698+
expect(error.response?.statusCode, 404);
699+
});
700+
701+
testWidgets('onHttpError is not called when no HTTP error is received',
702+
(WidgetTester tester) async {
703+
const String testPage = '''
704+
<!DOCTYPE html><html>
705+
</head>
706+
<body>
707+
</body>
708+
</html>
709+
''';
710+
711+
final Completer<HttpResponseError> errorCompleter =
712+
Completer<HttpResponseError>();
713+
final Completer<void> pageFinishCompleter = Completer<void>();
714+
715+
final WebViewController controller = WebViewController();
716+
unawaited(controller.setJavaScriptMode(JavaScriptMode.unrestricted));
717+
718+
final NavigationDelegate delegate = NavigationDelegate(
719+
onPageFinished: pageFinishCompleter.complete,
720+
onHttpError: (HttpResponseError error) {
721+
errorCompleter.complete(error);
722+
},
723+
);
724+
unawaited(controller.setNavigationDelegate(delegate));
725+
726+
unawaited(controller.loadHtmlString(testPage));
727+
728+
await tester.pumpWidget(WebViewWidget(controller: controller));
729+
730+
expect(errorCompleter.future, doesNotComplete);
731+
await pageFinishCompleter.future;
732+
});
733+
675734
testWidgets('supports asynchronous decisions', (WidgetTester tester) async {
676735
Completer<void> pageLoaded = Completer<void>();
677736

packages/webview_flutter/webview_flutter/example/lib/main.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ Page resource error:
170170
debugPrint('allowing navigation to ${request.url}');
171171
return NavigationDecision.navigate;
172172
},
173+
onHttpError: (HttpResponseError error) {
174+
debugPrint('Error occurred on page: ${error.response?.statusCode}');
175+
},
173176
onUrlChange: (UrlChange change) {
174177
debugPrint('url change to ${change.url}');
175178
},

packages/webview_flutter/webview_flutter/example/lib/simple_example.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class _WebViewExampleState extends State<WebViewExample> {
3434
},
3535
onPageStarted: (String url) {},
3636
onPageFinished: (String url) {},
37+
onHttpError: (HttpResponseError error) {},
3738
onWebResourceError: (WebResourceError error) {},
3839
onNavigationRequest: (NavigationRequest request) {
3940
if (request.url.startsWith('https://www.youtube.com/')) {

packages/webview_flutter/webview_flutter/example/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ dependencies:
1717
# The example app is bundled with the plugin so we use a path dependency on
1818
# the parent directory to use the current plugin's version.
1919
path: ../
20-
webview_flutter_android: ^3.15.0
21-
webview_flutter_wkwebview: ^3.12.0
20+
webview_flutter_android: ^3.16.0
21+
webview_flutter_wkwebview: ^3.13.0
2222

2323
dev_dependencies:
2424
build_runner: ^2.1.5

packages/webview_flutter/webview_flutter/example/test/main_test.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,7 @@ class FakeNavigationDelegate extends PlatformNavigationDelegate {
121121
Future<void> setOnHttpAuthRequest(
122122
HttpAuthRequestCallback handler,
123123
) async {}
124+
125+
@override
126+
Future<void> setOnHttpError(HttpResponseErrorCallback onHttpError) async {}
124127
}

packages/webview_flutter/webview_flutter/lib/src/navigation_delegate.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class NavigationDelegate {
5050
void Function(WebResourceError error)? onWebResourceError,
5151
void Function(UrlChange change)? onUrlChange,
5252
void Function(HttpAuthRequest request)? onHttpAuthRequest,
53+
void Function(HttpResponseError error)? onHttpError,
5354
}) : this.fromPlatformCreationParams(
5455
const PlatformNavigationDelegateCreationParams(),
5556
onNavigationRequest: onNavigationRequest,
@@ -59,6 +60,7 @@ class NavigationDelegate {
5960
onWebResourceError: onWebResourceError,
6061
onUrlChange: onUrlChange,
6162
onHttpAuthRequest: onHttpAuthRequest,
63+
onHttpError: onHttpError,
6264
);
6365

6466
/// Constructs a [NavigationDelegate] from creation params for a specific
@@ -102,6 +104,7 @@ class NavigationDelegate {
102104
void Function(WebResourceError error)? onWebResourceError,
103105
void Function(UrlChange change)? onUrlChange,
104106
void Function(HttpAuthRequest request)? onHttpAuthRequest,
107+
void Function(HttpResponseError error)? onHttpError,
105108
}) : this.fromPlatform(
106109
PlatformNavigationDelegate(params),
107110
onNavigationRequest: onNavigationRequest,
@@ -111,6 +114,7 @@ class NavigationDelegate {
111114
onWebResourceError: onWebResourceError,
112115
onUrlChange: onUrlChange,
113116
onHttpAuthRequest: onHttpAuthRequest,
117+
onHttpError: onHttpError,
114118
);
115119

116120
/// Constructs a [NavigationDelegate] from a specific platform implementation.
@@ -125,6 +129,7 @@ class NavigationDelegate {
125129
this.onWebResourceError,
126130
void Function(UrlChange change)? onUrlChange,
127131
HttpAuthRequestCallback? onHttpAuthRequest,
132+
void Function(HttpResponseError error)? onHttpError,
128133
}) {
129134
if (onNavigationRequest != null) {
130135
platform.setOnNavigationRequest(onNavigationRequest!);
@@ -147,6 +152,9 @@ class NavigationDelegate {
147152
if (onHttpAuthRequest != null) {
148153
platform.setOnHttpAuthRequest(onHttpAuthRequest);
149154
}
155+
if (onHttpError != null) {
156+
platform.setOnHttpError(onHttpError);
157+
}
150158
}
151159

152160
/// Implementation of [PlatformNavigationDelegate] for the current platform.

packages/webview_flutter/webview_flutter/lib/webview_flutter.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
export 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'
66
show
77
HttpAuthRequest,
8+
HttpResponseError,
9+
HttpResponseErrorCallback,
810
JavaScriptAlertDialogRequest,
911
JavaScriptConfirmDialogRequest,
1012
JavaScriptConsoleMessage,
@@ -28,6 +30,8 @@ export 'package:webview_flutter_platform_interface/webview_flutter_platform_inte
2830
WebResourceError,
2931
WebResourceErrorCallback,
3032
WebResourceErrorType,
33+
WebResourceRequest,
34+
WebResourceResponse,
3135
WebViewCookie,
3236
WebViewCredential,
3337
WebViewPermissionResourceType,

packages/webview_flutter/webview_flutter/pubspec.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: webview_flutter
22
description: A Flutter plugin that provides a WebView widget on Android and iOS.
33
repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 4.7.0
5+
version: 4.8.0
66

77
environment:
88
sdk: ^3.2.3
@@ -19,9 +19,9 @@ flutter:
1919
dependencies:
2020
flutter:
2121
sdk: flutter
22-
webview_flutter_android: ^3.15.0
22+
webview_flutter_android: ^3.16.0
2323
webview_flutter_platform_interface: ^2.10.0
24-
webview_flutter_wkwebview: ^3.12.0
24+
webview_flutter_wkwebview: ^3.13.0
2525

2626
dev_dependencies:
2727
build_runner: ^2.1.5

packages/webview_flutter/webview_flutter/test/navigation_delegate_test.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,18 @@ void main() {
9999

100100
verify(delegate.platform.setOnHttpAuthRequest(onHttpAuthRequest));
101101
});
102+
103+
test('onHttpError', () async {
104+
WebViewPlatform.instance = TestWebViewPlatform();
105+
106+
void onHttpError(HttpResponseError error) {}
107+
108+
final NavigationDelegate delegate = NavigationDelegate(
109+
onHttpError: onHttpError,
110+
);
111+
112+
verify(delegate.platform.setOnHttpError(onHttpError));
113+
});
102114
});
103115
}
104116

packages/webview_flutter/webview_flutter/test/webview_flutter_export_test.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ void main() {
1313
'ensure webview_flutter.dart exports classes from platform interface',
1414
() {
1515
main_file.HttpAuthRequest;
16+
main_file.HttpResponseError;
17+
main_file.HttpResponseErrorCallback;
1618
main_file.JavaScriptConsoleMessage;
1719
main_file.JavaScriptLogLevel;
1820
main_file.JavaScriptMessage;
@@ -34,6 +36,8 @@ void main() {
3436
main_file.WebViewCookie;
3537
main_file.WebViewCredential;
3638
main_file.WebResourceErrorType;
39+
main_file.WebResourceRequest;
40+
main_file.WebResourceResponse;
3741
main_file.UrlChange;
3842
},
3943
);

0 commit comments

Comments
 (0)