【问题标题】:How does the iOS 14 API WKScriptMessageHandlerWithReply work for communicating with JavaScript from iOS?iOS 14 API WKScriptMessageHandlerWithReply 如何与 iOS 中的 JavaScript 通信?
【发布时间】:2021-03-23 23:23:51
【问题描述】:

iOS 14 引入了一种新方法来接收 javascript 调用并使用 WKScriptMessageHandlerWithReply 而不是 WKScriptMessageHandler(在 WebKit 视图中)提供响应。但是文档基本上是不存在的。这是如何工作的?

【问题讨论】:

    标签: javascript ios webkit


    【解决方案1】:

    我对此进行了深入研究,发现它使用 Javascript Promises 来提供回调机制(并且从应用程序代码返回到 javascript 的响应必须是异步的)。

    这里有一些示例代码来说明:

    快速代码:

    import UIKit
    import WebKit
    import PureLayout
    
    final class ViewController: UIViewController {
    
        var webView : WKWebView?
        let JavaScriptAPIObjectName = "namespaceWithinTheInjectedJSCode"
        
        override func viewDidLoad() {
            super.viewDidLoad()
                    
            //-------
            
            guard let scriptPath = Bundle.main.path(forResource: "script", ofType: "js"),
                  let scriptSource = try? String(contentsOfFile: scriptPath) else { return }
    
            let userScript = WKUserScript(source: scriptSource, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
    
            let config = WKWebViewConfiguration()
    
            let userContentController = WKUserContentController()
            userContentController.addUserScript(userScript)
            
            // REQUIRES IOS14
            if #available(iOS 14, *){
                userContentController.addScriptMessageHandler(self, contentWorld: .page, name: JavaScriptAPIObjectName)
            }
    
            config.userContentController = userContentController
            
            webView = WKWebView(frame: .zero, configuration: config)
                    
            if let webView = webView{
                view.addSubview(webView)
                webView.autoPinEdgesToSuperviewMargins() // using PureLayout for easy AutoLayout syntax
    
                if let htmlPath = Bundle.main.url(forResource: "page", withExtension: "html"){
                    webView.loadFileURL( htmlPath, allowingReadAccessTo: htmlPath);
                }
            }
        }
    
        // need to deinit and remove webview stuff
        deinit {
            if let webView = webView{
                let ucc = webView.configuration.userContentController
                ucc.removeAllUserScripts()
                ucc.removeScriptMessageHandler(forName:JavaScriptAPIObjectName)
            }
        }
    }
    
    extension ViewController: WKScriptMessageHandlerWithReply {
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage, replyHandler: @escaping (Any?, String?) -> Void) {
            if message.name == JavaScriptAPIObjectName, let messageBody = message.body as? String {
                print(messageBody)
                replyHandler( 2.2, nil ) // first var is success return val, second is err string if error
            }
        }
    }
    

    这是通过该 Swift 代码加载并注入网页的 script.js:

    function sampleMethodTheHTMLCanCall( inputInfo, successFunc, errorFunc ) {
        
        var promise = window.webkit.messageHandlers.namespaceWithinTheInjectedJSCode.postMessage( inputInfo );
        
        promise.then(
          function(result) {
            console.log(result); // "Stuff worked!"
            successFunc( result )
          },
          function(err) {
            console.log(err); // Error: "It broke"
            errorFunc( err )
          });
    }
    

    这里是可以调用应用程序代码的 page.html 示例 HTML:

    <html>
        <meta name="viewport" content="width=device-width" />
            <script>
                function handleInfoFromApp( fromApp ){
                    document.getElementById("valToWrite").innerHTML = fromApp;
                }
                function handleError( err ){
                
                }
            </script>
    
        <h1 id="valToWrite">Hello</h1>
        <button onclick="sampleMethodTheHTMLCanCall( 'inputInfo', handleInfoFromApp, handleError )">Load Info from App</button>
        
    </html>
    

    上面的 HTML 提供了稍后在 javascript 发起的请求成功或失败时由应用扩展代码调用的函数。

    【讨论】:

    • 我认为这个答案应该被接受。非常感谢!!!!!!
    猜你喜欢
    • 2020-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多