Skip to content

Commit 6a2d543

Browse files
authored
[webview] Add new method for cross plugin webview access (#11714)
A new way of supporting cross plugin communication is coming in Flutter 3.44 which allows for access to plugin published values through the `FlutterPluginBinding` on Android and the `FlutterPluginRegistry` on iOS. Update native WebView access to support these new methods and deprecate the old methods. refs: flutter/flutter#121527 flutter/flutter#182753 ## Pre-Review Checklist
1 parent c584f33 commit 6a2d543

10 files changed

Lines changed: 155 additions & 36 deletions

File tree

packages/webview_flutter/webview_flutter_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 4.13.0
2+
3+
* Adds new method for accessing a native `WebView` from a `FlutterPluginBinding`.
4+
15
## 4.12.2
26

37
* Bumps the androidx group across 10 directories with 1 update.

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterAndroidExternalApi.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import androidx.annotation.NonNull;
99
import androidx.annotation.Nullable;
1010
import io.flutter.embedding.engine.FlutterEngine;
11+
import io.flutter.embedding.engine.plugins.FlutterPlugin;
1112

1213
/**
1314
* App and package facing native API provided by the `webview_flutter_android` plugin.
@@ -27,18 +28,44 @@ public interface WebViewFlutterAndroidExternalApi {
2728
* <p>See the Dart method `AndroidWebViewController.webViewIdentifier` to get the identifier of an
2829
* underlying `WebView`.
2930
*
31+
* @param binding the plugin binding provided by the Flutter engine. If the binding doesn't
32+
* contain an attached instance of {@link WebViewFlutterPlugin}, this method returns null.
33+
* @param identifier the associated identifier of the `WebView`.
34+
* @return the `WebView` associated with `identifier` or null if a `WebView` instance associated
35+
* with `identifier` could not be found.
36+
*/
37+
@Nullable
38+
static WebView getWebView(@NonNull FlutterPlugin.FlutterPluginBinding binding, long identifier) {
39+
final WebViewFlutterPlugin webViewPlugin =
40+
(WebViewFlutterPlugin) binding.getPlugin(WebViewFlutterPlugin.class);
41+
42+
return getWebViewFromPlugin(webViewPlugin, identifier);
43+
}
44+
45+
/**
46+
* Retrieves the {@link WebView} that is associated with `identifier`.
47+
*
48+
* <p>See the Dart method `AndroidWebViewController.webViewIdentifier` to get the identifier of an
49+
* underlying `WebView`.
50+
*
51+
* @deprecated Use {@link #getWebView(FlutterPlugin.FlutterPluginBinding, long)} instead.
3052
* @param engine the execution environment the {@link WebViewFlutterPlugin} should belong to. If
3153
* the engine doesn't contain an attached instance of {@link WebViewFlutterPlugin}, this
3254
* method returns null.
3355
* @param identifier the associated identifier of the `WebView`.
3456
* @return the `WebView` associated with `identifier` or null if a `WebView` instance associated
3557
* with `identifier` could not be found.
3658
*/
59+
@Deprecated
3760
@Nullable
3861
static WebView getWebView(@NonNull FlutterEngine engine, long identifier) {
3962
final WebViewFlutterPlugin webViewPlugin =
4063
(WebViewFlutterPlugin) engine.getPlugins().get(WebViewFlutterPlugin.class);
4164

65+
return getWebViewFromPlugin(webViewPlugin, identifier);
66+
}
67+
68+
private static WebView getWebViewFromPlugin(WebViewFlutterPlugin webViewPlugin, long identifier) {
4269
if (webViewPlugin != null && webViewPlugin.getInstanceManager() != null) {
4370
final Object instance = webViewPlugin.getInstanceManager().getInstance(identifier);
4471
if (instance instanceof WebView) {

packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewFlutterAndroidExternalApiTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import static org.junit.Assert.assertEquals;
88
import static org.junit.Assert.assertNotNull;
9+
import static org.junit.Assert.assertNull;
910
import static org.mockito.Mockito.mock;
1011
import static org.mockito.Mockito.when;
1112

@@ -33,6 +34,7 @@ public class WebViewFlutterAndroidExternalApiTest {
3334

3435
@Mock FlutterPlugin.FlutterPluginBinding mockPluginBinding;
3536

37+
@SuppressWarnings("deprecation")
3638
@Test
3739
public void getWebView() {
3840
final WebViewFlutterPlugin webViewFlutterPlugin = new WebViewFlutterPlugin();
@@ -60,4 +62,34 @@ public void getWebView() {
6062

6163
webViewFlutterPlugin.onDetachedFromEngine(mockPluginBinding);
6264
}
65+
66+
@Test
67+
public void getWebViewFromBinding() {
68+
final WebViewFlutterPlugin webViewFlutterPlugin = new WebViewFlutterPlugin();
69+
70+
when(mockPluginBinding.getApplicationContext()).thenReturn(mockContext);
71+
when(mockPluginBinding.getPlatformViewRegistry()).thenReturn(mockViewRegistry);
72+
when(mockPluginBinding.getBinaryMessenger()).thenReturn(mockBinaryMessenger);
73+
74+
webViewFlutterPlugin.onAttachedToEngine(mockPluginBinding);
75+
76+
final AndroidWebkitLibraryPigeonInstanceManager instanceManager =
77+
webViewFlutterPlugin.getInstanceManager();
78+
assertNotNull(instanceManager);
79+
80+
final WebView mockWebView = mock(WebView.class);
81+
instanceManager.addDartCreatedInstance(mockWebView, 0);
82+
83+
when(mockPluginBinding.getPlugin(WebViewFlutterPlugin.class)).thenReturn(webViewFlutterPlugin);
84+
85+
assertEquals(WebViewFlutterAndroidExternalApi.getWebView(mockPluginBinding, 0), mockWebView);
86+
87+
webViewFlutterPlugin.onDetachedFromEngine(mockPluginBinding);
88+
}
89+
90+
@Test
91+
public void getWebViewFromBindingReturnsNullForUnknownPlugin() {
92+
when(mockPluginBinding.getPlugin(WebViewFlutterPlugin.class)).thenReturn(null);
93+
assertNull(WebViewFlutterAndroidExternalApi.getWebView(mockPluginBinding, 0));
94+
}
6395
}

packages/webview_flutter/webview_flutter_android/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: webview_flutter_android
22
description: A Flutter plugin that provides a WebView widget on Android.
33
repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 4.12.2
5+
version: 4.13.0
66

77
environment:
88
sdk: ^3.12.0

packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 3.26.0
2+
3+
* Adds new method for accessing a native `WKWebView` from a `FlutterPluginRegistrar`.
4+
* Updates minimum supported SDK version to Flutter 3.44/Dart 3.12.
5+
16
## 3.25.1
27

38
* Relands update to prevent message calls when application will terminate.

packages/webview_flutter/webview_flutter_wkwebview/darwin/Tests/FWFWebViewFlutterWKWebViewExternalAPITests.swift

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ class FWFWebViewFlutterWKWebViewExternalAPITests: XCTestCase {
2727

2828
WebViewFlutterPlugin.register(with: registrar)
2929

30-
let plugin = registry.registrar.plugin as! WebViewFlutterPlugin?
30+
let plugin = registry.registrar.publishedValue as! WebViewFlutterPlugin
3131

3232
let webView = WKWebView(frame: .zero)
3333
let webViewIdentifier = 0
34-
plugin?.proxyApiRegistrar?.instanceManager.addDartCreatedInstance(
34+
plugin.proxyApiRegistrar?.instanceManager.addDartCreatedInstance(
3535
webView, withIdentifier: Int64(webViewIdentifier))
3636

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

4242
@MainActor func testWebViewForIdentifierHandlesIncorrectRegistry() {
43-
let registry = TestRegistry(publishedValue: false)
43+
let registry = TestRegistry()
4444
// Ensure that passing an empty registry, such as the FlutterAppDelegate
4545
// in an app that has adopted UIScene, gracefully returns nil.
4646
let result = FWFWebViewFlutterWKWebViewExternalAPI.webView(
4747
forIdentifier: 0, withPluginRegistry: registry)
4848
XCTAssertEqual(result, nil)
4949
}
50+
51+
// FlutterPluginRegistrar.valuePublished(byPlugin:) is not available on macOS. This
52+
// can be removed once this method becomes available.
53+
// See https://github.com/flutter/flutter/issues/186911.
54+
#if os(iOS)
55+
@MainActor func testWebViewForIdentifierFromRegistrar() {
56+
let registry = TestRegistry()
57+
58+
#if os(iOS)
59+
let registrar = registry.registrar(forPlugin: "")!
60+
#elseif os(macOS)
61+
let registrar = registry.registrar(forPlugin: "")
62+
#endif
63+
64+
WebViewFlutterPlugin.register(with: registrar)
65+
66+
let plugin = registry.registrar.publishedValue as! WebViewFlutterPlugin
67+
68+
let webView = WKWebView(frame: .zero)
69+
let webViewIdentifier = 0
70+
plugin.proxyApiRegistrar?.instanceManager.addDartCreatedInstance(
71+
webView, withIdentifier: Int64(webViewIdentifier))
72+
73+
let result = FWFWebViewFlutterWKWebViewExternalAPI.webView(
74+
forIdentifier: Int64(webViewIdentifier), withPluginRegistrar: registrar)
75+
XCTAssertEqual(result, webView)
76+
}
77+
78+
@MainActor func testWebViewForIdentifierHandlesIncorrectRegistrar() {
79+
let registrar = TestFlutterPluginRegistrar()
80+
// Ensure that passing an empty registry, such as the FlutterAppDelegate
81+
// in an app that has adopted UIScene, gracefully returns nil.
82+
let result = FWFWebViewFlutterWKWebViewExternalAPI.webView(
83+
forIdentifier: 0, withPluginRegistrar: registrar)
84+
XCTAssertEqual(result, nil)
85+
}
86+
#endif
5087
}
5188

5289
class TestRegistry: NSObject, FlutterPluginRegistry {
5390
let registrar = TestFlutterPluginRegistrar()
54-
let publishedValue: Bool
55-
56-
init(publishedValue: Bool) {
57-
self.publishedValue = publishedValue
58-
}
59-
60-
convenience override init() {
61-
self.init(publishedValue: true)
62-
}
6391

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

78106
func valuePublished(byPlugin pluginKey: String) -> NSObject? {
79-
if publishedValue && pluginKey == "WebViewFlutterPlugin" {
80-
return registrar.plugin
81-
}
82-
return nil
107+
return registrar.publishedValue
83108
}
84109
}
85110

@@ -98,7 +123,7 @@ class TestFlutterTextureRegistry: NSObject, FlutterTextureRegistry {
98123
}
99124

100125
class TestFlutterPluginRegistrar: NSObject, FlutterPluginRegistrar {
101-
var plugin: WebViewFlutterPlugin? = nil
126+
var publishedValue: NSObject? = nil
102127

103128
#if os(iOS)
104129
var viewController: UIViewController?
@@ -144,7 +169,7 @@ class TestFlutterPluginRegistrar: NSObject, FlutterPluginRegistrar {
144169
}
145170

146171
func publish(_ value: NSObject) {
147-
plugin = (value as! WebViewFlutterPlugin)
172+
publishedValue = value
148173
}
149174

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

162-
func valuePublished(byPlugin: String) -> NSObject? {
187+
func valuePublished(byPlugin pluginKey: String) -> NSObject? {
188+
if pluginKey == "WebViewFlutterPlugin" {
189+
return publishedValue
190+
}
163191
return nil
164192
}
165193
}

packages/webview_flutter/webview_flutter_wkwebview/darwin/webview_flutter_wkwebview/Sources/webview_flutter_wkwebview/WebViewFlutterWKWebViewExternalAPI.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ public class FWFWebViewFlutterWKWebViewExternalAPI: NSObject {
2424
///
2525
/// See the Dart method `WebKitWebViewController.webViewIdentifier` to get the identifier of an
2626
/// underlying `WKWebView`.
27+
#if os(iOS)
28+
// Only deprecate this method on iOS until FlutterPluginRegistrar.valuePublished(byPlugin:) is
29+
// available on macOS. See https://github.com/flutter/flutter/issues/186911.
30+
@available(*, deprecated, message: "Use webView(forIdentifier:withPluginRegistrar:) instead.")
31+
#endif
2732
@objc(webViewForIdentifier:withPluginRegistry:)
2833
public static func webView(
2934
forIdentifier identifier: Int64, withPluginRegistry registry: FlutterPluginRegistry
@@ -33,7 +38,33 @@ public class FWFWebViewFlutterWKWebViewExternalAPI: NSObject {
3338
return nil
3439
}
3540

36-
let webView: WKWebView? = webviewPlugin.proxyApiRegistrar?.instanceManager.instance(
41+
return webview(forIdentifier: identifier, withPlugin: webviewPlugin)
42+
}
43+
44+
// This method is only available on iOS until FlutterPluginRegistrar.valuePublished(byPlugin:) is
45+
// available on macOS. See https://github.com/flutter/flutter/issues/186911.
46+
#if os(iOS)
47+
/// Retrieves the `WKWebView` that is associated with `identifier` using a FlutterPluginRegistrar
48+
///
49+
/// See the Dart method `WebKitWebViewController.webViewIdentifier` to get the identifier of an
50+
/// underlying `WKWebView`.
51+
@objc(webViewForIdentifier:withPluginRegistrar:)
52+
public static func webView(
53+
forIdentifier identifier: Int64, withPluginRegistrar registrar: FlutterPluginRegistrar
54+
) -> WKWebView? {
55+
let plugin = registrar.valuePublished(byPlugin: "WebViewFlutterPlugin")
56+
guard let webviewPlugin = plugin as? WebViewFlutterPlugin else {
57+
return nil
58+
}
59+
60+
return webview(forIdentifier: identifier, withPlugin: webviewPlugin)
61+
}
62+
#endif
63+
64+
private static func webview(forIdentifier identifier: Int64, withPlugin: WebViewFlutterPlugin)
65+
-> WKWebView?
66+
{
67+
let webView: WKWebView? = withPlugin.proxyApiRegistrar?.instanceManager.instance(
3768
forIdentifier: identifier)
3869
return webView
3970
}

packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_ssl_auth_error.dart

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,11 @@ class WebKitSslAuthError extends PlatformSslAuthError {
1414
WebKitSslAuthError({
1515
required super.certificate,
1616
required super.description,
17-
required SecTrust trust,
17+
required this._trust,
1818
required this.host,
1919
required this.port,
20-
required Future<void> Function(
21-
UrlSessionAuthChallengeDisposition disposition,
22-
URLCredential? credential,
23-
)
24-
onResponse,
25-
}) : _trust = trust,
26-
_onResponse = onResponse;
20+
required this._onResponse,
21+
});
2722

2823
final SecTrust _trust;
2924

packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,10 +1353,7 @@ class WebKitNavigationDelegate extends PlatformNavigationDelegate {
13531353

13541354
/// WebKit implementation of [PlatformWebViewPermissionRequest].
13551355
class WebKitWebViewPermissionRequest extends PlatformWebViewPermissionRequest {
1356-
const WebKitWebViewPermissionRequest._({
1357-
required super.types,
1358-
required void Function(PermissionDecision decision) onDecision,
1359-
}) : _onDecision = onDecision;
1356+
const WebKitWebViewPermissionRequest._({required super.types, required this._onDecision});
13601357

13611358
final void Function(PermissionDecision) _onDecision;
13621359

packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ name: webview_flutter_wkwebview
22
description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
33
repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_wkwebview
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 3.25.1
5+
version: 3.26.0
66

77
environment:
8-
sdk: ^3.10.0
9-
flutter: ">=3.38.0"
8+
sdk: ^3.12.0
9+
flutter: ">=3.44.0"
1010

1111
flutter:
1212
plugin:

0 commit comments

Comments
 (0)