Search code examples
iosswiftwkwebview

Call swift function from js


Tell me please how should i implement the function in swift so that can be called in js. Now js call function mobile.preScreenerFinished(orderId, account.email, "ACCEPTED"); and it call kotlin function for android.

Here is my code:

import WebKit

protocol PreScreenerUIViewDelegate: class {
    func preScreenerFinished(_ orderId: Int, _ email: String, _ status: String)
}

class PreScreenerUIView: WKWebView, WKScriptMessageHandler {
    
    var delegate: PreScreenerUIViewDelegate!
        
    init(frame: CGRect, orderId: Int) {
        let url = "\(Session.instance.url)/mobile-prescreener"
        let config = WKWebViewConfiguration()
        let contentController = WKUserContentController();
    
        config.userContentController = contentController

        super.init(frame: frame, configuration: config)
    
        contentController.add(self, name: "mobile")
    
        self.load(URLRequest(url: URL(string: url)!))
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        let dictionary = message.body as? [String: Any]
        guard
            let orderId = dictionary?["orderId"] as? Int,
            let email = dictionary?["email"] as? String,
            let status = dictionary?["status"] as? String
        else { return }
        
        delegate?.preScreenerFinished(orderId, email, status)
    }
}

Solution

  • You need to change your Javascript (or inject Javascript code) to call postMessage() function instead. Since you can only pass one parameter you can compose a JSON:

    window.webkit.messageHandlers.mobile.postMessage({
        "orderId": orderId,
        "email": account.email,
        "status": "ACCEPTED"
    });
    

    That way you can handle body property of WKScriptMessage like a dictionary, in Swift:

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        let dictionary = message.body as? [String: Any]
        guard
            let orderId = dictionary?["orderId"] as? Int,
            let email = dictionary?["email"] as? String,
            let status = dictionary?["status"] as? String
        else { return }
        
        delegate?.preScreenerFinished(orderId, email, status)
    }