Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[webview_flutter_android][webview_flutter_wkwebview] Adds support for setOnScrollPositionChange for webview_flutter platform implementations #5664

Merged
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
dd1196d
Recreating PR from flutter/plugins
TheVinhLuong Mar 11, 2023
d91b421
Merge branch 'master' into webview-scroll-listener
TheVinhLuong Mar 11, 2023
2a9b827
[webview_android] Remove enableContentOffsetChangedListener
TheVinhLuong Apr 1, 2023
07d30ef
Merge branch 'master' into webview-scroll-listener
TheVinhLuong Apr 1, 2023
5a80183
Fixup based on code review
TheVinhLuong Apr 14, 2023
1ea39bc
Merge branch 'main' into webview-scroll-listener
TheVinhLuong Apr 29, 2023
e6a5c55
Resolve conflict
TheVinhLuong Apr 29, 2023
024e3a7
Fixup based on code review
TheVinhLuong Apr 29, 2023
af3358b
Merge branch 'main' into webview-scroll-listener
TheVinhLuong May 30, 2023
c7b5231
Make dart low-level code for offset changes listener mirror the Andro…
TheVinhLuong May 30, 2023
44ca259
Add iOS implementation
TheVinhLuong Jul 3, 2023
726d1a8
Merge branch 'main' into webview-scroll-listener
TheVinhLuong Aug 1, 2023
ac8eacc
Add iOS related unit test codes
TheVinhLuong Aug 1, 2023
59fa39d
Merge branch 'main' into webview-scroll-listener
TheVinhLuong Aug 1, 2023
cfbdee9
Fix CI failing checks
TheVinhLuong Aug 1, 2023
f24f661
Merge branch 'main' into webview-scroll-listener
TheVinhLuong Aug 6, 2023
562bd04
Apply changes based on review comments
TheVinhLuong Aug 27, 2023
1b5e9d3
Merge branch 'main' into webview-scroll-listener
TheVinhLuong Aug 27, 2023
d256a35
Fix code based on code review
TheVinhLuong Sep 26, 2023
df20af9
Merge branch 'main' into webview-scroll-listener
TheVinhLuong Sep 26, 2023
3c2a2ca
Merge branch 'main' into webview-scroll-listener
TheVinhLuong Sep 30, 2023
0c6aac1
Merge branch 'main' of github.com:flutter/packages into webview-scrol…
bparrishMines Oct 3, 2023
ac9dcee
some improvements
bparrishMines Oct 5, 2023
5dfa5b2
switch to doubles
bparrishMines Oct 5, 2023
94eed4b
update webview_flutter
bparrishMines Oct 5, 2023
b0153f9
formatting
bparrishMines Oct 5, 2023
a37dc83
Merge branch 'main' of github.com:flutter/packages into webview-scrol…
bparrishMines Oct 5, 2023
4348c1b
pubspec ordering and doc
bparrishMines Oct 5, 2023
48aa520
Merge branch 'main' of github.com:flutter/packages into webview-scrol…
bparrishMines Oct 11, 2023
02a4758
PR feedback
bparrishMines Oct 11, 2023
1233235
Fix integration test
TheVinhLuong Oct 14, 2023
2c39f56
Merge branch 'main' of github.com:flutter/packages into webview-scrol…
bparrishMines Nov 7, 2023
73aabaa
Merge branch 'main' into webview-scroll-listener
TheVinhLuong Dec 12, 2023
8a26cb4
Add android and ios implementation for scroll offset listener
TheVinhLuong Dec 13, 2023
75ab22d
Merge branch 'main' into webview-scroll-listener-platforms
TheVinhLuong Dec 13, 2023
066155a
Merge branch 'main' into webview-scroll-listener-platforms
TheVinhLuong Dec 17, 2023
36e176c
Fix wrong formatting
TheVinhLuong Dec 17, 2023
a435962
Merge branch 'main' of github.com:flutter/packages into webview-scrol…
bparrishMines Jan 4, 2024
a67f520
Merge branch 'main' of github.com:flutter/packages into webview-scrol…
bparrishMines Jan 5, 2024
7a9f6a6
update lint changes
bparrishMines Jan 5, 2024
8e7f8e9
Merge branch 'main' into webview-scroll-listener-platforms
stuartmorgan Jan 8, 2024
062d19e
Change expect logic for OnScollPositionChange
TheVinhLuong Jan 9, 2024
72a9988
Merge branch 'main' into webview-scroll-listener-platforms
TheVinhLuong Feb 3, 2024
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
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.14.0

* Adds support for `setOnScrollPositionChange` method to the `AndroidWebViewController`.

## 3.13.2

* Fixes new lint warnings.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1758,6 +1758,24 @@ public void create(@NonNull Long identifierArg, @NonNull Reply<Void> callback) {
new ArrayList<Object>(Collections.singletonList(identifierArg)),
channelReply -> callback.reply(null));
}

public void onScrollChanged(
@NonNull Long webViewInstanceIdArg,
@NonNull Long leftArg,
@NonNull Long topArg,
@NonNull Long oldLeftArg,
@NonNull Long oldTopArg,
@NonNull Reply<Void> callback) {
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.webview_flutter_android.WebViewFlutterApi.onScrollChanged",
getCodec());
channel.send(
new ArrayList<Object>(
Arrays.asList(webViewInstanceIdArg, leftArg, topArg, oldLeftArg, oldTopArg)),
channelReply -> callback.reply(null));
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface WebSettingsHostApi {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import androidx.annotation.VisibleForTesting;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewFlutterApi;
import java.util.Objects;

/**
* Flutter API implementation for `WebView`.
Expand Down Expand Up @@ -56,4 +57,20 @@ public void create(@NonNull WebView instance, @NonNull WebViewFlutterApi.Reply<V
void setApi(@NonNull WebViewFlutterApi api) {
this.api = api;
}

public void onScrollChanged(
@NonNull WebView instance,
@NonNull Long left,
@NonNull Long top,
@NonNull Long oldLeft,
@NonNull Long oldTop,
@NonNull WebViewFlutterApi.Reply<Void> callback) {
api.onScrollChanged(
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(instance)),
left,
top,
oldLeft,
oldTop,
callback);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,13 @@ public WebChromeClient getWebChromeClient() {
return currentWebChromeClient;
}

@Override
protected void onScrollChanged(int left, int top, int oldLeft, int oldTop) {
super.onScrollChanged(left, top, oldLeft, oldTop);
api.onScrollChanged(
this, (long) left, (long) top, (long) oldLeft, (long) oldTop, reply -> {});
}

/**
* Flutter API used to send messages back to Dart.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,4 +358,25 @@ public void setImportantForAutofillForParentFlutterView() {

verify(mockFlutterView).setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_YES);
}

@Test
public void onScrollChanged() {
final InstanceManager instanceManager = InstanceManager.create(identifier -> {});

final WebViewFlutterApiImpl flutterApiImpl =
new WebViewFlutterApiImpl(mockBinaryMessenger, instanceManager);

final WebViewFlutterApi mockFlutterApi = mock(WebViewFlutterApi.class);
flutterApiImpl.setApi(mockFlutterApi);
flutterApiImpl.create(mockWebView, reply -> {});

flutterApiImpl.onScrollChanged(mockWebView, 0L, 1L, 2L, 3L, reply -> {});

final long instanceIdentifier =
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(mockWebView));
verify(mockFlutterApi)
.onScrollChanged(eq(instanceIdentifier), eq(0L), eq(1L), eq(2L), eq(3L), any());

instanceManager.stopFinalizationListener();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,8 @@ Future<void> main() async {
});

group('Programmatic Scroll', () {
testWidgets('setAndGetScrollPosition', (WidgetTester tester) async {
testWidgets('setAndGetAndListenScrollPosition',
(WidgetTester tester) async {
const String scrollTestPage = '''
<!DOCTYPE html>
<html>
Expand All @@ -784,6 +785,7 @@ Future<void> main() async {
base64Encode(const Utf8Encoder().convert(scrollTestPage));

final Completer<void> pageLoaded = Completer<void>();
ScrollPositionChange? recordedPosition;
final PlatformWebViewController controller = PlatformWebViewController(
const PlatformWebViewControllerCreationParams(),
);
Expand All @@ -793,6 +795,10 @@ Future<void> main() async {
);
unawaited(delegate.setOnPageFinished((_) => pageLoaded.complete()));
unawaited(controller.setPlatformNavigationDelegate(delegate));
unawaited(controller.setOnScrollPositionChange(
(ScrollPositionChange contentOffsetChange) {
recordedPosition = contentOffsetChange;
}));

await controller.loadRequest(
LoadRequestParams(
Expand Down Expand Up @@ -824,17 +830,22 @@ Future<void> main() async {
// time to settle.
expect(scrollPos.dx, isNot(X_SCROLL));
expect(scrollPos.dy, isNot(Y_SCROLL));
expect(recordedPosition, null);

await controller.scrollTo(X_SCROLL, Y_SCROLL);
scrollPos = await controller.getScrollPosition();
expect(scrollPos.dx, X_SCROLL);
expect(scrollPos.dy, Y_SCROLL);
expect(recordedPosition?.x, X_SCROLL);
expect(recordedPosition?.y, Y_SCROLL);

// Check scrollBy() (on top of scrollTo())
await controller.scrollBy(X_SCROLL, Y_SCROLL);
scrollPos = await controller.getScrollPosition();
expect(scrollPos.dx, X_SCROLL * 2);
expect(scrollPos.dy, Y_SCROLL * 2);
expect(recordedPosition?.x, X_SCROLL * 2);
expect(recordedPosition?.y, Y_SCROLL * 2);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,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.7.0
webview_flutter_platform_interface: ^2.8.0

dev_dependencies:
espresso: ^0.2.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ class AndroidWebViewProxy {
});

/// Constructs a [android_webview.WebView].
final android_webview.WebView Function() createAndroidWebView;
final android_webview.WebView Function({
void Function(int left, int top, int oldLeft, int oldTop)? onScrollChanged,
}) createAndroidWebView;

/// Constructs a [android_webview.WebChromeClient].
final android_webview.WebChromeClient Function({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,8 @@ class GeolocationPermissionsCallback extends JavaObject {
/// When a [WebView] is no longer needed [release] must be called.
class WebView extends View {
/// Constructs a new WebView.
///
/// Due to changes in Flutter 3.0 the [useHybridComposition] doesn't have
/// any effect and should not be exposed publicly. More info here:
/// https://github.com/flutter/flutter/issues/108106
WebView({
this.onScrollChanged,
@visibleForTesting super.binaryMessenger,
@visibleForTesting super.instanceManager,
}) : super.detached() {
Expand All @@ -149,6 +146,7 @@ class WebView extends View {
/// create copies.
@protected
WebView.detached({
this.onScrollChanged,
super.binaryMessenger,
super.instanceManager,
}) : super.detached();
Expand All @@ -160,6 +158,18 @@ class WebView extends View {
/// The [WebSettings] object used to control the settings for this WebView.
late final WebSettings settings = WebSettings(this);

/// Called in response to an internal scroll in this view
/// (i.e., the view scrolled its own contents).
///
/// This is typically as a result of [scrollBy] or [scrollTo]
/// having been called.
final void Function(
int left,
int top,
int oldLeft,
int oldTop,
)? onScrollChanged;

/// Enables debugging of web contents (HTML / CSS / JavaScript) loaded into any WebViews of this application.
///
/// This flag can be enabled in order to facilitate debugging of web layouts
Expand Down Expand Up @@ -448,6 +458,7 @@ class WebView extends View {
@override
WebView copy() {
return WebView.detached(
onScrollChanged: onScrollChanged,
binaryMessenger: _api.binaryMessenger,
instanceManager: _api.instanceManager,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,9 @@ abstract class WebViewFlutterApi {
/// Create a new Dart instance and add it to the `InstanceManager`.
void create(int identifier);

void onScrollChanged(
int webViewInstanceId, int left, int top, int oldLeft, int oldTop);

static void setup(WebViewFlutterApi? api,
{BinaryMessenger? binaryMessenger}) {
{
Expand All @@ -1157,6 +1160,39 @@ abstract class WebViewFlutterApi {
});
}
}
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.webview_flutter_android.WebViewFlutterApi.onScrollChanged',
codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.webview_flutter_android.WebViewFlutterApi.onScrollChanged was null.');
final List<Object?> args = (message as List<Object?>?)!;
final int? arg_webViewInstanceId = (args[0] as int?);
assert(arg_webViewInstanceId != null,
'Argument for dev.flutter.pigeon.webview_flutter_android.WebViewFlutterApi.onScrollChanged was null, expected non-null int.');
final int? arg_left = (args[1] as int?);
assert(arg_left != null,
'Argument for dev.flutter.pigeon.webview_flutter_android.WebViewFlutterApi.onScrollChanged was null, expected non-null int.');
final int? arg_top = (args[2] as int?);
assert(arg_top != null,
'Argument for dev.flutter.pigeon.webview_flutter_android.WebViewFlutterApi.onScrollChanged was null, expected non-null int.');
final int? arg_oldLeft = (args[3] as int?);
assert(arg_oldLeft != null,
'Argument for dev.flutter.pigeon.webview_flutter_android.WebViewFlutterApi.onScrollChanged was null, expected non-null int.');
final int? arg_oldTop = (args[4] as int?);
assert(arg_oldTop != null,
'Argument for dev.flutter.pigeon.webview_flutter_android.WebViewFlutterApi.onScrollChanged was null, expected non-null int.');
api.onScrollChanged(arg_webViewInstanceId!, arg_left!, arg_top!,
arg_oldLeft!, arg_oldTop!);
return;
});
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,18 @@ class WebViewFlutterApiImpl implements WebViewFlutterApi {
void create(int identifier) {
instanceManager.addHostCreatedInstance(WebView.detached(), identifier);
}

@override
void onScrollChanged(
int webViewInstanceId, int left, int top, int oldLeft, int oldTop) {
final WebView? webViewInstance = instanceManager
.getInstanceWithWeakReference(webViewInstanceId) as WebView?;
assert(
webViewInstance != null,
'InstanceManager does not contain a WebView with instanceId: $webViewInstanceId',
);
webViewInstance!.onScrollChanged?.call(left, top, oldLeft, oldTop);
}
}

/// Host api implementation for [WebSettings].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,15 @@ class AndroidWebViewController extends PlatformWebViewController {

/// The native [android_webview.WebView] being controlled.
late final android_webview.WebView _webView =
_androidWebViewParams.androidWebViewProxy.createAndroidWebView();
_androidWebViewParams.androidWebViewProxy.createAndroidWebView(
onScrollChanged: withWeakReferenceTo(this,
(WeakReference<AndroidWebViewController> weakReference) {
return (int left, int top, int oldLeft, int oldTop) async {
final void Function(ScrollPositionChange)? callback =
weakReference.target?._onScrollPositionChangedCallback;
callback?.call(ScrollPositionChange(left.toDouble(), top.toDouble()));
};
}));

late final android_webview.WebChromeClient _webChromeClient =
_androidWebViewParams.androidWebViewProxy.createAndroidWebChromeClient(
Expand Down Expand Up @@ -290,6 +298,9 @@ class AndroidWebViewController extends PlatformWebViewController {

void Function(JavaScriptConsoleMessage consoleMessage)? _onConsoleLogCallback;

void Function(ScrollPositionChange scrollPositionChange)?
_onScrollPositionChangedCallback;

/// Whether to enable the platform's webview content debugging tools.
///
/// Defaults to false.
Expand Down Expand Up @@ -509,6 +520,13 @@ class AndroidWebViewController extends PlatformWebViewController {
Future<void> setUserAgent(String? userAgent) =>
_webView.settings.setUserAgentString(userAgent);

@override
Future<void> setOnScrollPositionChange(
void Function(ScrollPositionChange scrollPositionChange)?
onScrollPositionChange) async {
_onScrollPositionChangedCallback = onScrollPositionChange;
}

/// Sets the restrictions that apply on automatic media playback.
Future<void> setMediaPlaybackRequiresUserGesture(bool require) {
return _webView.settings.setMediaPlaybackRequiresUserGesture(require);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,14 @@ abstract class WebViewHostApi {
abstract class WebViewFlutterApi {
/// Create a new Dart instance and add it to the `InstanceManager`.
void create(int identifier);

void onScrollChanged(
int webViewInstanceId,
int left,
int top,
int oldLeft,
int oldTop,
);
}

@HostApi(dartHostTestHandler: 'TestWebSettingsHostApi')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: webview_flutter_android
description: A Flutter plugin that provides a WebView widget on Android.
repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
version: 3.13.2
version: 3.14.0

environment:
sdk: ">=3.0.0 <4.0.0"
Expand All @@ -20,7 +20,7 @@ flutter:
dependencies:
flutter:
sdk: flutter
webview_flutter_platform_interface: ^2.7.0
webview_flutter_platform_interface: ^2.8.0

dev_dependencies:
build_runner: ^2.1.4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,11 @@ void main() {
onConsoleMessage,
}) =>
MockWebChromeClient(),
createAndroidWebView: () => nonNullMockWebView,
createAndroidWebView: (
{dynamic Function(
int left, int top, int oldLeft, int oldTop)?
onScrollChanged}) =>
nonNullMockWebView,
createAndroidWebViewClient: ({
void Function(android_webview.WebView webView, String url)?
onPageFinished,
Expand Down
Loading