Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit c3ba213

Browse files
authored
[webview_flutter] Fixes bug when onNavigationRequestCallback returns false (#5981)
1 parent 42aebbe commit c3ba213

File tree

5 files changed

+229
-5
lines changed

5 files changed

+229
-5
lines changed

packages/webview_flutter/webview_flutter_android/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.8.13
2+
3+
* Fixes a bug which causes an exception when the `onNavigationRequestCallback` return `false`.
4+
15
## 2.8.12
26

37
* Bumps mockito-inline from 3.11.1 to 4.6.1.

packages/webview_flutter/webview_flutter_android/lib/webview_android_widget.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -652,8 +652,8 @@ class WebViewAndroidWebViewClient extends android_webview.WebViewClient {
652652

653653
if (returnValue is bool && returnValue) {
654654
loadUrl!(url, <String, String>{});
655-
} else {
656-
(returnValue as Future<bool>).then((bool shouldLoadUrl) {
655+
} else if (returnValue is Future<bool>) {
656+
returnValue.then((bool shouldLoadUrl) {
657657
if (shouldLoadUrl) {
658658
loadUrl!(url, <String, String>{});
659659
}
@@ -677,8 +677,8 @@ class WebViewAndroidWebViewClient extends android_webview.WebViewClient {
677677

678678
if (returnValue is bool && returnValue) {
679679
loadUrl!(request.url, <String, String>{});
680-
} else {
681-
(returnValue as Future<bool>).then((bool shouldLoadUrl) {
680+
} else if (returnValue is Future<bool>) {
681+
returnValue.then((bool shouldLoadUrl) {
682682
if (shouldLoadUrl) {
683683
loadUrl!(request.url, <String, String>{});
684684
}

packages/webview_flutter/webview_flutter_android/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: webview_flutter_android
22
description: A Flutter plugin that provides a WebView widget on Android.
33
repository: https://github.com/flutter/plugins/tree/main/packages/webview_flutter/webview_flutter_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 2.8.12
5+
version: 2.8.13
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"

packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.dart

+190
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:async';
56
import 'dart:typed_data';
67

78
import 'package:flutter/widgets.dart';
@@ -24,6 +25,7 @@ import 'webview_android_widget_test.mocks.dart';
2425
android_webview.WebSettings,
2526
android_webview.WebStorage,
2627
android_webview.WebView,
28+
android_webview.WebResourceRequest,
2729
WebViewAndroidDownloadListener,
2830
WebViewAndroidJavaScriptChannel,
2931
WebViewAndroidWebChromeClient,
@@ -843,4 +845,192 @@ void main() {
843845
verify(mockPlatformHostApi.setWebContentsDebuggingEnabled(false));
844846
});
845847
});
848+
849+
group('WebViewAndroidWebViewClient', () {
850+
test(
851+
'urlLoading should call loadUrl when onNavigationRequestCallback returns true',
852+
() {
853+
final Completer<void> completer = Completer<void>();
854+
final WebViewAndroidWebViewClient webViewClient =
855+
WebViewAndroidWebViewClient.handlesNavigation(
856+
onPageStartedCallback: (_) {},
857+
onPageFinishedCallback: (_) {},
858+
onWebResourceErrorCallback: (_) {},
859+
onNavigationRequestCallback: ({
860+
required bool isForMainFrame,
861+
required String url,
862+
}) =>
863+
true,
864+
loadUrl: (String url, Map<String, String>? headers) async {
865+
completer.complete();
866+
});
867+
868+
webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
869+
expect(completer.isCompleted, isTrue);
870+
});
871+
872+
test(
873+
'urlLoading should call loadUrl when onNavigationRequestCallback returns a Future true',
874+
() async {
875+
final Completer<void> completer = Completer<void>();
876+
final WebViewAndroidWebViewClient webViewClient =
877+
WebViewAndroidWebViewClient.handlesNavigation(
878+
onPageStartedCallback: (_) {},
879+
onPageFinishedCallback: (_) {},
880+
onWebResourceErrorCallback: (_) {},
881+
onNavigationRequestCallback: ({
882+
required bool isForMainFrame,
883+
required String url,
884+
}) =>
885+
Future<bool>.value(true),
886+
loadUrl: (String url, Map<String, String>? headers) async {
887+
completer.complete();
888+
});
889+
890+
webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
891+
expect(completer.future, completes);
892+
});
893+
894+
test(
895+
'urlLoading should not call laodUrl when onNavigationRequestCallback returns false',
896+
() async {
897+
final WebViewAndroidWebViewClient webViewClient =
898+
WebViewAndroidWebViewClient.handlesNavigation(
899+
onPageStartedCallback: (_) {},
900+
onPageFinishedCallback: (_) {},
901+
onWebResourceErrorCallback: (_) {},
902+
onNavigationRequestCallback: ({
903+
required bool isForMainFrame,
904+
required String url,
905+
}) =>
906+
false,
907+
loadUrl: (String url, Map<String, String>? headers) async {
908+
fail(
909+
'loadUrl should not be called if onNavigationRequestCallback returns false.');
910+
});
911+
912+
webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
913+
});
914+
915+
test(
916+
'urlLoading should not call loadUrl when onNavigationRequestCallback returns a Future false',
917+
() {
918+
final WebViewAndroidWebViewClient webViewClient =
919+
WebViewAndroidWebViewClient.handlesNavigation(
920+
onPageStartedCallback: (_) {},
921+
onPageFinishedCallback: (_) {},
922+
onWebResourceErrorCallback: (_) {},
923+
onNavigationRequestCallback: ({
924+
required bool isForMainFrame,
925+
required String url,
926+
}) =>
927+
Future<bool>.value(false),
928+
loadUrl: (String url, Map<String, String>? headers) async {
929+
fail(
930+
'loadUrl should not be called if onNavigationRequestCallback returns false.');
931+
});
932+
933+
webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
934+
});
935+
936+
test(
937+
'requestLoading should call loadUrl when onNavigationRequestCallback returns true',
938+
() {
939+
final Completer<void> completer = Completer<void>();
940+
final MockWebResourceRequest mockRequest = MockWebResourceRequest();
941+
when(mockRequest.isForMainFrame).thenReturn(true);
942+
when(mockRequest.url).thenReturn('https://flutter.dev');
943+
final WebViewAndroidWebViewClient webViewClient =
944+
WebViewAndroidWebViewClient.handlesNavigation(
945+
onPageStartedCallback: (_) {},
946+
onPageFinishedCallback: (_) {},
947+
onWebResourceErrorCallback: (_) {},
948+
onNavigationRequestCallback: ({
949+
required bool isForMainFrame,
950+
required String url,
951+
}) =>
952+
true,
953+
loadUrl: (String url, Map<String, String>? headers) async {
954+
expect(url, 'https://flutter.dev');
955+
completer.complete();
956+
});
957+
958+
webViewClient.requestLoading(MockWebView(), mockRequest);
959+
expect(completer.isCompleted, isTrue);
960+
});
961+
962+
test(
963+
'requestLoading should call loadUrl when onNavigationRequestCallback returns a Future true',
964+
() async {
965+
final Completer<void> completer = Completer<void>();
966+
final MockWebResourceRequest mockRequest = MockWebResourceRequest();
967+
when(mockRequest.isForMainFrame).thenReturn(true);
968+
when(mockRequest.url).thenReturn('https://flutter.dev');
969+
final WebViewAndroidWebViewClient webViewClient =
970+
WebViewAndroidWebViewClient.handlesNavigation(
971+
onPageStartedCallback: (_) {},
972+
onPageFinishedCallback: (_) {},
973+
onWebResourceErrorCallback: (_) {},
974+
onNavigationRequestCallback: ({
975+
required bool isForMainFrame,
976+
required String url,
977+
}) =>
978+
Future<bool>.value(true),
979+
loadUrl: (String url, Map<String, String>? headers) async {
980+
expect(url, 'https://flutter.dev');
981+
completer.complete();
982+
});
983+
984+
webViewClient.requestLoading(MockWebView(), mockRequest);
985+
expect(completer.future, completes);
986+
});
987+
988+
test(
989+
'requestLoading should not call loadUrl when onNavigationRequestCallback returns false',
990+
() {
991+
final MockWebResourceRequest mockRequest = MockWebResourceRequest();
992+
when(mockRequest.isForMainFrame).thenReturn(true);
993+
when(mockRequest.url).thenReturn('https://flutter.dev');
994+
final WebViewAndroidWebViewClient webViewClient =
995+
WebViewAndroidWebViewClient.handlesNavigation(
996+
onPageStartedCallback: (_) {},
997+
onPageFinishedCallback: (_) {},
998+
onWebResourceErrorCallback: (_) {},
999+
onNavigationRequestCallback: ({
1000+
required bool isForMainFrame,
1001+
required String url,
1002+
}) =>
1003+
false,
1004+
loadUrl: (String url, Map<String, String>? headers) {
1005+
fail(
1006+
'loadUrl should not be called if onNavigationRequestCallback returns false.');
1007+
});
1008+
1009+
webViewClient.requestLoading(MockWebView(), mockRequest);
1010+
});
1011+
1012+
test(
1013+
'requestLoading should not call loadUrl when onNavigationRequestCallback returns a Future false',
1014+
() {
1015+
final MockWebResourceRequest mockRequest = MockWebResourceRequest();
1016+
when(mockRequest.isForMainFrame).thenReturn(true);
1017+
when(mockRequest.url).thenReturn('https://flutter.dev');
1018+
final WebViewAndroidWebViewClient webViewClient =
1019+
WebViewAndroidWebViewClient.handlesNavigation(
1020+
onPageStartedCallback: (_) {},
1021+
onPageFinishedCallback: (_) {},
1022+
onWebResourceErrorCallback: (_) {},
1023+
onNavigationRequestCallback: ({
1024+
required bool isForMainFrame,
1025+
required String url,
1026+
}) =>
1027+
Future<bool>.value(false),
1028+
loadUrl: (String url, Map<String, String>? headers) {
1029+
fail(
1030+
'loadUrl should not be called if onNavigationRequestCallback returns false.');
1031+
});
1032+
1033+
webViewClient.requestLoading(MockWebView(), mockRequest);
1034+
});
1035+
});
8461036
}

packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.mocks.dart

+30
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,36 @@ class MockWebView extends _i1.Mock implements _i2.WebView {
286286
returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
287287
}
288288

289+
/// A class which mocks [WebResourceRequest].
290+
///
291+
/// See the documentation for Mockito's code generation for more information.
292+
class MockWebResourceRequest extends _i1.Mock
293+
implements _i2.WebResourceRequest {
294+
MockWebResourceRequest() {
295+
_i1.throwOnMissingStub(this);
296+
}
297+
298+
@override
299+
String get url =>
300+
(super.noSuchMethod(Invocation.getter(#url), returnValue: '') as String);
301+
@override
302+
bool get isForMainFrame => (super
303+
.noSuchMethod(Invocation.getter(#isForMainFrame), returnValue: false)
304+
as bool);
305+
@override
306+
bool get hasGesture =>
307+
(super.noSuchMethod(Invocation.getter(#hasGesture), returnValue: false)
308+
as bool);
309+
@override
310+
String get method =>
311+
(super.noSuchMethod(Invocation.getter(#method), returnValue: '')
312+
as String);
313+
@override
314+
Map<String, String> get requestHeaders =>
315+
(super.noSuchMethod(Invocation.getter(#requestHeaders),
316+
returnValue: <String, String>{}) as Map<String, String>);
317+
}
318+
289319
/// A class which mocks [WebViewAndroidDownloadListener].
290320
///
291321
/// See the documentation for Mockito's code generation for more information.

0 commit comments

Comments
 (0)