Skip to content

Commit 6adc861

Browse files
committed
[webview_flutter_wkwebview] Fix crash when calling setOnConsoleMessage multiple times
1 parent c4f084d commit 6adc861

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,53 @@ class TestUserContentController: WKUserContentController {
9595
removeAllUserScriptsCalled = true
9696
}
9797
}
98+
99+
// Mock that simulates WKUserContentController's behavior of crashing/complaining
100+
// when adding a duplicate script message handler.
101+
// Mock that verifies remove is called before add, and enforces uniqueness
102+
class MockVerifyingUserContentController: WKUserContentController {
103+
var registeredNames: Set<String> = []
104+
var removeCalledFor: String? = nil
105+
106+
override func add(_ scriptMessageHandler: WKScriptMessageHandler, name: String) {
107+
if registeredNames.contains(name) {
108+
// If we are here, it means remove wasn't called or failed to remove
109+
// In logical flow, remove() should have been called first.
110+
// But implementation-wise, we just want to ensure we don't crash.
111+
// Ideally, the 'remove' call below should have cleared it.
112+
NSException(name: NSExceptionName.invalidArgumentException, reason: "Duplicate handler name", userInfo: nil).raise()
113+
}
114+
registeredNames.insert(name)
115+
}
116+
117+
override func removeScriptMessageHandler(forName name: String) {
118+
removeCalledFor = name
119+
registeredNames.remove(name)
120+
}
121+
}
122+
123+
extension UserContentControllerProxyAPITests {
124+
@MainActor func testAddScriptMessageHandlerHandlesDuplicates() {
125+
let registrar = TestProxyApiRegistrar()
126+
let api = registrar.apiDelegate.pigeonApiWKUserContentController(registrar)
127+
128+
let instance = MockVerifyingUserContentController()
129+
let handler = ScriptMessageHandlerImpl(
130+
api: registrar.apiDelegate.pigeonApiWKScriptMessageHandler(registrar), registrar: registrar)
131+
let name = "myString"
132+
133+
// First add
134+
try? api.pigeonDelegate.addScriptMessageHandler(
135+
pigeonApi: api, pigeonInstance: instance, handler: handler, name: name)
136+
XCTAssertTrue(instance.registeredNames.contains(name))
137+
138+
// Second add - should NOT crash because implementation calls remove first
139+
try? api.pigeonDelegate.addScriptMessageHandler(
140+
pigeonApi: api, pigeonInstance: instance, handler: handler, name: name)
141+
142+
// Check that it's still registered (or re-registered)
143+
XCTAssertTrue(instance.registeredNames.contains(name))
144+
// Verify remove was called
145+
XCTAssertEqual(instance.removeCalledFor, name)
146+
}
147+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ class UserContentControllerProxyAPIDelegate: PigeonApiDelegateWKUserContentContr
1313
pigeonApi: PigeonApiWKUserContentController, pigeonInstance: WKUserContentController,
1414
handler: WKScriptMessageHandler, name: String
1515
) throws {
16+
// WKUserContentController will crash if a script message handler with the same name
17+
// is added twice. We remove the existing one (if any) to ensure the new one replaces it.
18+
pigeonInstance.removeScriptMessageHandler(forName: name)
1619
pigeonInstance.add(handler, name: name)
1720
}
1821

0 commit comments

Comments
 (0)