Skip to content

Commit

Permalink
[webview_flutter] Adds onHttpError callback to NavigationDelegate to …
Browse files Browse the repository at this point in the history
…catch HTTP error status codes (#6378)

This is a copy of #3278 since it doesn't allow for contributor access.

Fixes flutter/flutter#39502
  • Loading branch information
bparrishMines authored May 24, 2024
1 parent 1008d9e commit 40b66fc
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 5 deletions.
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.8.0

* Adds `onHttpError` callback to `NavigationDelegate` to catch HTTP error status codes.

## 4.7.0

* Adds support to track scroll position changes.
Expand Down
1 change: 1 addition & 0 deletions packages/webview_flutter/webview_flutter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ controller = WebViewController()
},
onPageStarted: (String url) {},
onPageFinished: (String url) {},
onHttpError: (HttpResponseError error) {},
onWebResourceError: (WebResourceError error) {},
onNavigationRequest: (NavigationRequest request) {
if (request.url.startsWith('https://www.youtube.com/')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,65 @@ Future<void> main() async {
expect(currentUrl, isNot(contains('youtube.com')));
});

testWidgets('onHttpError', (WidgetTester tester) async {
final Completer<HttpResponseError> errorCompleter =
Completer<HttpResponseError>();

final WebViewController controller = WebViewController();
unawaited(controller.setJavaScriptMode(JavaScriptMode.unrestricted));

final NavigationDelegate delegate = NavigationDelegate(
onHttpError: (HttpResponseError error) {
errorCompleter.complete(error);
},
);
unawaited(controller.setNavigationDelegate(delegate));

unawaited(controller.loadRequest(
Uri.parse('$prefixUrl/favicon.ico'),
));

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

final HttpResponseError error = await errorCompleter.future;

expect(error, isNotNull);
expect(error.response?.statusCode, 404);
});

testWidgets('onHttpError is not called when no HTTP error is received',
(WidgetTester tester) async {
const String testPage = '''
<!DOCTYPE html><html>
</head>
<body>
</body>
</html>
''';

final Completer<HttpResponseError> errorCompleter =
Completer<HttpResponseError>();
final Completer<void> pageFinishCompleter = Completer<void>();

final WebViewController controller = WebViewController();
unawaited(controller.setJavaScriptMode(JavaScriptMode.unrestricted));

final NavigationDelegate delegate = NavigationDelegate(
onPageFinished: pageFinishCompleter.complete,
onHttpError: (HttpResponseError error) {
errorCompleter.complete(error);
},
);
unawaited(controller.setNavigationDelegate(delegate));

unawaited(controller.loadHtmlString(testPage));

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

expect(errorCompleter.future, doesNotComplete);
await pageFinishCompleter.future;
});

testWidgets('supports asynchronous decisions', (WidgetTester tester) async {
Completer<void> pageLoaded = Completer<void>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ Page resource error:
debugPrint('allowing navigation to ${request.url}');
return NavigationDecision.navigate;
},
onHttpError: (HttpResponseError error) {
debugPrint('Error occurred on page: ${error.response?.statusCode}');
},
onUrlChange: (UrlChange change) {
debugPrint('url change to ${change.url}');
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class _WebViewExampleState extends State<WebViewExample> {
},
onPageStarted: (String url) {},
onPageFinished: (String url) {},
onHttpError: (HttpResponseError error) {},
onWebResourceError: (WebResourceError error) {},
onNavigationRequest: (NavigationRequest request) {
if (request.url.startsWith('https://www.youtube.com/')) {
Expand Down
4 changes: 2 additions & 2 deletions packages/webview_flutter/webview_flutter/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ dependencies:
# 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.15.0
webview_flutter_wkwebview: ^3.12.0
webview_flutter_android: ^3.16.0
webview_flutter_wkwebview: ^3.13.0

dev_dependencies:
build_runner: ^2.1.5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,7 @@ class FakeNavigationDelegate extends PlatformNavigationDelegate {
Future<void> setOnHttpAuthRequest(
HttpAuthRequestCallback handler,
) async {}

@override
Future<void> setOnHttpError(HttpResponseErrorCallback onHttpError) async {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class NavigationDelegate {
void Function(WebResourceError error)? onWebResourceError,
void Function(UrlChange change)? onUrlChange,
void Function(HttpAuthRequest request)? onHttpAuthRequest,
void Function(HttpResponseError error)? onHttpError,
}) : this.fromPlatformCreationParams(
const PlatformNavigationDelegateCreationParams(),
onNavigationRequest: onNavigationRequest,
Expand All @@ -59,6 +60,7 @@ class NavigationDelegate {
onWebResourceError: onWebResourceError,
onUrlChange: onUrlChange,
onHttpAuthRequest: onHttpAuthRequest,
onHttpError: onHttpError,
);

/// Constructs a [NavigationDelegate] from creation params for a specific
Expand Down Expand Up @@ -102,6 +104,7 @@ class NavigationDelegate {
void Function(WebResourceError error)? onWebResourceError,
void Function(UrlChange change)? onUrlChange,
void Function(HttpAuthRequest request)? onHttpAuthRequest,
void Function(HttpResponseError error)? onHttpError,
}) : this.fromPlatform(
PlatformNavigationDelegate(params),
onNavigationRequest: onNavigationRequest,
Expand All @@ -111,6 +114,7 @@ class NavigationDelegate {
onWebResourceError: onWebResourceError,
onUrlChange: onUrlChange,
onHttpAuthRequest: onHttpAuthRequest,
onHttpError: onHttpError,
);

/// Constructs a [NavigationDelegate] from a specific platform implementation.
Expand All @@ -125,6 +129,7 @@ class NavigationDelegate {
this.onWebResourceError,
void Function(UrlChange change)? onUrlChange,
HttpAuthRequestCallback? onHttpAuthRequest,
void Function(HttpResponseError error)? onHttpError,
}) {
if (onNavigationRequest != null) {
platform.setOnNavigationRequest(onNavigationRequest!);
Expand All @@ -147,6 +152,9 @@ class NavigationDelegate {
if (onHttpAuthRequest != null) {
platform.setOnHttpAuthRequest(onHttpAuthRequest);
}
if (onHttpError != null) {
platform.setOnHttpError(onHttpError);
}
}

/// Implementation of [PlatformNavigationDelegate] for the current platform.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
export 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'
show
HttpAuthRequest,
HttpResponseError,
HttpResponseErrorCallback,
JavaScriptAlertDialogRequest,
JavaScriptConfirmDialogRequest,
JavaScriptConsoleMessage,
Expand All @@ -28,6 +30,8 @@ export 'package:webview_flutter_platform_interface/webview_flutter_platform_inte
WebResourceError,
WebResourceErrorCallback,
WebResourceErrorType,
WebResourceRequest,
WebResourceResponse,
WebViewCookie,
WebViewCredential,
WebViewPermissionResourceType,
Expand Down
6 changes: 3 additions & 3 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.7.0
version: 4.8.0

environment:
sdk: ^3.2.3
Expand All @@ -19,9 +19,9 @@ flutter:
dependencies:
flutter:
sdk: flutter
webview_flutter_android: ^3.15.0
webview_flutter_android: ^3.16.0
webview_flutter_platform_interface: ^2.10.0
webview_flutter_wkwebview: ^3.12.0
webview_flutter_wkwebview: ^3.13.0

dev_dependencies:
build_runner: ^2.1.5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ void main() {

verify(delegate.platform.setOnHttpAuthRequest(onHttpAuthRequest));
});

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

void onHttpError(HttpResponseError error) {}

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

verify(delegate.platform.setOnHttpError(onHttpError));
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ void main() {
'ensure webview_flutter.dart exports classes from platform interface',
() {
main_file.HttpAuthRequest;
main_file.HttpResponseError;
main_file.HttpResponseErrorCallback;
main_file.JavaScriptConsoleMessage;
main_file.JavaScriptLogLevel;
main_file.JavaScriptMessage;
Expand All @@ -34,6 +36,8 @@ void main() {
main_file.WebViewCookie;
main_file.WebViewCredential;
main_file.WebResourceErrorType;
main_file.WebResourceRequest;
main_file.WebResourceResponse;
main_file.UrlChange;
},
);
Expand Down

0 comments on commit 40b66fc

Please sign in to comment.