Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
37 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
79e6c2c
Merge branch 'main' into webview-scroll-listener
TheVinhLuong Dec 12, 2023
0d8668b
Merge branch 'main' into webview-scroll-listener
TheVinhLuong Feb 9, 2024
a2400d2
Updates minimum supported SDK version to Flutter 3.16.6/Dart 3.2.3. U…
TheVinhLuong Feb 9, 2024
7f8d4c6
Fixup based on code review
TheVinhLuong Feb 9, 2024
3ea68d8
Merge branch 'main' into webview-scroll-listener
TheVinhLuong Feb 9, 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
4 changes: 4 additions & 0 deletions packages/webview_flutter/webview_flutter_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.4.3

* Added `setOnContentOffsetChanged` method to the `AndroidWebViewController`.

## 3.4.2

* Clarifies explanation of endorsement in README.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// 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.

package io.flutter.plugins.webviewflutter;

public interface ContentOffsetChangedListener {
void onContentOffsetChange(int left, int top, int oldLeft, int oldTop);
}
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.4), do not edit directly.
// Autogenerated from Pigeon (v9.0.6), do not edit directly.
// See also: https://pub.dev/packages/pigeon

package io.flutter.plugins.webviewflutter;
Expand Down Expand Up @@ -706,6 +706,8 @@ void removeJavaScriptChannel(

void setBackgroundColor(@NonNull Long instanceId, @NonNull Long color);

void enableContentOffsetChangedListener(@NonNull Long instanceId, @NonNull Boolean enabled);

/** The codec used by WebViewHostApi. */
static MessageCodec<Object> getCodec() {
return WebViewHostApiCodec.INSTANCE;
Expand Down Expand Up @@ -1572,6 +1574,40 @@ public void error(Throwable error) {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.WebViewHostApi.enableContentOffsetChangedListener",
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<Object>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
}
Boolean enabledArg = (Boolean) args.get(1);
if (enabledArg == null) {
throw new NullPointerException("enabledArg unexpectedly null.");
}
api.enableContentOffsetChangedListener(
(instanceIdArg == null) ? null : instanceIdArg.longValue(), enabledArg);
wrapped.add(0, null);
} catch (Error | RuntimeException exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}
/**
Expand All @@ -1591,6 +1627,7 @@ public WebViewFlutterApi(BinaryMessenger argBinaryMessenger) {
this.binaryMessenger = argBinaryMessenger;
}

/** Public interface for sending reply. */
public interface Reply<T> {
void reply(T reply);
}
Expand All @@ -1605,9 +1642,24 @@ public void create(@NonNull Long identifierArg, Reply<Void> callback) {
binaryMessenger, "dev.flutter.pigeon.WebViewFlutterApi.create", getCodec());
channel.send(
new ArrayList<Object>(Collections.singletonList(identifierArg)),
channelReply -> {
callback.reply(null);
});
channelReply -> callback.reply(null));
}

public void onScrollPosChange(
@NonNull Long webViewInstanceIdArg,
@NonNull Long xArg,
@NonNull Long yArg,
@NonNull Long oldXArg,
@NonNull Long oldYArg,
Reply<Void> callback) {
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.WebViewFlutterApi.onScrollPosChange",
getCodec());
channel.send(
new ArrayList<Object>(Arrays.asList(webViewInstanceIdArg, xArg, yArg, oldXArg, oldYArg)),
channelReply -> callback.reply(null));
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// 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.

package io.flutter.plugins.webviewflutter;

import androidx.annotation.Nullable;
/** Define extending APIs for {@link android.webkit.WebView} */
public interface WebViewExtendedApi {
void setContentOffsetChangedListener(
@Nullable ContentOffsetChangedListener contentOffsetChangedListener);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@
* <p>This class may handle adding native instances that are attached to a Dart instance or passing
* arguments of callbacks methods to a Dart instance.
*/
public class WebViewFlutterApiImpl {
// To ease adding additional methods, this value is added prematurely.
@SuppressWarnings({"unused", "FieldCanBeLocal"})
private final BinaryMessenger binaryMessenger;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three lines need to be kept


public class WebViewFlutterApiImpl extends WebViewFlutterApi {
private final InstanceManager instanceManager;
private WebViewFlutterApi api;

Expand All @@ -30,9 +26,9 @@ public class WebViewFlutterApiImpl {
* @param binaryMessenger used to communicate with Dart over asynchronous messages
* @param instanceManager maintains instances stored to communicate with attached Dart objects
*/
public WebViewFlutterApiImpl(
public WebViewFContentOffsetChangedListener lutterApiImpl(
@NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) {
this.binaryMessenger = binaryMessenger;
super(binaryMessenger);
this.instanceManager = instanceManager;
api = new WebViewFlutterApi(binaryMessenger);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ private void setUp(
instanceManager,
binaryMessenger,
new WebViewHostApiImpl.WebViewProxy(),
new WebViewFlutterApiImpl(binaryMessenger, instanceManager),
context,
containerView);
javaScriptChannelHostApi =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import androidx.annotation.Nullable;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewFlutterApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewHostApi;
import java.util.Map;
import java.util.Objects;
Expand All @@ -31,6 +32,7 @@ public class WebViewHostApiImpl implements WebViewHostApi {
// Only used with WebView using virtual displays.
@Nullable private final View containerView;
private final BinaryMessenger binaryMessenger;
private final WebViewFlutterApi webViewFlutterApi;

private Context context;

Expand Down Expand Up @@ -77,9 +79,11 @@ public void setWebContentsDebuggingEnabled(boolean enabled) {
}

/** Implementation of {@link WebView} that can be used as a Flutter {@link PlatformView}s. */
public static class WebViewPlatformView extends WebView implements PlatformView {
public static class WebViewPlatformView extends WebView
implements PlatformView, WebViewExtendedApi {
private WebViewClient currentWebViewClient;
private WebChromeClientHostApiImpl.SecureWebChromeClient currentWebChromeClient;
private @Nullable ContentOffsetChangedListener contentOffsetChangedListener;

/**
* Creates a {@link WebViewPlatformView}.
Expand Down Expand Up @@ -129,6 +133,20 @@ public void setWebChromeClient(WebChromeClient client) {
public WebChromeClient getWebChromeClient() {
return currentWebChromeClient;
}

@Override
protected void onScrollChanged(int l, int t, int oldL, int oldT) {
super.onScrollChanged(l, t, oldL, oldT);
if (contentOffsetChangedListener != null) {
contentOffsetChangedListener.onContentOffsetChange(l, t, oldL, oldT);
}
}

@Override
public void setContentOffsetChangedListener(
ContentOffsetChangedListener contentOffsetChangedListener) {
this.contentOffsetChangedListener = contentOffsetChangedListener;
}
}

/**
Expand All @@ -137,9 +155,10 @@ public WebChromeClient getWebChromeClient() {
*/
@SuppressLint("ViewConstructor")
public static class InputAwareWebViewPlatformView extends InputAwareWebView
implements PlatformView {
implements PlatformView, WebViewExtendedApi {
private WebViewClient currentWebViewClient;
private WebChromeClientHostApiImpl.SecureWebChromeClient currentWebChromeClient;
private @Nullable ContentOffsetChangedListener contentOffsetChangedListener;

/**
* Creates a {@link InputAwareWebViewPlatformView}.
Expand Down Expand Up @@ -206,6 +225,20 @@ public void setWebChromeClient(WebChromeClient client) {
currentWebChromeClient = (WebChromeClientHostApiImpl.SecureWebChromeClient) client;
currentWebChromeClient.setWebViewClient(currentWebViewClient);
}

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (contentOffsetChangedListener != null) {
contentOffsetChangedListener.onContentOffsetChange(l, t, oldl, oldt);
}
}

@Override
public void setContentOffsetChangedListener(
ContentOffsetChangedListener contentOffsetChangedListener) {
this.contentOffsetChangedListener = contentOffsetChangedListener;
}
}

/**
Expand All @@ -221,11 +254,13 @@ public WebViewHostApiImpl(
InstanceManager instanceManager,
BinaryMessenger binaryMessenger,
WebViewProxy webViewProxy,
WebViewFlutterApi webViewFlutterApi,
Context context,
@Nullable View containerView) {
this.instanceManager = instanceManager;
this.binaryMessenger = binaryMessenger;
this.webViewProxy = webViewProxy;
this.webViewFlutterApi = webViewFlutterApi;
this.context = context;
this.containerView = containerView;
}
Expand Down Expand Up @@ -420,6 +455,30 @@ public void setBackgroundColor(Long instanceId, Long color) {
webView.setBackgroundColor(color.intValue());
}

@Override
public void enableContentOffsetChangedListener(
@NonNull Long instanceId, @NonNull Boolean enabled) {
final WebView webView = (WebView) instanceManager.getInstance(instanceId);
if (webView instanceof WebViewExtendedApi) {
if (enabled) {
((WebViewExtendedApi) webView)
.setContentOffsetChangedListener(
(left, top, oldLeft, oldTop) -> {
webViewFlutterApi.onScrollPosChange(
instanceId,
(long) left,
(long) top,
(long) oldLeft,
(long) oldTop,
reply -> {});
});

} else {
((WebViewExtendedApi) webView).setContentOffsetChangedListener(null);
}
}
}

/** Maintains instances used to communicate with the corresponding WebView Dart object. */
public InstanceManager getInstanceManager() {
return instanceManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
Expand Down Expand Up @@ -39,6 +40,8 @@ public class WebViewTest {

@Mock WebViewHostApiImpl.WebViewProxy mockWebViewProxy;

@Mock public GeneratedAndroidWebView.WebViewFlutterApi mockWebViewFlutterApi;

@Mock Context mockContext;

@Mock BinaryMessenger mockBinaryMessenger;
Expand All @@ -54,7 +57,12 @@ public void setUp() {
.thenReturn(mockWebView);
testHostApiImpl =
new WebViewHostApiImpl(
testInstanceManager, mockBinaryMessenger, mockWebViewProxy, mockContext, null);
testInstanceManager,
mockBinaryMessenger,
mockWebViewProxy,
mockWebViewFlutterApi,
mockContext,
null);
testHostApiImpl.create(0L, true);
}

Expand Down Expand Up @@ -335,4 +343,21 @@ public void flutterApiCreate() {

instanceManager.close();
}

@Test
public void disableContentOffsetChangedListener() {
testHostApiImpl.enableContentOffsetChangedListener(0L, false);
verify(mockWebView).setContentOffsetChangedListener(null);
}

@Test
public void enableContentOffsetChangedListener() {
final ArgumentCaptor<ContentOffsetChangedListener> modeCaptor =
ArgumentCaptor.forClass(ContentOffsetChangedListener.class);
testHostApiImpl.enableContentOffsetChangedListener(0L, true);
verify(mockWebView).setContentOffsetChangedListener(modeCaptor.capture());
assertNotNull(modeCaptor.getValue());
modeCaptor.getValue().onContentOffsetChange(0, 1, 2, 3);
verify(mockWebViewFlutterApi).onScrollPosChange(eq(0L), eq(0L), eq(1L), eq(2L), eq(3L), any());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ Page resource error:
))
..loadRequest(LoadRequestParams(
uri: Uri.parse('https://flutter.dev'),
));
))
..setOnContentOffsetChanged((int left, int top, int oldLeft, int oldTop) {
debugPrint(
'Scroll offset change to left = $left y = $top oldX = $oldLeft oldY = $oldTop');
});
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ flutter:
- assets/sample_video.mp4
- assets/www/index.html
- assets/www/styles/style.css


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