Skip to content

Commit e212d61

Browse files
[webview_flutter_wkwebview] Tear down ProxyAPIRegistrar in applicationWillTerminate (#11567)
Relands #11484 ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent 5653b5a commit e212d61

7 files changed

Lines changed: 147 additions & 9 deletions

File tree

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.25.1
2+
3+
* Relands update to prevent message calls when application will terminate.
4+
* Updates minimum supported SDK version to Flutter 3.38/Dart 3.10.
5+
16
## 3.25.0
27

38
* Adds support for retrieving cookies with `PlatformWebViewCookieManager.getCookies`.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright 2013 The Flutter Authors
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import XCTest
6+
7+
@testable import webview_flutter_wkwebview
8+
9+
#if os(iOS)
10+
import Flutter
11+
import UIKit
12+
#endif
13+
14+
class WebViewFlutterPluginTests: XCTestCase {
15+
#if os(iOS)
16+
func testInstanceManagerIsDeallocatedInApplicationWillTerminate() {
17+
let plugin = WebViewFlutterPlugin(binaryMessenger: TestBinaryMessenger())
18+
plugin.proxyApiRegistrar!.setUp()
19+
20+
let view = UIView()
21+
_ = plugin.proxyApiRegistrar!.instanceManager.addHostCreatedInstance(view)
22+
23+
// Attaches an associated object to the InstanceManager to listen for when it is deallocated.
24+
var finalizer: TestFinalizer? = TestFinalizer()
25+
26+
let key = malloc(1)!
27+
defer {
28+
free(key)
29+
}
30+
objc_setAssociatedObject(
31+
plugin.proxyApiRegistrar!.instanceManager, key, finalizer, .OBJC_ASSOCIATION_RETAIN)
32+
let expectation = self.expectation(description: "Wait for InstanceManager to be deallocated.")
33+
TestFinalizer.onDeinit = {
34+
expectation.fulfill()
35+
}
36+
37+
// Ensure method is from `FlutterApplicationLifeCycleDelegate`.
38+
(plugin as FlutterApplicationLifeCycleDelegate).applicationWillTerminate!(
39+
UIApplication.shared)
40+
XCTAssertNil(plugin.proxyApiRegistrar)
41+
42+
finalizer = nil
43+
waitForExpectations(timeout: 5.0)
44+
}
45+
46+
func testInstanceManagerIsDeallocatedInSceneDidDisconnect() {
47+
let plugin = WebViewFlutterPlugin(binaryMessenger: TestBinaryMessenger())
48+
plugin.proxyApiRegistrar!.setUp()
49+
50+
let view = UIView()
51+
_ = plugin.proxyApiRegistrar!.instanceManager.addHostCreatedInstance(view)
52+
53+
// Attaches an associated object to the InstanceManager to listen for when it is deallocated.
54+
var finalizer: TestFinalizer? = TestFinalizer()
55+
56+
let key = malloc(1)!
57+
defer {
58+
free(key)
59+
}
60+
objc_setAssociatedObject(
61+
plugin.proxyApiRegistrar!.instanceManager, key, finalizer, .OBJC_ASSOCIATION_RETAIN)
62+
let expectation = self.expectation(description: "Wait for InstanceManager to be deallocated.")
63+
TestFinalizer.onDeinit = {
64+
expectation.fulfill()
65+
}
66+
67+
let scene = UIApplication.shared.connectedScenes.first!
68+
69+
// Ensure method is from `FlutterSceneLifeCycleDelegate`.
70+
(plugin as FlutterSceneLifeCycleDelegate).sceneDidDisconnect?(scene)
71+
XCTAssertNil(plugin.proxyApiRegistrar)
72+
73+
finalizer = nil
74+
waitForExpectations(timeout: 5.0)
75+
}
76+
#endif
77+
}
78+
79+
class TestFinalizer {
80+
static var onDeinit: (() -> Void)?
81+
82+
deinit {
83+
Self.onDeinit?()
84+
}
85+
}

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,37 @@ public class WebViewFlutterPlugin: NSObject, FlutterPlugin {
2828
let plugin = WebViewFlutterPlugin(binaryMessenger: binaryMessenger)
2929

3030
let viewFactory = FlutterViewFactory(instanceManager: plugin.proxyApiRegistrar!.instanceManager)
31+
32+
#if os(iOS)
33+
registrar.addApplicationDelegate(plugin)
34+
registrar.addSceneDelegate(plugin)
35+
#endif
36+
3137
registrar.register(viewFactory, withId: "plugins.flutter.io/webview")
3238
registrar.publish(plugin)
3339
}
3440

3541
public func detachFromEngine(for registrar: FlutterPluginRegistrar) {
36-
proxyApiRegistrar!.ignoreCallsToDart = true
37-
proxyApiRegistrar!.tearDown()
42+
tearDownProxyAPIRegistrar()
43+
}
44+
45+
private func tearDownProxyAPIRegistrar() {
46+
proxyApiRegistrar?.ignoreCallsToDart = true
47+
proxyApiRegistrar?.tearDown()
48+
try? proxyApiRegistrar?.instanceManager.removeAllObjects()
3849
proxyApiRegistrar = nil
3950
}
4051
}
52+
53+
#if os(iOS)
54+
extension WebViewFlutterPlugin: FlutterApplicationLifeCycleDelegate, FlutterSceneLifeCycleDelegate
55+
{
56+
public func applicationWillTerminate(_ application: UIApplication) {
57+
tearDownProxyAPIRegistrar()
58+
}
59+
60+
public func sceneDidDisconnect(_ scene: UIScene) {
61+
tearDownProxyAPIRegistrar()
62+
}
63+
}
64+
#endif

packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
8F1488FE2D2DE27000191744 /* HTTPCookieProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F1488C82D2DE27000191744 /* HTTPCookieProxyAPITests.swift */; };
4343
8F1488FF2D2DE27000191744 /* NavigationActionProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F1488CB2D2DE27000191744 /* NavigationActionProxyAPITests.swift */; };
4444
8F1489012D2DE91C00191744 /* AuthenticationChallengeResponseProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F1489002D2DE91C00191744 /* AuthenticationChallengeResponseProxyAPITests.swift */; };
45+
8F63D06B2F8812E400EC5076 /* WebViewFlutterPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F63D06A2F8812E400EC5076 /* WebViewFlutterPluginTests.swift */; };
46+
8F63D06C2F8812E400EC5076 /* PlatformViewImplTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F63D0692F8812E400EC5076 /* PlatformViewImplTests.swift */; };
4547
8FEC64852DA2C6DC00C48569 /* GetTrustResultResponseProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FEC64812DA2C6DC00C48569 /* GetTrustResultResponseProxyAPITests.swift */; };
4648
8FEC64862DA2C6DC00C48569 /* WebpagePreferencesProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FEC64842DA2C6DC00C48569 /* WebpagePreferencesProxyAPITests.swift */; };
4749
8FEC64872DA2C6DC00C48569 /* SecCertificateProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FEC64822DA2C6DC00C48569 /* SecCertificateProxyAPITests.swift */; };
@@ -128,6 +130,8 @@
128130
8F1488E02D2DE27000191744 /* WebViewConfigurationProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WebViewConfigurationProxyAPITests.swift; path = ../../darwin/Tests/WebViewConfigurationProxyAPITests.swift; sourceTree = SOURCE_ROOT; };
129131
8F1488E12D2DE27000191744 /* WebViewProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WebViewProxyAPITests.swift; path = ../../darwin/Tests/WebViewProxyAPITests.swift; sourceTree = SOURCE_ROOT; };
130132
8F1489002D2DE91C00191744 /* AuthenticationChallengeResponseProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AuthenticationChallengeResponseProxyAPITests.swift; path = ../../darwin/Tests/AuthenticationChallengeResponseProxyAPITests.swift; sourceTree = SOURCE_ROOT; };
133+
8F63D0692F8812E400EC5076 /* PlatformViewImplTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PlatformViewImplTests.swift; path = ../../darwin/Tests/PlatformViewImplTests.swift; sourceTree = SOURCE_ROOT; };
134+
8F63D06A2F8812E400EC5076 /* WebViewFlutterPluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WebViewFlutterPluginTests.swift; path = ../../darwin/Tests/WebViewFlutterPluginTests.swift; sourceTree = SOURCE_ROOT; };
131135
8FEC64812DA2C6DC00C48569 /* GetTrustResultResponseProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GetTrustResultResponseProxyAPITests.swift; path = ../../darwin/Tests/GetTrustResultResponseProxyAPITests.swift; sourceTree = SOURCE_ROOT; };
132136
8FEC64822DA2C6DC00C48569 /* SecCertificateProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SecCertificateProxyAPITests.swift; path = ../../darwin/Tests/SecCertificateProxyAPITests.swift; sourceTree = SOURCE_ROOT; };
133137
8FEC64832DA2C6DC00C48569 /* SecTrustProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SecTrustProxyAPITests.swift; path = ../../darwin/Tests/SecTrustProxyAPITests.swift; sourceTree = SOURCE_ROOT; };
@@ -174,6 +178,8 @@
174178
68BDCAEA23C3F7CB00D9C032 /* RunnerTests */ = {
175179
isa = PBXGroup;
176180
children = (
181+
8F63D0692F8812E400EC5076 /* PlatformViewImplTests.swift */,
182+
8F63D06A2F8812E400EC5076 /* WebViewFlutterPluginTests.swift */,
177183
8F0E23512EEB5D6B002AB342 /* ColorProxyAPITests.swift */,
178184
8F0EDFD22E1F4967001938E6 /* ProxyAPIRegistrarTests.swift */,
179185
8FEC64812DA2C6DC00C48569 /* GetTrustResultResponseProxyAPITests.swift */,
@@ -498,6 +504,8 @@
498504
8F1488F42D2DE27000191744 /* URLCredentialProxyAPITests.swift in Sources */,
499505
8F1488F52D2DE27000191744 /* URLAuthenticationChallengeProxyAPITests.swift in Sources */,
500506
8F1488F62D2DE27000191744 /* NavigationDelegateProxyAPITests.swift in Sources */,
507+
8F63D06B2F8812E400EC5076 /* WebViewFlutterPluginTests.swift in Sources */,
508+
8F63D06C2F8812E400EC5076 /* PlatformViewImplTests.swift in Sources */,
501509
8F1488F72D2DE27000191744 /* UIDelegateProxyAPITests.swift in Sources */,
502510
8F1488F82D2DE27000191744 /* ScrollViewDelegateProxyAPITests.swift in Sources */,
503511
8F1488FA2D2DE27000191744 /* FWFWebViewFlutterWKWebViewExternalAPITests.swift in Sources */,

packages/webview_flutter/webview_flutter_wkwebview/example/macos/Runner.xcodeproj/project.pbxproj

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@
6161
8FF1FEBD2D37201300A5E400 /* ScriptMessageProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FF1FE912D37201300A5E400 /* ScriptMessageProxyAPITests.swift */; };
6262
8FF1FEBE2D37201300A5E400 /* FrameInfoProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FF1FE862D37201300A5E400 /* FrameInfoProxyAPITests.swift */; };
6363
8FF1FEBF2D37201300A5E400 /* HTTPCookieProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FF1FE882D37201300A5E400 /* HTTPCookieProxyAPITests.swift */; };
64+
8FFBB0682FA1019E00F6659D /* PlatformViewImplTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FFBB0652FA1019E00F6659D /* PlatformViewImplTests.swift */; };
65+
8FFBB0692FA1019E00F6659D /* ColorProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FFBB0642FA1019E00F6659D /* ColorProxyAPITests.swift */; };
66+
8FFBB06A2FA1019E00F6659D /* ProxyAPIRegistrarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FFBB0662FA1019E00F6659D /* ProxyAPIRegistrarTests.swift */; };
67+
8FFBB06B2FA1019E00F6659D /* WebViewFlutterPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FFBB0672FA1019E00F6659D /* WebViewFlutterPluginTests.swift */; };
6468
/* End PBXBuildFile section */
6569

6670
/* Begin PBXContainerItemProxy section */
@@ -148,6 +152,10 @@
148152
8FF1FEA02D37201300A5E400 /* WebViewConfigurationProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WebViewConfigurationProxyAPITests.swift; path = ../../darwin/Tests/WebViewConfigurationProxyAPITests.swift; sourceTree = SOURCE_ROOT; };
149153
8FF1FEA12D37201300A5E400 /* WebViewProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WebViewProxyAPITests.swift; path = ../../darwin/Tests/WebViewProxyAPITests.swift; sourceTree = SOURCE_ROOT; };
150154
8FF1FEC02D37201500A5E400 /* RunnerTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RunnerTests-Bridging-Header.h"; sourceTree = "<group>"; };
155+
8FFBB0642FA1019E00F6659D /* ColorProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColorProxyAPITests.swift; path = ../../darwin/Tests/ColorProxyAPITests.swift; sourceTree = SOURCE_ROOT; };
156+
8FFBB0652FA1019E00F6659D /* PlatformViewImplTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PlatformViewImplTests.swift; path = ../../darwin/Tests/PlatformViewImplTests.swift; sourceTree = SOURCE_ROOT; };
157+
8FFBB0662FA1019E00F6659D /* ProxyAPIRegistrarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ProxyAPIRegistrarTests.swift; path = ../../darwin/Tests/ProxyAPIRegistrarTests.swift; sourceTree = SOURCE_ROOT; };
158+
8FFBB0672FA1019E00F6659D /* WebViewFlutterPluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WebViewFlutterPluginTests.swift; path = ../../darwin/Tests/WebViewFlutterPluginTests.swift; sourceTree = SOURCE_ROOT; };
151159
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
152160
/* End PBXFileReference section */
153161

@@ -173,6 +181,10 @@
173181
331C80D6294CF71000263BE5 /* RunnerTests */ = {
174182
isa = PBXGroup;
175183
children = (
184+
8FFBB0642FA1019E00F6659D /* ColorProxyAPITests.swift */,
185+
8FFBB0652FA1019E00F6659D /* PlatformViewImplTests.swift */,
186+
8FFBB0662FA1019E00F6659D /* ProxyAPIRegistrarTests.swift */,
187+
8FFBB0672FA1019E00F6659D /* WebViewFlutterPluginTests.swift */,
176188
8FEC64912DA303E200C48569 /* GetTrustResultResponseProxyAPITests.swift */,
177189
8FEC64922DA303E200C48569 /* SecCertificateProxyAPITests.swift */,
178190
8FEC64932DA303E200C48569 /* SecTrustProxyAPITests.swift */,
@@ -373,7 +385,7 @@
373385
);
374386
mainGroup = 33CC10E42044A3C60003C045;
375387
packageReferences = (
376-
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
388+
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
377389
);
378390
productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
379391
projectDirPath = "";
@@ -477,6 +489,10 @@
477489
8FF1FEB52D37201300A5E400 /* WebsiteDataStoreProxyAPITests.swift in Sources */,
478490
8FF1FEB62D37201300A5E400 /* PreferencesProxyAPITests.swift in Sources */,
479491
8FF1FEB72D37201300A5E400 /* URLCredentialProxyAPITests.swift in Sources */,
492+
8FFBB0682FA1019E00F6659D /* PlatformViewImplTests.swift in Sources */,
493+
8FFBB0692FA1019E00F6659D /* ColorProxyAPITests.swift in Sources */,
494+
8FFBB06A2FA1019E00F6659D /* ProxyAPIRegistrarTests.swift in Sources */,
495+
8FFBB06B2FA1019E00F6659D /* WebViewFlutterPluginTests.swift in Sources */,
480496
8FF1FEB82D37201300A5E400 /* URLRequestProxyAPITests.swift in Sources */,
481497
8FF1FEB92D37201300A5E400 /* UserScriptProxyAPITests.swift in Sources */,
482498
8FF1FEBA2D37201300A5E400 /* ScriptMessageHandlerProxyAPITests.swift in Sources */,
@@ -848,7 +864,7 @@
848864
/* End XCConfigurationList section */
849865

850866
/* Begin XCLocalSwiftPackageReference section */
851-
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
867+
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
852868
isa = XCLocalSwiftPackageReference;
853869
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
854870
};

packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ description: Demonstrates how to use the webview_flutter_wkwebview plugin.
33
publish_to: none
44

55
environment:
6-
sdk: ^3.9.0
7-
flutter: ">=3.35.0"
6+
sdk: ^3.10.0
7+
flutter: ">=3.38.0"
88

99
dependencies:
1010
flutter:

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.0
5+
version: 3.25.1
66

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

1111
flutter:
1212
plugin:

0 commit comments

Comments
 (0)