为了账号安全,请及时绑定邮箱和手机立即绑定

iOS 14 API WKScriptMessageHandlerWithReply 如何从 iOS

iOS 14 API WKScriptMessageHandlerWithReply 如何从 iOS

宝慕林4294392 2023-11-12 22:14:38
iOS 14 引入了一种新方法来接收 javascript 调用并使用 WKScriptMessageHandlerWithReply 而不是 WKScriptMessageHandler(在 WebKit 视图内)提供响应。然而文档基本上不存在。这是如何运作的?
查看完整描述

1 回答

?
侃侃无极

TA贡献2051条经验 获得超10个赞

我对此进行了深入研究,发现它使用 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 发起的请求成功或失败时由应用程序扩展代码调用的函数。


查看完整回答
反对 回复 2023-11-12
  • 1 回答
  • 0 关注
  • 203 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信