fix(ios): refactor screen webview lifecycle handling#20366
Merged
Conversation
Comment on lines
24
to
26
| init() { | ||
| let config = WKWebViewConfiguration() | ||
| config.websiteDataStore = .nonPersistent() | ||
| let a2uiActionHandler = CanvasA2UIActionMessageHandler() | ||
| let userContentController = WKUserContentController() | ||
| for name in CanvasA2UIActionMessageHandler.handlerNames { | ||
| userContentController.add(a2uiActionHandler, name: name) | ||
| } | ||
| config.userContentController = userContentController | ||
| self.navigationDelegate = ScreenNavigationDelegate() | ||
| self.a2uiActionHandler = a2uiActionHandler | ||
| self.webView = WKWebView(frame: .zero, configuration: config) | ||
| // Canvas scaffold is a fully self-contained HTML page; avoid relying on transparency underlays. | ||
| self.webView.isOpaque = true | ||
| self.webView.backgroundColor = .black | ||
| self.webView.scrollView.backgroundColor = .black | ||
| self.webView.scrollView.contentInsetAdjustmentBehavior = .never | ||
| self.webView.scrollView.contentInset = .zero | ||
| self.webView.scrollView.scrollIndicatorInsets = .zero | ||
| self.webView.scrollView.automaticallyAdjustsScrollIndicatorInsets = false | ||
| self.applyScrollBehavior() | ||
| self.webView.navigationDelegate = self.navigationDelegate | ||
| self.navigationDelegate.controller = self | ||
| a2uiActionHandler.controller = self | ||
| self.reload() | ||
| } |
Contributor
There was a problem hiding this comment.
No-op reload() in init()
self.reload() in init() is now effectively dead code — activeWebView is always nil at construction time, so both applyScrollBehavior() and the web-view guard inside reload() early-return immediately. The real reload happens when attachWebView(_:) is called later. Consider removing this call to avoid confusion.
Suggested change
| init() { | |
| let config = WKWebViewConfiguration() | |
| config.websiteDataStore = .nonPersistent() | |
| let a2uiActionHandler = CanvasA2UIActionMessageHandler() | |
| let userContentController = WKUserContentController() | |
| for name in CanvasA2UIActionMessageHandler.handlerNames { | |
| userContentController.add(a2uiActionHandler, name: name) | |
| } | |
| config.userContentController = userContentController | |
| self.navigationDelegate = ScreenNavigationDelegate() | |
| self.a2uiActionHandler = a2uiActionHandler | |
| self.webView = WKWebView(frame: .zero, configuration: config) | |
| // Canvas scaffold is a fully self-contained HTML page; avoid relying on transparency underlays. | |
| self.webView.isOpaque = true | |
| self.webView.backgroundColor = .black | |
| self.webView.scrollView.backgroundColor = .black | |
| self.webView.scrollView.contentInsetAdjustmentBehavior = .never | |
| self.webView.scrollView.contentInset = .zero | |
| self.webView.scrollView.scrollIndicatorInsets = .zero | |
| self.webView.scrollView.automaticallyAdjustsScrollIndicatorInsets = false | |
| self.applyScrollBehavior() | |
| self.webView.navigationDelegate = self.navigationDelegate | |
| self.navigationDelegate.controller = self | |
| a2uiActionHandler.controller = self | |
| self.reload() | |
| } | |
| init() { | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/ios/Sources/Screen/ScreenController.swift
Line: 24-26
Comment:
**No-op `reload()` in `init()`**
`self.reload()` in `init()` is now effectively dead code — `activeWebView` is always nil at construction time, so both `applyScrollBehavior()` and the web-view guard inside `reload()` early-return immediately. The real reload happens when `attachWebView(_:)` is called later. Consider removing this call to avoid confusion.
```suggestion
init() {
}
```
How can I resolve this? If you propose a fix, please make it concise.
ngutman
added a commit
that referenced
this pull request
Feb 18, 2026
54839a8 to
49ba1c6
Compare
49ba1c6 to
7beb794
Compare
Contributor
Author
|
Merged via maintainer flow Details:
|
anschmieg
pushed a commit
to anschmieg/openclaw
that referenced
this pull request
Feb 19, 2026
Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7beb794 Co-authored-by: ngutman <[email protected]> Co-authored-by: ngutman <[email protected]> Reviewed-by: @ngutman
yneth-ray-openclaw
pushed a commit
to yneth-ray-openclaw/openclaw
that referenced
this pull request
Feb 19, 2026
Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7beb794 Co-authored-by: ngutman <[email protected]> Co-authored-by: ngutman <[email protected]> Reviewed-by: @ngutman
HenryChenV
pushed a commit
to HenryChenV/openclaw
that referenced
this pull request
Feb 20, 2026
Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7beb794 Co-authored-by: ngutman <[email protected]> Co-authored-by: ngutman <[email protected]> Reviewed-by: @ngutman
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ScreenControllerno longer owns a long-livedWKWebViewWKWebViewcreation, delegate wiring, script handler setup, and teardown intoScreenWebViewCoordinatorScreenControllerfocused on state/navigation/debug commands and attach/detach a weak active web viewScreenControllerTeststo mount via coordinator-owned web view lifecycleWhy
We were seeing crashes around gesture handlers and
__NSArrayM insertObject:atIndex:. Reusing a sharedWKWebViewinstance across SwiftUI lifecycle transitions can lead to unstable UIKit/WebKit internals. This change aligns ownership withUIViewRepresentablelifecycle (makeUIView/dismantleUIView) and ensures delegates/script handlers are cleaned up deterministically.Validation
xcodebuild build -project apps/ios/OpenClaw.xcodeproj -scheme OpenClaw -destination 'platform=iOS Simulator,OS=18.6,name=iPhone 16'✅xcodebuild test ... -only-testing:OpenClawTests/ScreenControllerTestscould not run to completion because of an unrelated existing compile failure inGatewayConnectionSecurityTests(GatewayTLSStorenot found)Greptile Summary
This PR refactors the iOS
ScreenController/ScreenWebViewlifecycle so thatWKWebViewcreation, delegate wiring, and teardown are owned by a newScreenWebViewCoordinator, aligned with theUIViewRepresentablelifecycle (makeUIView/dismantleUIView). This fixes crashes related to gesture handlers and__NSArrayM insertObject:atIndex:caused by reusing a sharedWKWebViewacross SwiftUI lifecycle transitions.ScreenControllerno longer owns aWKWebView; it holds a weak reference set viaattachWebView/detachWebViewScreenWebViewCoordinatorhandles web view creation, AutoLayout, navigation delegate wiring, A2UI script handler install/teardownScreenNavigationDelegateandCanvasA2UIActionMessageHandlermoved fromScreenController.swifttoScreenWebView.swift(logic unchanged)teardown()indeferblocksScreenControllerhandles state/navigation/debug, coordinator handles UIKit/WebKit lifecycleConfidence Score: 4/5
reload()call ininit()is now dead code but harmless.ScreenWebView.swiftcoordinator is the most significant new code but follows standard UIViewRepresentable patterns.Last reviewed commit: 28452d9