Lonaso
Lonaso

Reputation: 55

Argument Type does not conform to expected type 'WKScriptMessageHandler'

I'm trying two-way integration between Swift and Javascript interfacing with SwiftUI.
Here is interfacing WebKit with SwiftUI.

import SwiftUI
import WebKit

struct ggWebView : UIViewRepresentable {

    let filePath: String

    func makeUIView(context: Context) -> WKWebView  {
        return WKWebView()
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        uiView.configuration.userContentController.add(self, name: "jsHandler")
        let bundleURL = Bundle.main.resourceURL!.absoluteURL
        let html = bundleURL.appendingPathComponent(filePath)
        uiView.loadFileURL(html, allowingReadAccessTo:bundleURL)
    }

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "jsHandler"{
            print(message.body)
        }
    }
}

userContentController.add(self, name: "jsHandler") shows an error at self with Argument type 'ggWebView' does not conform to expected type 'WKScriptMessageHandler'.

Upvotes: 3

Views: 3799

Answers (1)

Maciej Gad
Maciej Gad

Reputation: 1731

As WKScriptMessageHandler require that object that implements it inherit from NSObject it is better to create a separate class ContentController that will be implementing those protocol, rather than changing the type of GgWebView.

import SwiftUI
import WebKit

struct GgWebView: UIViewRepresentable {

    let filePath: String
    let contentController = ContentController()

    func makeUIView(context: Context) -> WKWebView  {
        return WKWebView()
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        uiView.configuration.userContentController.add(contentController, name: "jsHandler")
        let bundleURL = Bundle.main.resourceURL!.absoluteURL
        let html = bundleURL.appendingPathComponent(filePath)
        uiView.loadFileURL(html, allowingReadAccessTo:bundleURL)
    }

    class ContentController: NSObject, WKScriptMessageHandler {
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            if message.name == "jsHandler"{
                print(message.body)
            }
        }
    }
}

You have to confirm ggWebView (BTW this is not the best name for a class because it should start with capital letter) to WKScriptMessageHandler protocol and implement func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) method. You have to change the type of ggWebView from structure to class. I can see that you already add a userContentController(_:didReceive:) method, so you only need to update your class signature to:

class ggWebView: UIViewRepresentable, WKScriptMessageHandler {

Upvotes: 8

Related Questions