Initialisieren Sie das Mitglied in der Ansichtsstruktur
Ich möchte eine WKWebView mit JavaScript-Verarbeitung in SwiftUI haben. Bei der Initialisierung von Swift-Variablen mache ich Folgendes: (Ich verwendehttps://github.com/kylehickinson/SwiftUI-WebViewum einen Wrapper für WKWebView
in SwiftUI bereitzustellen, der auch wertvolle Layouteinschränkungen hinzufügt.)
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)
}()
}
Aber dann habe ich von Instance gelernt, dass Mitglieder nicht für Typen verwendet werden können , die nicht funktionieren, da der Abschluss keinen Bezug zu sich selbst hat. Ich brauche das WKWebView, um ein dediziertes Konfigurationsobjekt zu haben, damit ich nicht einfach den anderen Konstruktor verwenden kann. Ich brauche einen Verweis darauf evaluateJavaScript
.
Wie funktioniert das?
BEARBEITEN 1 : Fügen Sie das hinzu body
und erwähnen Sie das Framework, das zum Umschließen von WKWebView verwendet wird.
BEARBEITEN 2 : Code hinzugefügt, um zu verdeutlichen, dass ich eine bidirektionale Kommunikation von WKWebView
zur nativen App über WKScriptMessageHandler
(um benachrichtigt zu werden, wenn das HTML-Dokument fertig ist) und von der nativen App zur WKWebView
via evaluateJavaScript
(um Daten zu übertragen , wenn das HTML-Dokument bereit ist) benötige .
Antworten
Eine mögliche Lösung besteht darin, WKWebView in zu konfigurieren 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()
}
Machen Sie myWebView einfach zu einer lazy
Variablen. Dadurch wird sichergestellt, dass der jsHandler vor WebView initialisiert wird.
lazy var myWebView: WKWebView = {
let config = WKWebViewConfiguration()
let controller = WKUserContentController()
controller.add(myJSHandler , name: "documentReady")
config.userContentController = controller
return WKWebView(frame: .zero, configuration: config)
}()