Skip to content

Commit

Permalink
[webview_flutter_android] [webview_flutter_wkwebview] Adds support fo…
Browse files Browse the repository at this point in the history
…r `PlatformNavigationDelegate.onUrlChange` (flutter#3653)

[webview_flutter_android] [webview_flutter_wkwebview] Adds support for `PlatformNavigationDelegate.onUrlChange`
  • Loading branch information
bparrishMines authored Apr 12, 2023
1 parent 6bf2ea8 commit d01f4ea
Show file tree
Hide file tree
Showing 45 changed files with 2,326 additions and 1,216 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## NEXT
## 3.5.0

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

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.webkit.WebResourceErrorCompat;
import io.flutter.plugin.common.BinaryMessenger;
Expand Down Expand Up @@ -202,6 +203,21 @@ public void urlLoading(
urlLoading(getIdentifierForClient(webViewClient), webViewIdentifier, urlArg, callback);
}

/** Passes arguments from {@link WebViewClient#doUpdateVisitedHistory} to Dart. */
public void doUpdateVisitedHistory(
@NonNull WebViewClient webViewClient,
@NonNull WebView webView,
@NonNull String url,
boolean isReload,
@NonNull Reply<Void> callback) {
webViewFlutterApi.create(webView, reply -> {});

final Long webViewIdentifier =
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView));
doUpdateVisitedHistory(
getIdentifierForClient(webViewClient), webViewIdentifier, url, isReload, callback);
}

private long getIdentifierForClient(WebViewClient webViewClient) {
final Long identifier = instanceManager.getIdentifierForStrongReference(webViewClient);
if (identifier == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
return returnValueForShouldOverrideUrlLoading;
}

@Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
flutterApi.doUpdateVisitedHistory(this, view, url, isReload, reply -> {});
}

@Override
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
// Deliberately empty. Occasionally the webview will mark events as having failed to be
Expand Down Expand Up @@ -155,7 +160,12 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
}

@Override
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
flutterApi.doUpdateVisitedHistory(this, view, url, isReload, reply -> {});
}

@Override
public void onUnhandledKeyEvent(@NonNull WebView view, @NonNull KeyEvent event) {
// Deliberately empty. Occasionally the webview will mark events as having failed to be
// handled even though they were handled. We don't want to propagate those as they're not
// truly lost.
Expand All @@ -175,7 +185,8 @@ public static class WebViewClientCreator {
* @param flutterApi handles sending messages to Dart
* @return the created {@link WebViewClient}
*/
public WebViewClient createWebViewClient(WebViewClientFlutterApiImpl flutterApi) {
@NonNull
public WebViewClient createWebViewClient(@NonNull WebViewClientFlutterApiImpl flutterApi) {
// WebViewClientCompat is used to get
// shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
// invoked by the webview on older Android devices, without it pages that use iframes will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import io.flutter.plugins.webviewflutter.WebViewClientHostApiImpl.WebViewClientCompatImpl;
import io.flutter.plugins.webviewflutter.WebViewClientHostApiImpl.WebViewClientCreator;
import java.util.HashMap;
Expand Down Expand Up @@ -111,8 +112,10 @@ public void setReturnValueForShouldOverrideUrlLoading() {
new WebViewClientHostApiImpl(
instanceManager,
new WebViewClientCreator() {
@NonNull
@Override
public WebViewClient createWebViewClient(WebViewClientFlutterApiImpl flutterApi) {
public WebViewClient createWebViewClient(
@NonNull WebViewClientFlutterApiImpl flutterApi) {
return mockWebViewClient;
}
},
Expand All @@ -123,4 +126,12 @@ public WebViewClient createWebViewClient(WebViewClientFlutterApiImpl flutterApi)

verify(mockWebViewClient).setReturnValueForShouldOverrideUrlLoading(false);
}

@Test
public void doUpdateVisitedHistory() {
webViewClient.doUpdateVisitedHistory(mockWebView, "https://www.google.com", true);
verify(mockFlutterApi)
.doUpdateVisitedHistory(
eq(webViewClient), eq(mockWebView), eq("https://www.google.com"), eq(true), any());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,81 @@ Future<void> main() async {
final String? currentUrl = await controller.currentUrl();
expect(currentUrl, secondaryUrl);
});

testWidgets('can receive url changes', (WidgetTester tester) async {
final Completer<void> pageLoaded = Completer<void>();

final PlatformNavigationDelegate navigationDelegate =
PlatformNavigationDelegate(
const PlatformNavigationDelegateCreationParams(),
)..setOnPageFinished((_) => pageLoaded.complete());

final PlatformWebViewController controller = PlatformWebViewController(
const PlatformWebViewControllerCreationParams(),
)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setPlatformNavigationDelegate(navigationDelegate)
..loadRequest(LoadRequestParams(uri: Uri.parse(blankPageEncoded)));

await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageLoaded.future;
await navigationDelegate.setOnPageFinished((_) {});

final Completer<String> urlChangeCompleter = Completer<String>();
await navigationDelegate.setOnUrlChange((UrlChange change) {
urlChangeCompleter.complete(change.url);
});

await controller.runJavaScript('location.href = "$primaryUrl"');

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

testWidgets('can receive updates to history state',
(WidgetTester tester) async {
final Completer<void> pageLoaded = Completer<void>();

final PlatformNavigationDelegate navigationDelegate =
PlatformNavigationDelegate(
const PlatformNavigationDelegateCreationParams(),
)..setOnPageFinished((_) => pageLoaded.complete());

final PlatformWebViewController controller = PlatformWebViewController(
const PlatformWebViewControllerCreationParams(),
)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setPlatformNavigationDelegate(navigationDelegate)
..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));

await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageLoaded.future;
await navigationDelegate.setOnPageFinished((_) {});

final Completer<String> urlChangeCompleter = Completer<String>();
await navigationDelegate.setOnUrlChange((UrlChange change) {
urlChangeCompleter.complete(change.url);
});

await controller.runJavaScript(
'window.history.pushState({}, "", "secondary.txt");',
);

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

testWidgets('target _blank opens in same window',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ Page resource error:
}
debugPrint('allowing navigation to ${request.url}');
return NavigationDecision.navigate;
})
..setOnUrlChange((UrlChange change) {
debugPrint('url change to ${change.url}');
}),
)
..addJavaScriptChannel(JavaScriptChannelParams(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ 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_platform_interface: ^2.0.0
webview_flutter_platform_interface: ^2.1.0

dev_dependencies:
espresso: ^0.2.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ class AndroidWebViewProxy {
android_webview.WebResourceRequest request,
)? requestLoading,
void Function(android_webview.WebView webView, String url)? urlLoading,
void Function(android_webview.WebView webView, String url, bool isReload)?
doUpdateVisitedHistory,
}) createAndroidWebViewClient;

/// Constructs a [android_webview.FlutterAssetManager].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ class WebViewClient extends JavaObject {
@Deprecated('Only called on Android version < 23.') this.onReceivedError,
this.requestLoading,
this.urlLoading,
this.doUpdateVisitedHistory,
@visibleForTesting super.binaryMessenger,
@visibleForTesting super.instanceManager,
}) : super.detached() {
Expand All @@ -696,6 +697,7 @@ class WebViewClient extends JavaObject {
@Deprecated('Only called on Android version < 23.') this.onReceivedError,
this.requestLoading,
this.urlLoading,
this.doUpdateVisitedHistory,
super.binaryMessenger,
super.instanceManager,
}) : super.detached();
Expand Down Expand Up @@ -840,6 +842,10 @@ class WebViewClient extends JavaObject {
/// indicates whether the [WebView] loaded the URL.
final void Function(WebView webView, String url)? urlLoading;

/// Notify the host application to update its visited links database.
final void Function(WebView webView, String url, bool isReload)?
doUpdateVisitedHistory;

/// Sets the required synchronous return value for the Java method,
/// `WebViewClient.shouldOverrideUrlLoading(...)`.
///
Expand Down Expand Up @@ -867,6 +873,7 @@ class WebViewClient extends JavaObject {
onReceivedError: onReceivedError,
requestLoading: requestLoading,
urlLoading: urlLoading,
doUpdateVisitedHistory: doUpdateVisitedHistory,
binaryMessenger: _api.binaryMessenger,
instanceManager: _api.instanceManager,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Autogenerated from Pigeon (v9.0.5), do not edit directly.
// Autogenerated from Pigeon (v9.2.3), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// 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

Expand Down Expand Up @@ -1514,6 +1514,9 @@ abstract class WebViewClientFlutterApi {

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

void doUpdateVisitedHistory(
int instanceId, int webViewInstanceId, String url, bool isReload);

static void setup(WebViewClientFlutterApi? api,
{BinaryMessenger? binaryMessenger}) {
{
Expand Down Expand Up @@ -1682,6 +1685,36 @@ abstract class WebViewClientFlutterApi {
});
}
}
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory',
codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null.');
final List<Object?> args = (message as List<Object?>?)!;
final int? arg_instanceId = (args[0] as int?);
assert(arg_instanceId != null,
'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null int.');
final int? arg_webViewInstanceId = (args[1] as int?);
assert(arg_webViewInstanceId != null,
'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null int.');
final String? arg_url = (args[2] as String?);
assert(arg_url != null,
'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null String.');
final bool? arg_isReload = (args[3] as bool?);
assert(arg_isReload != null,
'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null bool.');
api.doUpdateVisitedHistory(
arg_instanceId!, arg_webViewInstanceId!, arg_url!, arg_isReload!);
return;
});
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,30 @@ class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi {
instance.urlLoading!(webViewInstance!, url);
}
}

@override
void doUpdateVisitedHistory(
int instanceId,
int webViewInstanceId,
String url,
bool isReload,
) {
final WebViewClient? instance = instanceManager
.getInstanceWithWeakReference(instanceId) as WebViewClient?;
final WebView? webViewInstance = instanceManager
.getInstanceWithWeakReference(webViewInstanceId) as WebView?;
assert(
instance != null,
'InstanceManager does not contain an WebViewClient with instanceId: $instanceId',
);
assert(
webViewInstance != null,
'InstanceManager does not contain an WebView with instanceId: $webViewInstanceId',
);
if (instance!.doUpdateVisitedHistory != null) {
instance.doUpdateVisitedHistory!(webViewInstance!, url, isReload);
}
}
}

/// Host api implementation for [DownloadListener].
Expand Down
Loading

0 comments on commit d01f4ea

Please sign in to comment.