From a4d3d16029a761274e6e1f7e4cc0696a3db599fe Mon Sep 17 00:00:00 2001 From: Maurice Parrish <10687576+bparrishMines@users.noreply.github.com> Date: Wed, 8 Mar 2023 10:28:07 -0500 Subject: [PATCH] [webview_flutter_android] Adds a WebViewFlutterApi (#3324) [webview_flutter_android] Adds a WebViewFlutterApi --- .../webview_flutter_android/CHANGELOG.md | 5 ++ .../FileChooserParamsFlutterApiImpl.java | 22 +++---- .../GeneratedAndroidWebView.java | 36 +++++++++++ .../WebChromeClientFlutterApiImpl.java | 22 +++---- .../WebViewClientFlutterApiImpl.java | 61 ++++++++++--------- .../webviewflutter/WebViewFlutterApiImpl.java | 59 ++++++++++++++++++ .../webviewflutter/WebChromeClientTest.java | 2 - .../webviewflutter/WebViewClientTest.java | 2 - .../plugins/webviewflutter/WebViewTest.java | 21 +++++++ .../lib/src/android_webview.g.dart | 37 +++++++++++ .../lib/src/android_webview_api_impls.dart | 27 ++++++++ .../pigeons/android_webview.dart | 13 ++++ .../webview_flutter_android/pubspec.yaml | 2 +- .../test/android_webview_test.dart | 18 ++++++ 14 files changed, 271 insertions(+), 56 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterApiImpl.java diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index 6bd586155faa0..5c20834c91a78 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.4.1 + +* Fixes a potential bug where a `WebView` that was not added to the `InstanceManager` could be + returned by a `WebViewClient` or `WebChromeClient`. + ## 3.4.0 * Adds support to set text zoom of a page. See `AndroidWebViewController.setTextZoom`. diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FileChooserParamsFlutterApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FileChooserParamsFlutterApiImpl.java index 6797859496978..cacf3642c3e5a 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FileChooserParamsFlutterApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FileChooserParamsFlutterApiImpl.java @@ -57,18 +57,16 @@ private static GeneratedAndroidWebView.FileChooserModeEnumData toFileChooserEnum /** * Stores the FileChooserParams instance and notifies Dart to create a new FileChooserParams * instance that is attached to this one. - * - * @return the instanceId of the stored instance */ - public long create(WebChromeClient.FileChooserParams instance, Reply callback) { - final long instanceId = instanceManager.addHostCreatedInstance(instance); - create( - instanceId, - instance.isCaptureEnabled(), - Arrays.asList(instance.getAcceptTypes()), - toFileChooserEnumData(instance.getMode()), - instance.getFilenameHint(), - callback); - return instanceId; + public void create(WebChromeClient.FileChooserParams instance, Reply callback) { + if (!instanceManager.containsInstance(instance)) { + create( + instanceManager.addHostCreatedInstance(instance), + instance.isCaptureEnabled(), + Arrays.asList(instance.getAcceptTypes()), + toFileChooserEnumData(instance.getMode()), + instance.getFilenameHint(), + callback); + } } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index 6fa20feb1d092..189b85c32bb33 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -1574,6 +1574,42 @@ public void error(Throwable error) { } } } + /** + * Flutter API for `WebView`. + * + *

This class may handle instantiating and adding Dart instances that are attached to a native + * instance or receiving callback methods from an overridden native class. + * + *

See https://developer.android.com/reference/android/webkit/WebView. + * + *

Generated class from Pigeon that represents Flutter messages that can be called from Java. + */ + public static class WebViewFlutterApi { + private final BinaryMessenger binaryMessenger; + + public WebViewFlutterApi(BinaryMessenger argBinaryMessenger) { + this.binaryMessenger = argBinaryMessenger; + } + + public interface Reply { + void reply(T reply); + } + /** The codec used by WebViewFlutterApi. */ + static MessageCodec getCodec() { + return new StandardMessageCodec(); + } + /** Create a new Dart instance and add it to the `InstanceManager`. */ + public void create(@NonNull Long identifierArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewFlutterApi.create", getCodec()); + channel.send( + new ArrayList(Collections.singletonList(identifierArg)), + channelReply -> { + callback.reply(null); + }); + } + } /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface WebSettingsHostApi { diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java index 92f0e41905cc5..ece8e62e8b91b 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java @@ -21,6 +21,7 @@ public class WebChromeClientFlutterApiImpl extends WebChromeClientFlutterApi { private final BinaryMessenger binaryMessenger; private final InstanceManager instanceManager; + private final WebViewFlutterApiImpl webViewFlutterApi; /** * Creates a Flutter api that sends messages to Dart. @@ -33,15 +34,16 @@ public WebChromeClientFlutterApiImpl( super(binaryMessenger); this.binaryMessenger = binaryMessenger; this.instanceManager = instanceManager; + webViewFlutterApi = new WebViewFlutterApiImpl(binaryMessenger, instanceManager); } /** Passes arguments from {@link WebChromeClient#onProgressChanged} to Dart. */ public void onProgressChanged( WebChromeClient webChromeClient, WebView webView, Long progress, Reply callback) { - final Long webViewIdentifier = instanceManager.getIdentifierForStrongReference(webView); - if (webViewIdentifier == null) { - throw new IllegalStateException("Could not find identifier for WebView."); - } + webViewFlutterApi.create(webView, reply -> {}); + + final Long webViewIdentifier = + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView)); super.onProgressChanged( getIdentifierForClient(webChromeClient), webViewIdentifier, progress, callback); } @@ -53,17 +55,15 @@ public void onShowFileChooser( WebView webView, WebChromeClient.FileChooserParams fileChooserParams, Reply> callback) { - Long paramsInstanceId = instanceManager.getIdentifierForStrongReference(fileChooserParams); - if (paramsInstanceId == null) { - final FileChooserParamsFlutterApiImpl flutterApi = - new FileChooserParamsFlutterApiImpl(binaryMessenger, instanceManager); - paramsInstanceId = flutterApi.create(fileChooserParams, reply -> {}); - } + webViewFlutterApi.create(webView, reply -> {}); + + new FileChooserParamsFlutterApiImpl(binaryMessenger, instanceManager) + .create(fileChooserParams, reply -> {}); onShowFileChooser( Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webChromeClient)), Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView)), - paramsInstanceId, + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(fileChooserParams)), callback); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java index 0dc0bbb82b076..aad569dc47ce1 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java @@ -15,6 +15,7 @@ import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientFlutterApi; import java.util.HashMap; +import java.util.Objects; /** * Flutter Api implementation for {@link WebViewClient}. @@ -22,7 +23,9 @@ *

Passes arguments of callbacks methods from a {@link WebViewClient} to Dart. */ public class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { + private final BinaryMessenger binaryMessenger; private final InstanceManager instanceManager; + private final WebViewFlutterApiImpl webViewFlutterApi; @RequiresApi(api = Build.VERSION_CODES.M) static GeneratedAndroidWebView.WebResourceErrorData createWebResourceErrorData( @@ -71,26 +74,28 @@ static GeneratedAndroidWebView.WebResourceRequestData createWebResourceRequestDa public WebViewClientFlutterApiImpl( BinaryMessenger binaryMessenger, InstanceManager instanceManager) { super(binaryMessenger); + this.binaryMessenger = binaryMessenger; this.instanceManager = instanceManager; + webViewFlutterApi = new WebViewFlutterApiImpl(binaryMessenger, instanceManager); } /** Passes arguments from {@link WebViewClient#onPageStarted} to Dart. */ public void onPageStarted( WebViewClient webViewClient, WebView webView, String urlArg, Reply callback) { - final Long webViewIdentifier = instanceManager.getIdentifierForStrongReference(webView); - if (webViewIdentifier == null) { - throw new IllegalStateException("Could not find identifier for WebView."); - } + webViewFlutterApi.create(webView, reply -> {}); + + final Long webViewIdentifier = + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView)); onPageStarted(getIdentifierForClient(webViewClient), webViewIdentifier, urlArg, callback); } /** Passes arguments from {@link WebViewClient#onPageFinished} to Dart. */ public void onPageFinished( WebViewClient webViewClient, WebView webView, String urlArg, Reply callback) { - final Long webViewIdentifier = instanceManager.getIdentifierForStrongReference(webView); - if (webViewIdentifier == null) { - throw new IllegalStateException("Could not find identifier for WebView."); - } + webViewFlutterApi.create(webView, reply -> {}); + + final Long webViewIdentifier = + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView)); onPageFinished(getIdentifierForClient(webViewClient), webViewIdentifier, urlArg, callback); } @@ -105,10 +110,10 @@ public void onReceivedRequestError( WebResourceRequest request, WebResourceError error, Reply callback) { - final Long webViewIdentifier = instanceManager.getIdentifierForStrongReference(webView); - if (webViewIdentifier == null) { - throw new IllegalStateException("Could not find identifier for WebView."); - } + webViewFlutterApi.create(webView, reply -> {}); + + final Long webViewIdentifier = + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView)); onReceivedRequestError( getIdentifierForClient(webViewClient), webViewIdentifier, @@ -128,10 +133,10 @@ public void onReceivedRequestError( WebResourceRequest request, WebResourceErrorCompat error, Reply callback) { - final Long webViewIdentifier = instanceManager.getIdentifierForStrongReference(webView); - if (webViewIdentifier == null) { - throw new IllegalStateException("Could not find identifier for WebView."); - } + webViewFlutterApi.create(webView, reply -> {}); + + final Long webViewIdentifier = + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView)); onReceivedRequestError( getIdentifierForClient(webViewClient), webViewIdentifier, @@ -151,10 +156,10 @@ public void onReceivedError( String descriptionArg, String failingUrlArg, Reply callback) { - final Long webViewIdentifier = instanceManager.getIdentifierForStrongReference(webView); - if (webViewIdentifier == null) { - throw new IllegalStateException("Could not find identifier for WebView."); - } + webViewFlutterApi.create(webView, reply -> {}); + + final Long webViewIdentifier = + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView)); onReceivedError( getIdentifierForClient(webViewClient), webViewIdentifier, @@ -174,10 +179,10 @@ public void requestLoading( WebView webView, WebResourceRequest request, Reply callback) { - final Long webViewIdentifier = instanceManager.getIdentifierForStrongReference(webView); - if (webViewIdentifier == null) { - throw new IllegalStateException("Could not find identifier for WebView."); - } + webViewFlutterApi.create(webView, reply -> {}); + + final Long webViewIdentifier = + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView)); requestLoading( getIdentifierForClient(webViewClient), webViewIdentifier, @@ -190,10 +195,10 @@ public void requestLoading( */ public void urlLoading( WebViewClient webViewClient, WebView webView, String urlArg, Reply callback) { - final Long webViewIdentifier = instanceManager.getIdentifierForStrongReference(webView); - if (webViewIdentifier == null) { - throw new IllegalStateException("Could not find identifier for WebView."); - } + webViewFlutterApi.create(webView, reply -> {}); + + final Long webViewIdentifier = + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView)); urlLoading(getIdentifierForClient(webViewClient), webViewIdentifier, urlArg, callback); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterApiImpl.java new file mode 100644 index 0000000000000..d468cf8f189d8 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterApiImpl.java @@ -0,0 +1,59 @@ +// 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 android.webkit.WebView; +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewFlutterApi; + +/** + * Flutter API implementation for `WebView`. + * + *

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; + + private final InstanceManager instanceManager; + private WebViewFlutterApi api; + + /** + * Constructs a {@link WebViewFlutterApiImpl}. + * + * @param binaryMessenger used to communicate with Dart over asynchronous messages + * @param instanceManager maintains instances stored to communicate with attached Dart objects + */ + public WebViewFlutterApiImpl( + @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) { + this.binaryMessenger = binaryMessenger; + this.instanceManager = instanceManager; + api = new WebViewFlutterApi(binaryMessenger); + } + + /** + * Stores the `WebView` instance and notifies Dart to create and store a new `WebView` instance + * that is attached to this one. If `instance` has already been added, this method does nothing. + */ + public void create(@NonNull WebView instance, @NonNull WebViewFlutterApi.Reply callback) { + if (!instanceManager.containsInstance(instance)) { + api.create(instanceManager.addHostCreatedInstance(instance), callback); + } + } + + /** + * Sets the Flutter API used to send messages to Dart. + * + *

This is only visible for testing. + */ + @VisibleForTesting + void setApi(@NonNull WebViewFlutterApi api) { + this.api = api; + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java index e821537eda97f..be301fa49eade 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java @@ -47,8 +47,6 @@ public class WebChromeClientTest { public void setUp() { instanceManager = InstanceManager.open(identifier -> {}); - instanceManager.addDartCreatedInstance(mockWebView, 0L); - final WebChromeClientCreator webChromeClientCreator = new WebChromeClientCreator() { @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java index 3267291b2e998..b1cf1105771f2 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java @@ -43,8 +43,6 @@ public class WebViewClientTest { public void setUp() { instanceManager = InstanceManager.open(identifier -> {}); - instanceManager.addDartCreatedInstance(mockWebView, 0L); - final WebViewClientCreator webViewClientCreator = new WebViewClientCreator() { @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java index 1721ccdce8e4d..4a36184f03c6c 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -18,6 +19,7 @@ import android.webkit.WebChromeClient; import android.webkit.WebViewClient; import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewFlutterApi; import io.flutter.plugins.webviewflutter.WebViewHostApiImpl.WebViewPlatformView; import java.util.HashMap; import java.util.Objects; @@ -314,4 +316,23 @@ public void destroy() { assertTrue(destroyCalled[0]); } + + @Test + public void flutterApiCreate() { + final InstanceManager instanceManager = InstanceManager.open(identifier -> {}); + + final WebViewFlutterApiImpl flutterApiImpl = + new WebViewFlutterApiImpl(mockBinaryMessenger, instanceManager); + + final WebViewFlutterApi mockFlutterApi = mock(WebViewFlutterApi.class); + flutterApiImpl.setApi(mockFlutterApi); + + flutterApiImpl.create(mockWebView, reply -> {}); + + final long instanceIdentifier = + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(mockWebView)); + verify(mockFlutterApi).create(eq(instanceIdentifier), any()); + + instanceManager.close(); + } } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart index 6c9ba8e66fb06..ebfb0cc017f23 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart @@ -944,6 +944,43 @@ class WebViewHostApi { } } +/// Flutter API for `WebView`. +/// +/// This class may handle instantiating and adding Dart instances that are +/// attached to a native instance or receiving callback methods from an +/// overridden native class. +/// +/// See https://developer.android.com/reference/android/webkit/WebView. +abstract class WebViewFlutterApi { + static const MessageCodec codec = StandardMessageCodec(); + + /// Create a new Dart instance and add it to the `InstanceManager`. + void create(int identifier); + + static void setup(WebViewFlutterApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewFlutterApi.create', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewFlutterApi.create was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.WebViewFlutterApi.create was null, expected non-null int.'); + api.create(arg_identifier!); + return; + }); + } + } + } +} + class WebSettingsHostApi { /// Constructor for [WebSettingsHostApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index 0db0f0477273f..ce34673b43106 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -346,6 +346,33 @@ class WebViewHostApiImpl extends WebViewHostApi { } } +/// Flutter API implementation for [WebView]. +/// +/// This class may handle instantiating and adding Dart instances that are +/// attached to a native instance or receiving callback methods from an +/// overridden native class. +class WebViewFlutterApiImpl implements WebViewFlutterApi { + /// Constructs a [WebViewFlutterApiImpl]. + WebViewFlutterApiImpl({ + this.binaryMessenger, + InstanceManager? instanceManager, + }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + + /// Receives binary data across the Flutter platform barrier. + /// + /// If it is null, the default BinaryMessenger will be used which routes to + /// the host platform. + final BinaryMessenger? binaryMessenger; + + /// Maintains instances stored to communicate with native language objects. + final InstanceManager instanceManager; + + @override + void create(int identifier) { + instanceManager.addHostCreatedInstance(WebView.detached(), identifier); + } +} + /// Host api implementation for [WebSettings]. class WebSettingsHostApiImpl extends WebSettingsHostApi { /// Constructs a [WebSettingsHostApiImpl]. diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart index b8c22e56f1e63..20bc915559619 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -191,6 +191,19 @@ abstract class WebViewHostApi { void setBackgroundColor(int instanceId, int color); } +/// Flutter API for `WebView`. +/// +/// This class may handle instantiating and adding Dart instances that are +/// attached to a native instance or receiving callback methods from an +/// overridden native class. +/// +/// See https://developer.android.com/reference/android/webkit/WebView. +@FlutterApi() +abstract class WebViewFlutterApi { + /// Create a new Dart instance and add it to the `InstanceManager`. + void create(int identifier); +} + @HostApi(dartHostTestHandler: 'TestWebSettingsHostApi') abstract class WebSettingsHostApi { void create(int instanceId, int webViewInstanceId); diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 3217263130901..d38b866b13f46 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -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.4.0 +version: 3.4.1 environment: sdk: ">=2.17.0 <3.0.0" diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart index 79b5b3fdcd014..a6184724e600b 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart @@ -364,6 +364,24 @@ void main() { )); }); + test('FlutterAPI create', () { + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + + final WebViewFlutterApiImpl api = WebViewFlutterApiImpl( + instanceManager: instanceManager, + ); + + const int instanceIdentifier = 0; + api.create(instanceIdentifier); + + expect( + instanceManager.getInstanceWithWeakReference(instanceIdentifier), + isA(), + ); + }); + test('copy', () { expect(webView.copy(), isA()); });