Added a test for the pull-to-refresh feature when used on Android.
This commit is contained in:
parent
0744743c97
commit
237ba6efb4
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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: (
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 view’s 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;
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue