diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 9822ad511f0e..7710f748fca5 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.3.15 + +* Add support for the v2 Android embedding. This shouldn't affect existing + functionality. Plugin authors who use the V2 embedding can now register the + plugin and expect that it correctly responds to app lifecycle changes. + ## 0.3.14+2 * Define clang module for iOS. @@ -13,7 +19,7 @@ ## 0.3.13 * Add an optional `userAgent` property to set a custom User Agent. - + ## 0.3.12+1 * Temporarily revert getTitle (doing this as a patch bump shortly after publishing). diff --git a/packages/webview_flutter/android/build.gradle b/packages/webview_flutter/android/build.gradle index 4fe7629b5f76..0104ede0a418 100644 --- a/packages/webview_flutter/android/build.gradle +++ b/packages/webview_flutter/android/build.gradle @@ -50,3 +50,28 @@ android { implementation 'androidx.webkit:webkit:1.0.0' } } + +// TODO(mklim): Remove this hack once androidx.lifecycle is included on stable. https://github.com/flutter/flutter/issues/42348 +afterEvaluate { + def containsEmbeddingDependencies = false + for (def configuration : configurations.all) { + for (def dependency : configuration.dependencies) { + if (dependency.group == 'io.flutter' && + dependency.name.startsWith('flutter_embedding') && + dependency.isTransitive()) + { + containsEmbeddingDependencies = true + break + } + } + } + if (!containsEmbeddingDependencies) { + android { + dependencies { + def lifecycle_version = "2.1.0" + api "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" + api "androidx.lifecycle:lifecycle-runtime:$lifecycle_version" + } + } + } +} \ No newline at end of file diff --git a/packages/webview_flutter/android/gradle.properties b/packages/webview_flutter/android/gradle.properties index 8bd86f680510..08f2b5f91bff 100644 --- a/packages/webview_flutter/android/gradle.properties +++ b/packages/webview_flutter/android/gradle.properties @@ -1 +1,3 @@ org.gradle.jvmargs=-Xmx1536M +android.enableJetifier=true +android.useAndroidX=true diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java index 908f877fb922..86b4fd412a29 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java @@ -15,17 +15,11 @@ import io.flutter.plugin.common.MethodChannel.Result; class FlutterCookieManager implements MethodCallHandler { + private final MethodChannel methodChannel; - private FlutterCookieManager() { - // Do not instantiate. - // This class should only be used in context of a BinaryMessenger. - // Use FlutterCookieManager#registerWith instead. - } - - static void registerWith(BinaryMessenger messenger) { - MethodChannel methodChannel = new MethodChannel(messenger, "plugins.flutter.io/cookie_manager"); - FlutterCookieManager cookieManager = new FlutterCookieManager(); - methodChannel.setMethodCallHandler(cookieManager); + FlutterCookieManager(BinaryMessenger messenger) { + methodChannel = new MethodChannel(messenger, "plugins.flutter.io/cookie_manager"); + methodChannel.setMethodCallHandler(this); } @Override @@ -39,6 +33,10 @@ public void onMethodCall(MethodCall methodCall, Result result) { } } + void dispose() { + methodChannel.setMethodCallHandler(null); + } + private static void clearCookies(final Result result) { CookieManager cookieManager = CookieManager.getInstance(); final boolean hasCookies = cookieManager.hasCookies(); diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java index a7f2db308e15..ac326ed7f27b 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java @@ -12,6 +12,8 @@ import android.view.View; import android.webkit.WebStorage; import android.webkit.WebViewClient; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -36,7 +38,7 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { BinaryMessenger messenger, int id, Map params, - final View containerView) { + @Nullable View containerView) { DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy(); DisplayManager displayManager = @@ -95,6 +97,16 @@ public void onInputConnectionLocked() { webView.lockInputConnection(); } + @Override + public void onFlutterViewAttached(@NonNull View flutterView) { + webView.setContainerView(flutterView); + } + + @Override + public void onFlutterViewDetached() { + webView.setContainerView(null); + } + @Override public void onMethodCall(MethodCall methodCall, Result result) { switch (methodCall.method) { diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java index 9275c380fb56..e04d566bdc92 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java @@ -7,9 +7,11 @@ import static android.content.Context.INPUT_METHOD_SERVICE; import android.content.Context; +import android.util.Log; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.webkit.WebView; +import androidx.annotation.Nullable; /** * A WebView subclass that mirrors the same implementation hacks that the system WebView does in @@ -22,16 +24,29 @@ *

See also {@link ThreadedInputConnectionProxyAdapterView}. */ final class InputAwareWebView extends WebView { - private final View containerView; - + private static final String TAG = "InputAwareWebView"; private View threadedInputConnectionProxyView; private ThreadedInputConnectionProxyAdapterView proxyAdapterView; + private @Nullable View containerView; - InputAwareWebView(Context context, View containerView) { + InputAwareWebView(Context context, @Nullable View containerView) { super(context); this.containerView = containerView; } + void setContainerView(@Nullable View containerView) { + this.containerView = containerView; + + if (proxyAdapterView == null) { + return; + } + + Log.w(TAG, "The containerView has changed while the proxyAdapterView exists."); + if (containerView != null) { + setInputConnectionTarget(proxyAdapterView); + } + } + /** * Set our proxy adapter view to use its cached input connection instead of creating new ones. * @@ -81,6 +96,12 @@ public boolean checkInputConnectionProxy(final View view) { // This isn't a new ThreadedInputConnectionProxyView. Ignore it. return super.checkInputConnectionProxy(view); } + if (containerView == null) { + Log.e( + TAG, + "Can't create a proxy view because there's no container view. Text input may not work."); + return super.checkInputConnectionProxy(view); + } // We've never seen this before, so we make the assumption that this is WebView's // ThreadedInputConnectionProxyView. We are making the assumption that the only view that could @@ -120,6 +141,10 @@ private void resetInputConnection() { // No need to reset the InputConnection to the default thread if we've never changed it. return; } + if (containerView == null) { + Log.e(TAG, "Can't reset the input connection to the container view because there is none."); + return; + } setInputConnectionTarget(/*targetView=*/ containerView); } @@ -132,6 +157,13 @@ private void resetInputConnection() { * InputConnections should be created on. */ private void setInputConnectionTarget(final View targetView) { + if (containerView == null) { + Log.e( + TAG, + "Can't set the input connection target because there is no containerView to use as a handler."); + return; + } + targetView.requestFocus(); containerView.post( new Runnable() { diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java index 6fdc36fbe545..fe62e3a35540 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java @@ -6,6 +6,7 @@ import android.content.Context; import android.view.View; +import androidx.annotation.Nullable; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.StandardMessageCodec; import io.flutter.plugin.platform.PlatformView; @@ -14,9 +15,9 @@ public final class WebViewFactory extends PlatformViewFactory { private final BinaryMessenger messenger; - private final View containerView; + private @Nullable final View containerView; - WebViewFactory(BinaryMessenger messenger, View containerView) { + WebViewFactory(BinaryMessenger messenger, @Nullable View containerView) { super(StandardMessageCodec.INSTANCE); this.messenger = messenger; this.containerView = containerView; diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java index 17177541222c..dcce7962aed5 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java @@ -4,17 +4,68 @@ package io.flutter.plugins.webviewflutter; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.PluginRegistry.Registrar; -/** WebViewFlutterPlugin */ -public class WebViewFlutterPlugin { - /** Plugin registration. */ +/** + * Java platform implementation of the webview_flutter plugin. + * + *

Register this in an add to app scenario to gracefully handle activity and context changes. + * + *

Call {@link #registerWith(Registrar)} to use the stable {@code io.flutter.plugin.common} + * package instead. + */ +public class WebViewFlutterPlugin implements FlutterPlugin { + + private @Nullable FlutterCookieManager flutterCookieManager; + + /** + * Add an instance of this to {@link io.flutter.embedding.engine.plugins.PluginRegistry} to + * register it. + * + *

Registration should eventually be handled automatically by v2 of the + * GeneratedPluginRegistrant. https://github.com/flutter/flutter/issues/42694 + */ + public WebViewFlutterPlugin() {} + + /** + * Registers a plugin implementation that uses the stable {@code io.flutter.plugin.common} + * package. + * + *

Calling this automatically initializes the plugin. However plugins initialized this way + * won't react to changes in activity or context, unlike {@link CameraPlugin}. + */ public static void registerWith(Registrar registrar) { registrar .platformViewRegistry() .registerViewFactory( "plugins.flutter.io/webview", new WebViewFactory(registrar.messenger(), registrar.view())); - FlutterCookieManager.registerWith(registrar.messenger()); + new FlutterCookieManager(registrar.messenger()); + } + + @Override + public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { + BinaryMessenger messenger = binding.getFlutterEngine().getDartExecutor(); + binding + .getFlutterEngine() + .getPlatformViewsController() + .getRegistry() + .registerViewFactory( + "plugins.flutter.io/webview", new WebViewFactory(messenger, /*containerView=*/ null)); + flutterCookieManager = new FlutterCookieManager(messenger); + } + + @Override + public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { + if (flutterCookieManager == null) { + return; + } + + flutterCookieManager.dispose(); + flutterCookieManager = null; } } diff --git a/packages/webview_flutter/example/android/app/build.gradle b/packages/webview_flutter/example/android/app/build.gradle index 79a69ac3e4d7..706d501c4060 100644 --- a/packages/webview_flutter/example/android/app/build.gradle +++ b/packages/webview_flutter/example/android/app/build.gradle @@ -56,6 +56,7 @@ flutter { dependencies { testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test:rules:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' } diff --git a/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1ActivityTest.java b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1ActivityTest.java new file mode 100644 index 000000000000..fe10c6155e5a --- /dev/null +++ b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1ActivityTest.java @@ -0,0 +1,13 @@ +package io.flutter.plugins.webviewflutterexample; + +import androidx.test.rule.ActivityTestRule; +import dev.flutter.plugins.e2e.FlutterRunner; +import org.junit.Rule; +import org.junit.runner.RunWith; + +@RunWith(FlutterRunner.class) +public class EmbeddingV1ActivityTest { + @Rule + public ActivityTestRule rule = + new ActivityTestRule<>(EmbeddingV1Activity.class); +} diff --git a/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/MainActivityTest.java b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/MainActivityTest.java new file mode 100644 index 000000000000..a0bd4fe1a7f5 --- /dev/null +++ b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/MainActivityTest.java @@ -0,0 +1,11 @@ +package io.flutter.plugins.webviewflutterexample; + +import androidx.test.rule.ActivityTestRule; +import dev.flutter.plugins.e2e.FlutterRunner; +import org.junit.Rule; +import org.junit.runner.RunWith; + +@RunWith(FlutterRunner.class) +public class MainActivityTest { + @Rule public ActivityTestRule rule = new ActivityTestRule<>(MainActivity.class); +} diff --git a/packages/webview_flutter/example/android/app/src/main/AndroidManifest.xml b/packages/webview_flutter/example/android/app/src/main/AndroidManifest.xml index 8fcbcd3908ba..fd570acc8959 100644 --- a/packages/webview_flutter/example/android/app/src/main/AndroidManifest.xml +++ b/packages/webview_flutter/example/android/app/src/main/AndroidManifest.xml @@ -1,39 +1,48 @@ + package="io.flutter.plugins.webviewflutterexample"> - - + + + + + + + + + + + + + - - - - - - - - - - - + + diff --git a/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1Activity.java b/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1Activity.java new file mode 100644 index 000000000000..9b868934cc10 --- /dev/null +++ b/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1Activity.java @@ -0,0 +1,17 @@ +// Copyright 2019 The Chromium 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.webviewflutterexample; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class EmbeddingV1Activity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/MainActivity.java b/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/MainActivity.java index f935d0030483..1596844948e7 100644 --- a/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/MainActivity.java +++ b/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/MainActivity.java @@ -4,14 +4,14 @@ package io.flutter.plugins.webviewflutterexample; -import android.os.Bundle; -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; +import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.plugins.webviewflutter.WebViewFlutterPlugin; public class MainActivity extends FlutterActivity { + // TODO(mklim): Remove this once v2 of GeneratedPluginRegistrant rolls to stable. https://github.com/flutter/flutter/issues/42694 @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - GeneratedPluginRegistrant.registerWith(this); + public void configureFlutterEngine(FlutterEngine flutterEngine) { + flutterEngine.getPlugins().add(new WebViewFlutterPlugin()); } } diff --git a/packages/webview_flutter/example/android/gradle.properties b/packages/webview_flutter/example/android/gradle.properties index ad8917e962e5..a6738207fd15 100644 --- a/packages/webview_flutter/example/android/gradle.properties +++ b/packages/webview_flutter/example/android/gradle.properties @@ -1,2 +1,4 @@ org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true \ No newline at end of file +android.useAndroidX=true +android.enableJetifier=true +android.enableR8=true diff --git a/packages/webview_flutter/example/pubspec.yaml b/packages/webview_flutter/example/pubspec.yaml index 8657cfde0f8b..0e24333cfc0b 100644 --- a/packages/webview_flutter/example/pubspec.yaml +++ b/packages/webview_flutter/example/pubspec.yaml @@ -1,10 +1,11 @@ name: webview_flutter_example description: Demonstrates how to use the webview_flutter plugin. -version: 1.0.1 +version: 1.0.2 environment: sdk: ">=2.0.0-dev.68.0 <3.0.0" + flutter: ">=1.9.1+hotfix.4 <2.0.0" dependencies: flutter: @@ -17,6 +18,7 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter + e2e: "^0.2.0" flutter: uses-material-design: true diff --git a/packages/webview_flutter/example/test_driver/webview.dart b/packages/webview_flutter/example/test_driver/webview_flutter_e2e.dart similarity index 92% rename from packages/webview_flutter/example/test_driver/webview.dart rename to packages/webview_flutter/example/test_driver/webview_flutter_e2e.dart index e24afd73f557..a5d4d7de66fe 100644 --- a/packages/webview_flutter/example/test_driver/webview.dart +++ b/packages/webview_flutter/example/test_driver/webview_flutter_e2e.dart @@ -9,19 +9,17 @@ import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; -import 'package:flutter_driver/driver_extension.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:webview_flutter/webview_flutter.dart'; +import 'package:e2e/e2e.dart'; void main() { - final Completer allTestsCompleter = Completer(); - enableFlutterDriverExtension(handler: (_) => allTestsCompleter.future); - tearDownAll(() => allTestsCompleter.complete(null)); + E2EWidgetsFlutterBinding.ensureInitialized(); - test('initalUrl', () async { + testWidgets('initalUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -38,10 +36,10 @@ void main() { expect(currentUrl, 'https://flutter.dev/'); }); - test('loadUrl', () async { + testWidgets('loadUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -61,11 +59,11 @@ void main() { // enable this once https://github.com/flutter/flutter/issues/31510 // is resolved. - test('loadUrl with headers', () async { + testWidgets('loadUrl with headers', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -96,12 +94,12 @@ void main() { expect(content.contains('flutter_test_header'), isTrue); }); - test('JavaScriptChannel', () async { + testWidgets('JavaScriptChannel', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); final List messagesReceived = []; - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -137,7 +135,7 @@ void main() { expect(messagesReceived, equals(['hello'])); }); - test('resize webview', () async { + testWidgets('resize webview', (WidgetTester tester) async { final String resizeTest = ''' Resize test @@ -184,7 +182,7 @@ void main() { javascriptMode: JavascriptMode.unrestricted, ); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Column( @@ -204,7 +202,7 @@ void main() { expect(resizeCompleter.isCompleted, false); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Column( @@ -222,11 +220,11 @@ void main() { await resizeCompleter.future; }); - test('set custom userAgent', () async { + testWidgets('set custom userAgent', (WidgetTester tester) async { final Completer controllerCompleter1 = Completer(); final GlobalKey _globalKey = GlobalKey(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -244,7 +242,7 @@ void main() { final String customUserAgent1 = await _getUserAgent(controller1); expect(customUserAgent1, 'Custom_User_Agent1'); // rebuild the WebView with a different user agent. - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -260,12 +258,13 @@ void main() { expect(customUserAgent2, 'Custom_User_Agent2'); }); - test('use default platform userAgent after webView is rebuilt', () async { + testWidgets('use default platform userAgent after webView is rebuilt', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final GlobalKey _globalKey = GlobalKey(); // Build the webView with no user agent to get the default platform user agent. - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -281,7 +280,7 @@ void main() { final WebViewController controller = await controllerCompleter.future; final String defaultPlatformUserAgent = await _getUserAgent(controller); // rebuild the WebView with a custom user agent. - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -295,7 +294,7 @@ void main() { final String customUserAgent = await _getUserAgent(controller); expect(customUserAgent, 'Custom_User_Agent'); // rebuilds the WebView with no user agent. - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -341,12 +340,12 @@ void main() { audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest)); }); - test('Auto media playback', () async { + testWidgets('Auto media playback', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -373,7 +372,7 @@ void main() { pageLoaded = Completer(); // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -399,13 +398,14 @@ void main() { expect(isPaused, _webviewBool(true)); }); - test('Changes to initialMediaPlaybackPolocy are ignored', () async { + testWidgets('Changes to initialMediaPlaybackPolocy are ignored', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); final GlobalKey key = GlobalKey(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -430,7 +430,7 @@ void main() { pageLoaded = Completer(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -458,7 +458,7 @@ void main() { }); }); - test('getTitle', () async { + testWidgets('getTitle', (WidgetTester tester) async { final String getTitleTest = ''' Some title @@ -473,7 +473,7 @@ void main() { final Completer controllerCompleter = Completer(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -496,11 +496,6 @@ void main() { }); } -Future pumpWidget(Widget widget) { - runApp(widget); - return WidgetsBinding.instance.endOfFrame; -} - // JavaScript booleans evaluate to different string values on Android and iOS. // This utility method returns the string boolean value of the current platform. String _webviewBool(bool value) { diff --git a/packages/webview_flutter/example/test_driver/webview_test.dart b/packages/webview_flutter/example/test_driver/webview_flutter_e2e_test.dart similarity index 72% rename from packages/webview_flutter/example/test_driver/webview_test.dart rename to packages/webview_flutter/example/test_driver/webview_flutter_e2e_test.dart index b0d3305cd652..2e5c27fd402e 100644 --- a/packages/webview_flutter/example/test_driver/webview_test.dart +++ b/packages/webview_flutter/example/test_driver/webview_flutter_e2e_test.dart @@ -3,11 +3,14 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:async'; +import 'dart:io'; import 'package:flutter_driver/flutter_driver.dart'; Future main() async { final FlutterDriver driver = await FlutterDriver.connect(); - await driver.requestData(null, timeout: const Duration(minutes: 1)); + final String result = + await driver.requestData(null, timeout: const Duration(minutes: 1)); driver.close(); + exit(result == 'pass' ? 0 : 1); } diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index 13ccef744009..efddfd3b7aec 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,12 +1,12 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 0.3.14+2 +version: 0.3.15 author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter environment: sdk: ">=2.0.0-dev.68.0 <3.0.0" - flutter: ">=1.5.0 <2.0.0" + flutter: ">=1.6.7 <2.0.0" dependencies: flutter: