我在 SwiftUI 中使用 UIViewRepresentable 和 WKWebView 编写了一个 webview。 该应用程序目前已发布在应用程序商店中。对于某些用户来说,应用程序崩溃了,我们无法重现它。
以下是崩溃日志:
Crashed: com.apple.main-thread
EXC_BREAKPOINT 0x000000010455c388
0 uMove 0x28388 specialized WebView.makeUIView(context:) + 31 (WebView.swift:31)
1 uMove 0x27b48 protocol witness for UIViewRepresentable.makeUIView(context:) in conformance WebView + 4329765704 (<compiler-generated>:4329765704)
2 SwiftUI 0xaa4bc OUTLINED_FUNCTION_326 + 6512
3 SwiftUI 0x9ac5c OUTLINED_FUNCTION_1106 + 1428
4 SwiftUI 0xca31a8 OUTLINED_FUNCTION_1 + 8712
5 SwiftUI 0xca5868 OUTLINED_FUNCTION_1 + 18632
6 SwiftUI 0x89200 OUTLINED_FUNCTION_513 + 11236
7 SwiftUI 0xca306c OUTLINED_FUNCTION_1 + 8396
8 SwiftUI 0xca24b8 OUTLINED_FUNCTION_1 + 5400
9 SwiftUI 0x53eb00 OUTLINED_FUNCTION_5 + 26880
10 AttributeGraph 0x3ef8 AG::Graph::UpdateStack::update() + 512
下面是崩溃的代码片段:从 makeUIView() 函数返回 WKWebView 实例时发生崩溃。
struct WebView: UIViewRepresentable {
@Binding var url: String
private let wKWebView = WKWebView()
func makeUIView(context: Context) -> WKWebView {
configure(context: context)
print(LOG_TAG, "makeUIView Webview loading url \(url)")
if(!url.isEmpty) {
wKWebView.load(URLRequest(url: URL(string:url)!))
}
return wKWebView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
}
func makeCoordinator() -> WebViewNavigationDelegate {
WebViewNavigationDelegate(self)
}
// Our own methods
func configure(context: Context) {
wKWebView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
//wKWebView.configuration.preferences.javaScriptEnabled = true
wKWebView.configuration.defaultWebpagePreferences.allowsContentJavaScript = true
wKWebView.allowsBackForwardNavigationGestures = true
wKWebView.allowsLinkPreview = true
wKWebView.navigationDelegate = context.coordinator
wKWebView.uiDelegate = context.coordinator
}
.....
....
....
}
最初我认为问题可能是由于在
makeUIView()
函数中加载 URL 造成的,考虑到视图可能尚未准备好,而我们正在尝试加载。所以我将加载 URL 逻辑移至 updateUIView
函数,但没有成功。
从您提供的详细信息来看,您的 WKWebView 实现似乎导致了难以重现的崩溃。
第一个潜在问题是
makeUIView()
中 URL 的强制解包。应避免强制展开 (!),因为如果 URL(string: url)
返回 nil
,应用程序将崩溃。为了安全地处理这个问题,请使用可选的绑定:
if let urlString = URL(string: url) {
wKWebView.load(URLRequest(url: urlString))
}
此外,直接在
WKWebView
结构中创建 WebView
实例可能会出现问题,特别是在视图生命周期处理不当的情况下。因此,请考虑在 WKWebView
方法中创建 makeUIView
实例。这确保每次创建视图时 WebView
都会被重新初始化,这会更可靠:
func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView()
configure(webView: webView, context: context)
if let url = URL(string: self.url) {
webView.load(URLRequest(url: URL))
}
return webView
}
并更新
configure
方法以接受 WKWebView
参数。
func configure(webView: WKWebView, context: Context) {
webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
webView.configuration.defaultWebpagePreferences.allowsContentJavaScript = true
webView.allowsBackForwardNavigationGestures = true
webView.allowsLinkPreview = true
webView.navigationDelegate = context.coordinator
webView.uiDelegate = context.coordinator
}
最后,我想说你应该确保 WebView 的生命周期在 SwiftUI 中得到正确管理。如果
updateUIView
方法为空,则当视图状态更改时,它可能会丢失关键更新。虽然它与崩溃没有直接关系,但在此处处理视图更新是一个很好的做法。