Khởi tạo thành viên trong cấu trúc xem
Tôi muốn có một WKWebView với khả năng xử lý JavaScript trong SwiftUI. Từ Khởi tạo biến Swift , tôi đang làm như sau: (Tôi đang sử dụnghttps://github.com/kylehickinson/SwiftUI-WebViewđể cung cấp một trình bao bọc WKWebViewtrong SwiftUI cũng bổ sung các ràng buộc về bố cục có giá trị.)
struct ContentView: View {
var body: some View {
WebView(webView: myWebView)
.onAppear {
let url = Bundle.main.url(forResource: "index", withExtension: "html")!
myWebView.loadFileURL(url, allowingReadAccessTo: url)
let request = URLRequest(url: url)
myWebView.load(request)
}
}
class JSHandler : NSObject, WKScriptMessageHandler {
var contentView: ContentView?
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("documentReady")
contentView!.myWebView.evaluateJavaScript("<Long Script to Transfer Data>") { (result, error) in
}
}
}
let myJSHandler = JSHandler()
var myWebView: WKWebView = {
let config = WKWebViewConfiguration()
let controller = WKUserContentController()
controller.add(myJSHandler , name: "documentReady")
config.userContentController = controller
return WKWebView(frame: .zero, configuration: config)
}()
}
Nhưng sau đó tôi đã học được từ thành viên Instance không thể được sử dụng trên loại mà điều này không hoạt động vì việc đóng không có tham chiếu đến bản thân. Tôi cần WKWebView có đối tượng cấu hình chuyên dụng để tôi không thể chỉ sử dụng hàm tạo khác. Tôi cần một tham chiếu đến nó để làm evaluateJavaScript.
Làm thế nào để làm cho điều này hoạt động?
CHỈNH SỬA 1 : Thêm bodyvà đề cập đến khuôn khổ được sử dụng để bao bọc WKWebView.
CHỈNH SỬA 2 : Đã thêm mã để làm rõ rằng tôi cần liên lạc hai chiều từ WKWebViewứng dụng gốc qua WKScriptMessageHandler(để nhận thông báo khi tài liệu HTML sẵn sàng) và từ ứng dụng gốc đến WKWebViewqua evaluateJavaScript(để chuyển dữ liệu khi tài liệu HTML đã sẵn sàng).
Trả lời
Một giải pháp khả thi là định cấu hình WKWebView trong init
struct ContentView: View {
private var myWebView: WKWebView
init() {
let config = WKWebViewConfiguration()
let controller = WKUserContentController()
controller.add(myJSHandler , name: "documentReady")
config.userContentController = controller
myWebView = WKWebView(frame: .zero, configuration: config)
}
var body: some View {
WebView(webView: myWebView)
.onAppear {
let url = Bundle.main.url(forResource: "index", withExtension: "html")!
myWebView.loadFileURL(url, allowingReadAccessTo: url)
let request = URLRequest(url: url)
myWebView.load(request)
}
}
class JSHandler : NSObject, WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("documentReady")
message.webView?.evaluateJavaScript("<Long Script to Transfer Data>") { (result, error) in
}
}
}
let myJSHandler = JSHandler()
}
Chỉ cần đặt myWebView một lazybiến, Điều này đảm bảo rằng jsHandler được khởi tạo trước WebView.
lazy var myWebView: WKWebView = {
let config = WKWebViewConfiguration()
let controller = WKUserContentController()
controller.add(myJSHandler , name: "documentReady")
config.userContentController = controller
return WKWebView(frame: .zero, configuration: config)
}()