Thanks to visit codestin.com
Credit goes to github.com

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

[webview_flutter] Adds support to listen to url changes #7113

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.1.0

* Adds support to track url changes. See `NavigationDelegate(onUrlChange)`.

## 4.0.3

* Updates example code for `use_build_context_synchronously` lint.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,32 @@ 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 WebViewController controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(NavigationDelegate(
onPageFinished: (_) => pageLoaded.complete(),
))
..loadRequest(Uri.parse(blankPageEncoded));

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

await pageLoaded.future;

final Completer<String> urlChangeCompleter = Completer<String>();
await controller.setNavigationDelegate(NavigationDelegate(
onUrlChange: (UrlChange change) {
urlChangeCompleter.complete(change.url);
},
));

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

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

testWidgets('target _blank opens in same window',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ Page resource error:
debugPrint('allowing navigation to ${request.url}');
return NavigationDecision.navigate;
},
onUrlChange: (UrlChange change) {
debugPrint('url change to ${change.url}');
},
),
)
..addJavaScriptChannel(
Expand Down
10 changes: 10 additions & 0 deletions packages/webview_flutter/webview_flutter/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,13 @@ flutter:
- assets/sample_video.mp4
- assets/www/index.html
- assets/www/styles/style.css


# FOR TESTING ONLY. DO NOT MERGE.
dependency_overrides:
webview_flutter_android:
path: ../../../webview_flutter/webview_flutter_android
webview_flutter_platform_interface:
path: ../../../webview_flutter/webview_flutter_platform_interface
webview_flutter_wkwebview:
path: ../../../webview_flutter/webview_flutter_wkwebview
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,7 @@ class FakeNavigationDelegate extends PlatformNavigationDelegate {
Future<void> setOnWebResourceError(
WebResourceErrorCallback onWebResourceError,
) async {}

@override
Future<void> setOnUrlChange(UrlChangeCallback onUrlChange) async {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,33 @@ import 'webview_controller.dart';
/// See [WebViewController.setNavigationDelegate].
class NavigationDelegate {
/// Constructs a [NavigationDelegate].
///
///
/// {@template webview_fluttter.navigation_delegate}
/// `onUrlChange`: invoked when the underlying web view changes to a new url.
/// {@endtemplate}
NavigationDelegate({
FutureOr<NavigationDecision> Function(NavigationRequest request)?
onNavigationRequest,
void Function(String url)? onPageStarted,
void Function(String url)? onPageFinished,
void Function(int progress)? onProgress,
void Function(WebResourceError error)? onWebResourceError,
void Function(UrlChange change)? onUrlChange,
}) : this.fromPlatformCreationParams(
const PlatformNavigationDelegateCreationParams(),
onNavigationRequest: onNavigationRequest,
onPageStarted: onPageStarted,
onPageFinished: onPageFinished,
onProgress: onProgress,
onWebResourceError: onWebResourceError,
onUrlChange: onUrlChange,
);

/// Constructs a [NavigationDelegate] from creation params for a specific
/// platform.
///
/// {@macro webview_fluttter.navigation_delegate}
NavigationDelegate.fromPlatformCreationParams(
PlatformNavigationDelegateCreationParams params, {
FutureOr<NavigationDecision> Function(NavigationRequest request)?
Expand All @@ -40,23 +49,28 @@ class NavigationDelegate {
void Function(String url)? onPageFinished,
void Function(int progress)? onProgress,
void Function(WebResourceError error)? onWebResourceError,
void Function(UrlChange change)? onUrlChange,
}) : this.fromPlatform(
PlatformNavigationDelegate(params),
onNavigationRequest: onNavigationRequest,
onPageStarted: onPageStarted,
onPageFinished: onPageFinished,
onProgress: onProgress,
onWebResourceError: onWebResourceError,
onUrlChange: onUrlChange,
);

/// Constructs a [NavigationDelegate] from a specific platform implementation.
///
/// {@macro webview_fluttter.navigation_delegate}
NavigationDelegate.fromPlatform(
this.platform, {
this.onNavigationRequest,
this.onPageStarted,
this.onPageFinished,
this.onProgress,
this.onWebResourceError,
void Function(UrlChange change)? onUrlChange,
}) {
if (onNavigationRequest != null) {
platform.setOnNavigationRequest(onNavigationRequest!);
Expand All @@ -73,6 +87,9 @@ class NavigationDelegate {
if (onWebResourceError != null) {
platform.setOnWebResourceError(onWebResourceError!);
}
if (onUrlChange != null) {
platform.setOnUrlChange(onUrlChange);
}
}

/// Implementation of [PlatformNavigationDelegate] for the current platform.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export 'package:webview_flutter_platform_interface/webview_flutter_platform_inte
PlatformWebViewCookieManagerCreationParams,
PlatformWebViewWidgetCreationParams,
ProgressCallback,
UrlChange,
WebResourceError,
WebResourceErrorCallback,
WebResourceErrorType,
Expand Down
12 changes: 11 additions & 1 deletion 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/plugins/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.0.3
version: 4.1.0

environment:
sdk: ">=2.17.0 <3.0.0"
Expand Down Expand Up @@ -31,3 +31,13 @@ dev_dependencies:
sdk: flutter
mockito: ^5.3.2
plugin_platform_interface: ^2.1.3


# FOR TESTING ONLY. DO NOT MERGE.
dependency_overrides:
webview_flutter_android:
path: ../../webview_flutter/webview_flutter_android
webview_flutter_platform_interface:
path: ../../webview_flutter/webview_flutter_platform_interface
webview_flutter_wkwebview:
path: ../../webview_flutter/webview_flutter_wkwebview
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ void main() {

verify(delegate.platform.setOnWebResourceError(onWebResourceError));
});

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

void onUrlChange(UrlChange change) {}

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

verify(delegate.platform.setOnUrlChange(onUrlChange));
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,14 @@ class MockPlatformNavigationDelegate extends _i1.Mock
returnValue: _i8.Future<void>.value(),
returnValueForMissingStub: _i8.Future<void>.value(),
) as _i8.Future<void>);
@override
_i8.Future<void> setOnUrlChange(_i3.UrlChangeCallback? onUrlChange) =>
(super.noSuchMethod(
Invocation.method(
#setOnUrlChange,
[onUrlChange],
),
returnValue: _i8.Future<void>.value(),
returnValueForMissingStub: _i8.Future<void>.value(),
) as _i8.Future<void>);
}
Original file line number Diff line number Diff line change
Expand Up @@ -414,4 +414,14 @@ class MockPlatformNavigationDelegate extends _i1.Mock
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
@override
_i5.Future<void> setOnUrlChange(_i6.UrlChangeCallback? onUrlChange) =>
(super.noSuchMethod(
Invocation.method(
#setOnUrlChange,
[onUrlChange],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ void main() {
main_file.WebViewCookie;
// ignore: unnecessary_statements
main_file.WebResourceErrorType;
// ignore: unnecessary_statements
main_file.UrlChange;
});
});
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.3.0

* Adds support for `PlatformNavigationDelegate.onUrlChange`.

## 3.2.4

* Renames Pigeon output files.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2352,6 +2352,25 @@ public void urlLoading(
callback.reply(null);
});
}

public void doUpdateVisitedHistory(
@NonNull Long instanceIdArg,
@NonNull Long webViewInstanceIdArg,
@NonNull String urlArg,
@NonNull Boolean isReloadArg,
Reply<Void> callback) {
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory",
getCodec());
channel.send(
new ArrayList<Object>(
Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg, isReloadArg)),
channelReply -> {
callback.reply(null);
});
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface DownloadListenerHostApi {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,21 @@ public void urlLoading(
urlLoading(getIdentifierForClient(webViewClient), webViewIdentifier, urlArg, callback);
}

/** Passes arguments from {@link WebViewClient#doUpdateVisitedHistory} to Dart. */
public void doUpdateVisitedHistory(
WebViewClient webViewClient,
WebView webView,
String url,
boolean isReload,
Reply<Void> callback) {
final Long webViewIdentifier = instanceManager.getIdentifierForStrongReference(webView);
if (webViewIdentifier == null) {
throw new IllegalStateException("Could not find identifier for 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 @@ -78,6 +78,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 @@ -146,6 +151,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
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,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 @@ -936,6 +936,42 @@ 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('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 @@ -35,3 +35,11 @@ flutter:
- assets/sample_video.mp4
- assets/www/index.html
- assets/www/styles/style.css


# FOR TESTING ONLY. DO NOT MERGE.
dependency_overrides:
webview_flutter_android:
path: ../../../webview_flutter/webview_flutter_android
webview_flutter_platform_interface:
path: ../../../webview_flutter/webview_flutter_platform_interface
Loading