OpenPanel.initialize blocks main thread / crashes on background thread due to WKWebView + DispatchSemaphore deadlock in getiOSUserAgent
还没有人认领这个 Issue。
评估
调研方向
Start with DeviceInfo.getiOSUserAgent and trace how OpenPanel.initialize obtains and uses the user agent. Verify the behavior when initialization is called on both the main and a background thread, then make completion or fallback handling non-blocking while preserving the expected user-agent value.
由索引模型根据 Issue 内容生成。
描述
OpenPanel.initialize is not safe to call from either the main thread or a background thread due to a deadlock in the internal getiOSUserAgent implementation. This makes it impossible to initialize the SDK without causing either a crash or a ~1 second UI freeze.
Root cause
Inside DeviceInfo.getiOSUserAgent():
let webView = WKWebView(frame: .zero) // (1) must be on main thread
var userAgent = ""
let semaphore = DispatchSemaphore(value: 0)
DispatchQueue.main.async { // (2) queued on main thread
webView.evaluateJavaScript("navigator.userAgent") { (result, error) in
if let agent = result as? String { userAgent = agent }
semaphore.signal()
}
}
_ = semaphore.wait(timeout: .now() + 1.0) // (3) blocks calling thread
This creates two mutually exclusive failure scenarios:
Scenario A — Called from main thread:
Step (1) is fine.
Step (3) blocks the main thread via semaphore.wait.
Step (2)'s main.async block is queued but can never execute because the main thread is blocked.
The semaphore always times out after 1 full second, freezing the UI every time.
Scenario B — Called from a background thread:
Step (1) crashes immediately with Main Thread Checker: UI API called on a background thread: -[WKWebView .cxx_construct].
Observed crash (background thread):
Main Thread Checker: UI API called on a background thread: -[WKWebView .cxx_construct]
Queue name: com.apple.root.utility-qos
#5 OpenPanel.DeviceInfo.getiOSUserAgent()
#6 OpenPanel.DeviceInfo.getUserAgent()
#7 OpenPanel.OpenPanel.initialize(options:)
Observed freeze (main thread): OpenPanel.initialize always blocks the calling thread for exactly 1 second (the semaphore timeout), regardless of device speed, because the JS evaluation can never signal the semaphore while the thread is waiting on it.
Expected behavior
OpenPanel.initialize should be safe to call from the main thread without blocking it. The user agent should be fetched asynchronously and either:
Cached lazily on first use after a non-blocking async fetch, or
Fetched during initialize without blocking (e.g. completion-based), or
Simply use getBasicUserAgent() as the default and upgrade to the WKWebView-based UA once it becomes available asynchronously.
Suggested fix:
private static func getiOSUserAgent(completion: @escaping (String) -> Void) {
DispatchQueue.main.async {
let webView = WKWebView(frame: .zero)
webView.evaluateJavaScript("navigator.userAgent") { result, _ in
let agent = (result as? String) ?? getBasicUserAgent()
completion(agent + " OpenPanel/\(OpenPanel.sdkVersion)")
}
}
}
- 主要语言
- Swift
- 星标
- 5
- 派生
- 8
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
Openpanel-dev/swift-sdk 的其他 Issue
-
难度 5/5 一周以上 新手友好度 20/100
查看 Openpanel-dev/swift-sdk 的全部 Issue
相似的 Issue
-
needs-triage
难度 2/5 1-3 小时 新手友好度 65/100
manaflow-ai/cmux#32617 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 70/100
skiptools/skip-fuse-ui#166 ·
维护者通常 2 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100
runjuu/InputSourcePro#153 · 1 条评论 ·
-
难度 2/5 1-3 小时 新手友好度 62/100
remko/age-plugin-se#25 ·
-
难度 2/5 1-3 小时 新手友好度 62/100
peteromallet/desloppify#942 ·