侃侃无极
我对此进行了深入研究,发现它使用 Javascript Promises 来提供回调机制(并且从应用程序代码返回到 javascript 的响应必须是异步的)。下面是一些示例代码来说明:快速代码:import UIKitimport WebKitimport PureLayoutfinal 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 发起的请求成功或失败时由应用程序扩展代码调用的函数。