Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## NEXT
## 4.13.0

* Adds new method for accessing a native `WebView` from a `FlutterPluginBinding`.
* Updates minimum supported SDK version to Flutter 3.38/Dart 3.10.

## 4.12.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.plugins.FlutterPlugin;

/**
* App and package facing native API provided by the `webview_flutter_android` plugin.
Expand All @@ -27,18 +28,44 @@ public interface WebViewFlutterAndroidExternalApi {
* <p>See the Dart method `AndroidWebViewController.webViewIdentifier` to get the identifier of an
* underlying `WebView`.
*
* @param binding the plugin binding provided by the Flutter engine. If the binding doesn't
* contain an attached instance of {@link WebViewFlutterPlugin}, this method returns null.
* @param identifier the associated identifier of the `WebView`.
* @return the `WebView` associated with `identifier` or null if a `WebView` instance associated
* with `identifier` could not be found.
*/
@Nullable
static WebView getWebView(@NonNull FlutterPlugin.FlutterPluginBinding binding, long identifier) {
final WebViewFlutterPlugin webViewPlugin =
(WebViewFlutterPlugin) binding.getPlugin(WebViewFlutterPlugin.class);

return getWebViewFromPlugin(webViewPlugin, identifier);
}

/**
* Retrieves the {@link WebView} that is associated with `identifier`.
*
* <p>See the Dart method `AndroidWebViewController.webViewIdentifier` to get the identifier of an
* underlying `WebView`.
*
* @deprecated Use {@link #getWebView(FlutterPlugin.FlutterPluginBinding, long)} instead.
* @param engine the execution environment the {@link WebViewFlutterPlugin} should belong to. If
* the engine doesn't contain an attached instance of {@link WebViewFlutterPlugin}, this
* method returns null.
* @param identifier the associated identifier of the `WebView`.
* @return the `WebView` associated with `identifier` or null if a `WebView` instance associated
* with `identifier` could not be found.
*/
@Deprecated
@Nullable
static WebView getWebView(@NonNull FlutterEngine engine, long identifier) {
final WebViewFlutterPlugin webViewPlugin =
(WebViewFlutterPlugin) engine.getPlugins().get(WebViewFlutterPlugin.class);

return getWebViewFromPlugin(webViewPlugin, identifier);
}

private static WebView getWebViewFromPlugin(WebViewFlutterPlugin webViewPlugin, long identifier) {
if (webViewPlugin != null && webViewPlugin.getInstanceManager() != null) {
final Object instance = webViewPlugin.getInstanceManager().getInstance(identifier);
if (instance instanceof WebView) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -33,6 +34,7 @@ public class WebViewFlutterAndroidExternalApiTest {

@Mock FlutterPlugin.FlutterPluginBinding mockPluginBinding;

@SuppressWarnings("deprecation")
@Test
public void getWebView() {
final WebViewFlutterPlugin webViewFlutterPlugin = new WebViewFlutterPlugin();
Expand Down Expand Up @@ -60,4 +62,34 @@ public void getWebView() {

webViewFlutterPlugin.onDetachedFromEngine(mockPluginBinding);
}

@Test
public void getWebViewFromBinding() {
final WebViewFlutterPlugin webViewFlutterPlugin = new WebViewFlutterPlugin();

when(mockPluginBinding.getApplicationContext()).thenReturn(mockContext);
when(mockPluginBinding.getPlatformViewRegistry()).thenReturn(mockViewRegistry);
when(mockPluginBinding.getBinaryMessenger()).thenReturn(mockBinaryMessenger);

webViewFlutterPlugin.onAttachedToEngine(mockPluginBinding);

final AndroidWebkitLibraryPigeonInstanceManager instanceManager =
webViewFlutterPlugin.getInstanceManager();
assertNotNull(instanceManager);

final WebView mockWebView = mock(WebView.class);
instanceManager.addDartCreatedInstance(mockWebView, 0);

when(mockPluginBinding.getPlugin(WebViewFlutterPlugin.class)).thenReturn(webViewFlutterPlugin);

assertEquals(WebViewFlutterAndroidExternalApi.getWebView(mockPluginBinding, 0), mockWebView);

webViewFlutterPlugin.onDetachedFromEngine(mockPluginBinding);
}

@Test
public void getWebViewFromBindingReturnsNullForUnknownPlugin() {
when(mockPluginBinding.getPlugin(WebViewFlutterPlugin.class)).thenReturn(null);
assertNull(WebViewFlutterAndroidExternalApi.getWebView(mockPluginBinding, 0));
}
}
6 changes: 3 additions & 3 deletions packages/webview_flutter/webview_flutter_android/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ 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: 4.12.0
version: 4.13.0

environment:
sdk: ^3.10.0
flutter: ">=3.38.0"
sdk: ^3.12.0
flutter: ">=3.44.0"

flutter:
plugin:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.26.0

* Adds new method for accessing a native `WKWebView` from a `FlutterPluginRegistrar`.

## 3.25.1

* Relands update to prevent message calls when application will terminate.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ class FWFWebViewFlutterWKWebViewExternalAPITests: XCTestCase {

WebViewFlutterPlugin.register(with: registrar)

let plugin = registry.registrar.plugin as! WebViewFlutterPlugin?
let plugin = registry.registrar.publishedValue as! WebViewFlutterPlugin

let webView = WKWebView(frame: .zero)
let webViewIdentifier = 0
plugin?.proxyApiRegistrar?.instanceManager.addDartCreatedInstance(
plugin.proxyApiRegistrar?.instanceManager.addDartCreatedInstance(
webView, withIdentifier: Int64(webViewIdentifier))

let result = FWFWebViewFlutterWKWebViewExternalAPI.webView(
Expand All @@ -40,26 +40,54 @@ class FWFWebViewFlutterWKWebViewExternalAPITests: XCTestCase {
}

@MainActor func testWebViewForIdentifierHandlesIncorrectRegistry() {
let registry = TestRegistry(publishedValue: false)
let registry = TestRegistry()
// Ensure that passing an empty registry, such as the FlutterAppDelegate
// in an app that has adopted UIScene, gracefully returns nil.
let result = FWFWebViewFlutterWKWebViewExternalAPI.webView(
forIdentifier: 0, withPluginRegistry: registry)
XCTAssertEqual(result, nil)
}

// FlutterPluginRegistrar.valuePublished(byPlugin:) is not available on macOS. This
// can be removed once this method becomes available.
// See https://github.com/flutter/flutter/issues/186911.
#if os(iOS)
@MainActor func testWebViewForIdentifierFromRegistrar() {
let registry = TestRegistry()

#if os(iOS)
let registrar = registry.registrar(forPlugin: "")!
#elseif os(macOS)
let registrar = registry.registrar(forPlugin: "")
#endif

WebViewFlutterPlugin.register(with: registrar)

let plugin = registry.registrar.publishedValue as! WebViewFlutterPlugin

let webView = WKWebView(frame: .zero)
let webViewIdentifier = 0
plugin.proxyApiRegistrar?.instanceManager.addDartCreatedInstance(
webView, withIdentifier: Int64(webViewIdentifier))

let result = FWFWebViewFlutterWKWebViewExternalAPI.webView(
forIdentifier: Int64(webViewIdentifier), withPluginRegistrar: registrar)
XCTAssertEqual(result, webView)
}

@MainActor func testWebViewForIdentifierHandlesIncorrectRegistrar() {
let registrar = TestFlutterPluginRegistrar()
// Ensure that passing an empty registry, such as the FlutterAppDelegate
// in an app that has adopted UIScene, gracefully returns nil.
let result = FWFWebViewFlutterWKWebViewExternalAPI.webView(
forIdentifier: 0, withPluginRegistrar: registrar)
XCTAssertEqual(result, nil)
}
#endif
}

class TestRegistry: NSObject, FlutterPluginRegistry {
let registrar = TestFlutterPluginRegistrar()
let publishedValue: Bool

init(publishedValue: Bool) {
self.publishedValue = publishedValue
}

convenience override init() {
self.init(publishedValue: true)
}

#if os(iOS)
func registrar(forPlugin pluginKey: String) -> FlutterPluginRegistrar? {
Expand All @@ -76,10 +104,7 @@ class TestRegistry: NSObject, FlutterPluginRegistry {
}

func valuePublished(byPlugin pluginKey: String) -> NSObject? {
if publishedValue && pluginKey == "WebViewFlutterPlugin" {
return registrar.plugin
}
return nil
return registrar.publishedValue
}
}

Expand All @@ -98,7 +123,7 @@ class TestFlutterTextureRegistry: NSObject, FlutterTextureRegistry {
}

class TestFlutterPluginRegistrar: NSObject, FlutterPluginRegistrar {
var plugin: WebViewFlutterPlugin? = nil
var publishedValue: NSObject? = nil

#if os(iOS)
var viewController: UIViewController?
Expand Down Expand Up @@ -144,7 +169,7 @@ class TestFlutterPluginRegistrar: NSObject, FlutterPluginRegistrar {
}

func publish(_ value: NSObject) {
plugin = (value as! WebViewFlutterPlugin)
publishedValue = value
}

func addMethodCallDelegate(_ delegate: FlutterPlugin, channel: FlutterMethodChannel) {
Expand All @@ -159,7 +184,10 @@ class TestFlutterPluginRegistrar: NSObject, FlutterPluginRegistrar {
return ""
}

func valuePublished(byPlugin: String) -> NSObject? {
func valuePublished(byPlugin pluginKey: String) -> NSObject? {
if pluginKey == "WebViewFlutterPlugin" {
return publishedValue
}
return nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public class FWFWebViewFlutterWKWebViewExternalAPI: NSObject {
///
/// See the Dart method `WebKitWebViewController.webViewIdentifier` to get the identifier of an
/// underlying `WKWebView`.
#if os(iOS)
// Only deprecate this method on iOS until FlutterPluginRegistrar.valuePublished(byPlugin:) is
// available on macOS. See https://github.com/flutter/flutter/issues/186911.
@available(*, deprecated, message: "Use webView(forIdentifier:withPluginRegistrar:) instead.")
#endif
@objc(webViewForIdentifier:withPluginRegistry:)
public static func webView(
forIdentifier identifier: Int64, withPluginRegistry registry: FlutterPluginRegistry
Expand All @@ -33,7 +38,33 @@ public class FWFWebViewFlutterWKWebViewExternalAPI: NSObject {
return nil
}

let webView: WKWebView? = webviewPlugin.proxyApiRegistrar?.instanceManager.instance(
return webview(forIdentifier: identifier, withPlugin: webviewPlugin)
}

// This method is only available on iOS until FlutterPluginRegistrar.valuePublished(byPlugin:) is
// available on macOS. See https://github.com/flutter/flutter/issues/186911.
#if os(iOS)
/// Retrieves the `WKWebView` that is associated with `identifier` using a FlutterPluginRegistrar
///
/// See the Dart method `WebKitWebViewController.webViewIdentifier` to get the identifier of an
/// underlying `WKWebView`.
@objc(webViewForIdentifier:withPluginRegistrar:)
public static func webView(
forIdentifier identifier: Int64, withPluginRegistrar registrar: FlutterPluginRegistrar
) -> WKWebView? {
let plugin = registrar.valuePublished(byPlugin: "WebViewFlutterPlugin")
guard let webviewPlugin = plugin as? WebViewFlutterPlugin else {
return nil
}

return webview(forIdentifier: identifier, withPlugin: webviewPlugin)
}
#endif

private static func webview(forIdentifier identifier: Int64, withPlugin: WebViewFlutterPlugin)
-> WKWebView?
{
let webView: WKWebView? = withPlugin.proxyApiRegistrar?.instanceManager.instance(
forIdentifier: identifier)
return webView
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ name: webview_flutter_wkwebview
description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_wkwebview
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
version: 3.25.1
version: 3.26.0

environment:
sdk: ^3.10.0
flutter: ">=3.38.0"
sdk: ^3.12.0
flutter: ">=3.44.0"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@stuartmorgan-g Does this PR need to wait until we bump all the plugins in the repo to 3.44? This isn't fixing a bug, so I don't think it is an exemption to support n-2 stable version.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We don't require supporting N-2, we just don't allow supporting things older than N-2. We only require supporting stable.

This will need wait until Flutter master rolls to a version that reports being newer than a 3.44 pre-release though so that the resolver works (the usual problem we have with master right after a release).


flutter:
plugin:
Expand Down