Skip to content

Commit d01f4ea

Browse files
[webview_flutter_android] [webview_flutter_wkwebview] Adds support for PlatformNavigationDelegate.onUrlChange (#3653)
[webview_flutter_android] [webview_flutter_wkwebview] Adds support for `PlatformNavigationDelegate.onUrlChange`
1 parent 6bf2ea8 commit d01f4ea

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2326
-1216
lines changed

packages/webview_flutter/webview_flutter_android/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 3.5.0
22

3+
* Adds support for `PlatformNavigationDelegate.onUrlChange`.
34
* Bumps androidx.webkit:webkit from 1.6.0 to 1.6.1.
45
* Fixes common typos in tests and documentation.
56

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java

Lines changed: 360 additions & 623 deletions
Large diffs are not rendered by default.

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import android.webkit.WebResourceRequest;
1111
import android.webkit.WebView;
1212
import android.webkit.WebViewClient;
13+
import androidx.annotation.NonNull;
1314
import androidx.annotation.RequiresApi;
1415
import androidx.webkit.WebResourceErrorCompat;
1516
import io.flutter.plugin.common.BinaryMessenger;
@@ -202,6 +203,21 @@ public void urlLoading(
202203
urlLoading(getIdentifierForClient(webViewClient), webViewIdentifier, urlArg, callback);
203204
}
204205

206+
/** Passes arguments from {@link WebViewClient#doUpdateVisitedHistory} to Dart. */
207+
public void doUpdateVisitedHistory(
208+
@NonNull WebViewClient webViewClient,
209+
@NonNull WebView webView,
210+
@NonNull String url,
211+
boolean isReload,
212+
@NonNull Reply<Void> callback) {
213+
webViewFlutterApi.create(webView, reply -> {});
214+
215+
final Long webViewIdentifier =
216+
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView));
217+
doUpdateVisitedHistory(
218+
getIdentifierForClient(webViewClient), webViewIdentifier, url, isReload, callback);
219+
}
220+
205221
private long getIdentifierForClient(WebViewClient webViewClient) {
206222
final Long identifier = instanceManager.getIdentifierForStrongReference(webViewClient);
207223
if (identifier == null) {

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
8282
return returnValueForShouldOverrideUrlLoading;
8383
}
8484

85+
@Override
86+
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
87+
flutterApi.doUpdateVisitedHistory(this, view, url, isReload, reply -> {});
88+
}
89+
8590
@Override
8691
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
8792
// Deliberately empty. Occasionally the webview will mark events as having failed to be
@@ -155,7 +160,12 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
155160
}
156161

157162
@Override
158-
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
163+
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
164+
flutterApi.doUpdateVisitedHistory(this, view, url, isReload, reply -> {});
165+
}
166+
167+
@Override
168+
public void onUnhandledKeyEvent(@NonNull WebView view, @NonNull KeyEvent event) {
159169
// Deliberately empty. Occasionally the webview will mark events as having failed to be
160170
// handled even though they were handled. We don't want to propagate those as they're not
161171
// truly lost.
@@ -175,7 +185,8 @@ public static class WebViewClientCreator {
175185
* @param flutterApi handles sending messages to Dart
176186
* @return the created {@link WebViewClient}
177187
*/
178-
public WebViewClient createWebViewClient(WebViewClientFlutterApiImpl flutterApi) {
188+
@NonNull
189+
public WebViewClient createWebViewClient(@NonNull WebViewClientFlutterApiImpl flutterApi) {
179190
// WebViewClientCompat is used to get
180191
// shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
181192
// invoked by the webview on older Android devices, without it pages that use iframes will

packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import android.webkit.WebResourceRequest;
1616
import android.webkit.WebView;
1717
import android.webkit.WebViewClient;
18+
import androidx.annotation.NonNull;
1819
import io.flutter.plugins.webviewflutter.WebViewClientHostApiImpl.WebViewClientCompatImpl;
1920
import io.flutter.plugins.webviewflutter.WebViewClientHostApiImpl.WebViewClientCreator;
2021
import java.util.HashMap;
@@ -111,8 +112,10 @@ public void setReturnValueForShouldOverrideUrlLoading() {
111112
new WebViewClientHostApiImpl(
112113
instanceManager,
113114
new WebViewClientCreator() {
115+
@NonNull
114116
@Override
115-
public WebViewClient createWebViewClient(WebViewClientFlutterApiImpl flutterApi) {
117+
public WebViewClient createWebViewClient(
118+
@NonNull WebViewClientFlutterApiImpl flutterApi) {
116119
return mockWebViewClient;
117120
}
118121
},
@@ -123,4 +126,12 @@ public WebViewClient createWebViewClient(WebViewClientFlutterApiImpl flutterApi)
123126

124127
verify(mockWebViewClient).setReturnValueForShouldOverrideUrlLoading(false);
125128
}
129+
130+
@Test
131+
public void doUpdateVisitedHistory() {
132+
webViewClient.doUpdateVisitedHistory(mockWebView, "https://www.google.com", true);
133+
verify(mockFlutterApi)
134+
.doUpdateVisitedHistory(
135+
eq(webViewClient), eq(mockWebView), eq("https://www.google.com"), eq(true), any());
136+
}
126137
}

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

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,81 @@ Future<void> main() async {
942942
final String? currentUrl = await controller.currentUrl();
943943
expect(currentUrl, secondaryUrl);
944944
});
945+
946+
testWidgets('can receive url changes', (WidgetTester tester) async {
947+
final Completer<void> pageLoaded = Completer<void>();
948+
949+
final PlatformNavigationDelegate navigationDelegate =
950+
PlatformNavigationDelegate(
951+
const PlatformNavigationDelegateCreationParams(),
952+
)..setOnPageFinished((_) => pageLoaded.complete());
953+
954+
final PlatformWebViewController controller = PlatformWebViewController(
955+
const PlatformWebViewControllerCreationParams(),
956+
)
957+
..setJavaScriptMode(JavaScriptMode.unrestricted)
958+
..setPlatformNavigationDelegate(navigationDelegate)
959+
..loadRequest(LoadRequestParams(uri: Uri.parse(blankPageEncoded)));
960+
961+
await tester.pumpWidget(Builder(
962+
builder: (BuildContext context) {
963+
return PlatformWebViewWidget(
964+
PlatformWebViewWidgetCreationParams(controller: controller),
965+
).build(context);
966+
},
967+
));
968+
969+
await pageLoaded.future;
970+
await navigationDelegate.setOnPageFinished((_) {});
971+
972+
final Completer<String> urlChangeCompleter = Completer<String>();
973+
await navigationDelegate.setOnUrlChange((UrlChange change) {
974+
urlChangeCompleter.complete(change.url);
975+
});
976+
977+
await controller.runJavaScript('location.href = "$primaryUrl"');
978+
979+
await expectLater(urlChangeCompleter.future, completion(primaryUrl));
980+
});
981+
982+
testWidgets('can receive updates to history state',
983+
(WidgetTester tester) async {
984+
final Completer<void> pageLoaded = Completer<void>();
985+
986+
final PlatformNavigationDelegate navigationDelegate =
987+
PlatformNavigationDelegate(
988+
const PlatformNavigationDelegateCreationParams(),
989+
)..setOnPageFinished((_) => pageLoaded.complete());
990+
991+
final PlatformWebViewController controller = PlatformWebViewController(
992+
const PlatformWebViewControllerCreationParams(),
993+
)
994+
..setJavaScriptMode(JavaScriptMode.unrestricted)
995+
..setPlatformNavigationDelegate(navigationDelegate)
996+
..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
997+
998+
await tester.pumpWidget(Builder(
999+
builder: (BuildContext context) {
1000+
return PlatformWebViewWidget(
1001+
PlatformWebViewWidgetCreationParams(controller: controller),
1002+
).build(context);
1003+
},
1004+
));
1005+
1006+
await pageLoaded.future;
1007+
await navigationDelegate.setOnPageFinished((_) {});
1008+
1009+
final Completer<String> urlChangeCompleter = Completer<String>();
1010+
await navigationDelegate.setOnUrlChange((UrlChange change) {
1011+
urlChangeCompleter.complete(change.url);
1012+
});
1013+
1014+
await controller.runJavaScript(
1015+
'window.history.pushState({}, "", "secondary.txt");',
1016+
);
1017+
1018+
await expectLater(urlChangeCompleter.future, completion(secondaryUrl));
1019+
});
9451020
});
9461021

9471022
testWidgets('target _blank opens in same window',

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ Page resource error:
123123
}
124124
debugPrint('allowing navigation to ${request.url}');
125125
return NavigationDecision.navigate;
126+
})
127+
..setOnUrlChange((UrlChange change) {
128+
debugPrint('url change to ${change.url}');
126129
}),
127130
)
128131
..addJavaScriptChannel(JavaScriptChannelParams(

packages/webview_flutter/webview_flutter_android/example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ dependencies:
1919
# The example app is bundled with the plugin so we use a path dependency on
2020
# the parent directory to use the current plugin's version.
2121
path: ../
22-
webview_flutter_platform_interface: ^2.0.0
22+
webview_flutter_platform_interface: ^2.1.0
2323

2424
dev_dependencies:
2525
espresso: ^0.2.0

packages/webview_flutter/webview_flutter_android/lib/src/android_proxy.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class AndroidWebViewProxy {
5858
android_webview.WebResourceRequest request,
5959
)? requestLoading,
6060
void Function(android_webview.WebView webView, String url)? urlLoading,
61+
void Function(android_webview.WebView webView, String url, bool isReload)?
62+
doUpdateVisitedHistory,
6163
}) createAndroidWebViewClient;
6264

6365
/// Constructs a [android_webview.FlutterAssetManager].

packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ class WebViewClient extends JavaObject {
677677
@Deprecated('Only called on Android version < 23.') this.onReceivedError,
678678
this.requestLoading,
679679
this.urlLoading,
680+
this.doUpdateVisitedHistory,
680681
@visibleForTesting super.binaryMessenger,
681682
@visibleForTesting super.instanceManager,
682683
}) : super.detached() {
@@ -696,6 +697,7 @@ class WebViewClient extends JavaObject {
696697
@Deprecated('Only called on Android version < 23.') this.onReceivedError,
697698
this.requestLoading,
698699
this.urlLoading,
700+
this.doUpdateVisitedHistory,
699701
super.binaryMessenger,
700702
super.instanceManager,
701703
}) : super.detached();
@@ -840,6 +842,10 @@ class WebViewClient extends JavaObject {
840842
/// indicates whether the [WebView] loaded the URL.
841843
final void Function(WebView webView, String url)? urlLoading;
842844

845+
/// Notify the host application to update its visited links database.
846+
final void Function(WebView webView, String url, bool isReload)?
847+
doUpdateVisitedHistory;
848+
843849
/// Sets the required synchronous return value for the Java method,
844850
/// `WebViewClient.shouldOverrideUrlLoading(...)`.
845851
///
@@ -867,6 +873,7 @@ class WebViewClient extends JavaObject {
867873
onReceivedError: onReceivedError,
868874
requestLoading: requestLoading,
869875
urlLoading: urlLoading,
876+
doUpdateVisitedHistory: doUpdateVisitedHistory,
870877
binaryMessenger: _api.binaryMessenger,
871878
instanceManager: _api.instanceManager,
872879
);

packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2013 The Flutter Authors. All rights reserved.
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
4-
// Autogenerated from Pigeon (v9.0.5), do not edit directly.
4+
// Autogenerated from Pigeon (v9.2.3), do not edit directly.
55
// See also: https://pub.dev/packages/pigeon
66
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
77

@@ -1514,6 +1514,9 @@ abstract class WebViewClientFlutterApi {
15141514

15151515
void urlLoading(int instanceId, int webViewInstanceId, String url);
15161516

1517+
void doUpdateVisitedHistory(
1518+
int instanceId, int webViewInstanceId, String url, bool isReload);
1519+
15171520
static void setup(WebViewClientFlutterApi? api,
15181521
{BinaryMessenger? binaryMessenger}) {
15191522
{
@@ -1682,6 +1685,36 @@ abstract class WebViewClientFlutterApi {
16821685
});
16831686
}
16841687
}
1688+
{
1689+
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
1690+
'dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory',
1691+
codec,
1692+
binaryMessenger: binaryMessenger);
1693+
if (api == null) {
1694+
channel.setMessageHandler(null);
1695+
} else {
1696+
channel.setMessageHandler((Object? message) async {
1697+
assert(message != null,
1698+
'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null.');
1699+
final List<Object?> args = (message as List<Object?>?)!;
1700+
final int? arg_instanceId = (args[0] as int?);
1701+
assert(arg_instanceId != null,
1702+
'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null int.');
1703+
final int? arg_webViewInstanceId = (args[1] as int?);
1704+
assert(arg_webViewInstanceId != null,
1705+
'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null int.');
1706+
final String? arg_url = (args[2] as String?);
1707+
assert(arg_url != null,
1708+
'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null String.');
1709+
final bool? arg_isReload = (args[3] as bool?);
1710+
assert(arg_isReload != null,
1711+
'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null bool.');
1712+
api.doUpdateVisitedHistory(
1713+
arg_instanceId!, arg_webViewInstanceId!, arg_url!, arg_isReload!);
1714+
return;
1715+
});
1716+
}
1717+
}
16851718
}
16861719
}
16871720

packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,30 @@ class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi {
754754
instance.urlLoading!(webViewInstance!, url);
755755
}
756756
}
757+
758+
@override
759+
void doUpdateVisitedHistory(
760+
int instanceId,
761+
int webViewInstanceId,
762+
String url,
763+
bool isReload,
764+
) {
765+
final WebViewClient? instance = instanceManager
766+
.getInstanceWithWeakReference(instanceId) as WebViewClient?;
767+
final WebView? webViewInstance = instanceManager
768+
.getInstanceWithWeakReference(webViewInstanceId) as WebView?;
769+
assert(
770+
instance != null,
771+
'InstanceManager does not contain an WebViewClient with instanceId: $instanceId',
772+
);
773+
assert(
774+
webViewInstance != null,
775+
'InstanceManager does not contain an WebView with instanceId: $webViewInstanceId',
776+
);
777+
if (instance!.doUpdateVisitedHistory != null) {
778+
instance.doUpdateVisitedHistory!(webViewInstance!, url, isReload);
779+
}
780+
}
757781
}
758782

759783
/// Host api implementation for [DownloadListener].

0 commit comments

Comments
 (0)