Added a test for the pull-to-refresh feature when used on Android.

This commit is contained in:
Lorenzo Pichilli 2021-03-06 16:10:31 +01:00
parent 0744743c97
commit 237ba6efb4
13 changed files with 85 additions and 23 deletions

View File

@ -1,3 +1,7 @@
## 5.1.0+1
- Added a test for the pull-to-refresh feature when used on Android. It requires the `useHybridComposition: true` Android-specific option, otherwise it will throw an exception.
## 5.1.0
- Added support for pull-to-refresh feature [#395](https://github.com/pichillilorenzo/flutter_inappwebview/issues/395)

View File

@ -11,6 +11,7 @@ import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature;
@ -74,15 +75,17 @@ public class FlutterWebView implements PlatformView {
}
}
webView = new InAppWebView(context, channel, id, windowId, options, contextMenu, containerView, userScripts);
webView = new InAppWebView(context, channel, id, windowId, options, contextMenu, options.useHybridComposition ? null : containerView, userScripts);
displayListenerProxy.onPostWebViewInitialization(displayManager);
MethodChannel pullToRefreshLayoutChannel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_" + id);
PullToRefreshOptions pullToRefreshOptions = new PullToRefreshOptions();
pullToRefreshOptions.parse(pullToRefreshInitialOptions);
pullToRefreshLayout = new PullToRefreshLayout(context, pullToRefreshLayoutChannel, pullToRefreshOptions);
pullToRefreshLayout.addView(webView);
pullToRefreshLayout.prepare();
if (options.useHybridComposition) {
MethodChannel pullToRefreshLayoutChannel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_" + id);
PullToRefreshOptions pullToRefreshOptions = new PullToRefreshOptions();
pullToRefreshOptions.parse(pullToRefreshInitialOptions);
pullToRefreshLayout = new PullToRefreshLayout(context, pullToRefreshLayoutChannel, pullToRefreshOptions);
pullToRefreshLayout.addView(webView);
pullToRefreshLayout.prepare();
}
methodCallDelegate = new InAppWebViewMethodHandler(webView);
channel.setMethodCallHandler(methodCallDelegate);
@ -127,7 +130,7 @@ public class FlutterWebView implements PlatformView {
@Override
public View getView() {
return pullToRefreshLayout;
return pullToRefreshLayout != null ? pullToRefreshLayout : webView;
}
@Override
@ -170,26 +173,26 @@ public class FlutterWebView implements PlatformView {
@Override
public void onInputConnectionLocked() {
if (webView != null && webView.inAppBrowserDelegate == null)
if (webView != null && webView.inAppBrowserDelegate == null && !webView.options.useHybridComposition)
webView.lockInputConnection();
}
@Override
public void onInputConnectionUnlocked() {
if (webView != null && webView.inAppBrowserDelegate == null)
if (webView != null && webView.inAppBrowserDelegate == null && !webView.options.useHybridComposition)
webView.unlockInputConnection();
}
@Override
public void onFlutterViewAttached(View flutterView) {
if (webView != null) {
public void onFlutterViewAttached(@NonNull View flutterView) {
if (webView != null && !webView.options.useHybridComposition) {
webView.setContainerView(flutterView);
}
}
@Override
public void onFlutterViewDetached() {
if (webView != null) {
if (webView != null && !webView.options.useHybridComposition) {
webView.setContainerView(null);
}
}

View File

@ -156,7 +156,7 @@ final public class InAppWebView extends InputAwareWebView {
@Nullable Integer windowId, InAppWebViewOptions options,
@Nullable Map<String, Object> contextMenu, View containerView,
List<UserScript> userScripts) {
super(context, containerView);
super(context, containerView, options.useHybridComposition);
this.channel = channel;
this.id = id;
this.windowId = windowId;
@ -1244,7 +1244,7 @@ final public class InAppWebView extends InputAwareWebView {
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
InputConnection connection = super.onCreateInputConnection(outAttrs);
if (connection == null && containerView != null) {
if (connection == null && !options.useHybridComposition && containerView != null) {
// workaround to hide the Keyboard when the user click outside
// on something not focusable such as input or a textarea.
containerView

View File

@ -12,6 +12,8 @@ import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
import android.widget.ListPopupWindow;
import androidx.annotation.Nullable;
/**
* A WebView subclass that mirrors the same implementation hacks that the system WebView does in
* order to correctly create an InputConnection.
@ -22,13 +24,16 @@ import android.widget.ListPopupWindow;
*/
public class InputAwareWebView extends WebView {
private static final String LOG_TAG = "InputAwareWebView";
@Nullable
public View containerView;
private View threadedInputConnectionProxyView;
private ThreadedInputConnectionProxyAdapterView proxyAdapterView;
private boolean useHybridComposition = false;
public InputAwareWebView(Context context, View containerView) {
public InputAwareWebView(Context context, @Nullable View containerView, Boolean useHybridComposition) {
super(context);
this.containerView = containerView;
this.useHybridComposition = useHybridComposition == null ? false : useHybridComposition;
}
public InputAwareWebView(Context context, AttributeSet attrs) {
@ -83,6 +88,9 @@ public class InputAwareWebView extends WebView {
/** Restore the original InputConnection, if needed. */
void dispose() {
if (useHybridComposition) {
return;
}
resetInputConnection();
}
@ -101,6 +109,9 @@ public class InputAwareWebView extends WebView {
*/
@Override
public boolean checkInputConnectionProxy(final View view) {
if (useHybridComposition) {
return super.checkInputConnectionProxy(view);
}
// Check to see if the view param is WebView's ThreadedInputConnectionProxyView.
View previousProxy = threadedInputConnectionProxyView;
threadedInputConnectionProxyView = view;
@ -138,6 +149,10 @@ public class InputAwareWebView extends WebView {
@Override
public void clearFocus() {
super.clearFocus();
if (useHybridComposition) {
return;
}
resetInputConnection();
}
@ -206,6 +221,10 @@ public class InputAwareWebView extends WebView {
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (useHybridComposition) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
return;
}
// This works around a crash when old (<67.0.3367.0) Chromium versions are used.
// Prior to Chromium 67.0.3367 the following sequence happens when a select drop down is shown

View File

@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-03-05 22:47:49.023558","version":"2.1.0-10.0.pre"}
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-03-06 16:03:42.653087","version":"2.1.0-10.0.pre"}

View File

@ -4412,6 +4412,11 @@ setTimeout(function() {
child: InAppWebView(
key: GlobalKey(),
initialUrlRequest: URLRequest(url: Uri.parse('https://github.com/flutter')),
initialOptions: InAppWebViewGroupOptions(
android: AndroidInAppWebViewOptions(
useHybridComposition: true
)
),
pullToRefreshController: pullToRefreshController,
onWebViewCreated: (controller) {
controllerCompleter.complete(controller);

View File

@ -0,0 +1,18 @@
#
# NOTE: This podspec is NOT to be published. It is only used as a local source!
# This is a generated file; do not edit or check into version control.
#
Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '1.0.0'
s.summary = 'High-performance, high-fidelity mobile apps.'
s.homepage = 'https://flutter.io'
s.license = { :type => 'MIT' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
# Framework linking is handled by Flutter tooling, not CocoaPods.
# Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs.
s.vendored_frameworks = 'path/to/nothing'
end

View File

@ -2,12 +2,13 @@
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/lorenzopichilli/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_TARGET=integration_test/webview_flutter_test.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.packages"
export "PACKAGE_CONFIG=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/.dart_tool/package_config.json"

View File

@ -229,7 +229,6 @@ class InAppBrowser {
Future<void> show() async {
this.throwIfNotOpened();
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('id', () => id);
await _channel.invokeMethod('show', args);
}

View File

@ -354,7 +354,13 @@ class _InAppWebViewState extends State<InAppWebView> {
@override
Widget build(BuildContext context) {
if (defaultTargetPlatform == TargetPlatform.android) {
if (widget.initialOptions?.android.useHybridComposition ?? false) {
var useHybridComposition = widget.initialOptions?.android.useHybridComposition ?? false;
if (!useHybridComposition && widget.pullToRefreshController != null) {
throw new Exception("To use the pull-to-refresh feature, useHybridComposition Android-specific option MUST be true!");
}
if (useHybridComposition) {
return PlatformViewLink(
viewType: 'com.pichillilorenzo/flutter_inappwebview',
surfaceFactory: (

View File

@ -10,6 +10,8 @@ import 'in_app_webview_controller.dart';
import 'in_app_webview_options.dart';
import 'headless_in_app_webview.dart';
import 'android/in_app_webview_options.dart';
///Abstract class that represents a WebView. Used by [InAppWebView] and [HeadlessInAppWebView].
abstract class WebView {
///The window id of a [CreateWindowAction.windowId].
@ -645,6 +647,8 @@ abstract class WebView {
final UnmodifiableListView<UserScript>? initialUserScripts;
///Represents the pull-to-refresh feature controller.
///
///**NOTE for Android**: to be able to use the "pull-to-refresh" feature, [AndroidInAppWebViewOptions.useHybridComposition] must be `true`.
final PullToRefreshController? pullToRefreshController;
WebView(

View File

@ -5,6 +5,7 @@ import '../in_app_webview/webview.dart';
import '../in_app_browser/in_app_browser.dart';
import '../util.dart';
import '../types.dart';
import '../in_app_webview/android/in_app_webview_options.dart';
import 'pull_to_refresh_options.dart';
///A standard controller that can initiate the refreshing of a scroll views contents.
@ -12,6 +13,8 @@ import 'pull_to_refresh_options.dart';
///
///All the methods should be called only when the WebView has been created or is already running
///(for example [WebView.onWebViewCreated] or [InAppBrowser.onBrowserCreated]).
///
///**NOTE for Android**: to be able to use the "pull-to-refresh" feature, [AndroidInAppWebViewOptions.useHybridComposition] must be `true`.
class PullToRefreshController {
late PullToRefreshOptions options;
MethodChannel? _channel;

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview
description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window.
version: 5.1.0
version: 5.1.0+1
homepage: https://github.com/pichillilorenzo/flutter_inappwebview
environment: