【问题标题】:WKWebView WKScriptMessageHandler not called with iOS 10, Xcode 8 betaiOS 10、Xcode 8 beta 未调用 WKWebView WKScriptMessageHandler
【发布时间】:2016-09-08 10:06:48
【问题描述】:

我需要将我的代码更新为 swift 3。下面的代码是完美运行的原始解决方案,但在 Xcode 8 beta 和带有 swift 3 的 iOS 10 中,当我使用原始 html 时不会调用 userContentController 委托+js 代码调用原生端。

class ViewController: UIViewController, WKUIDelegate, WKScriptMessageHandler, WKNavigationDelegate,UIWebViewDelegate,CLLocationManagerDelegate,URLSessionDataDelegate,UIImagePickerControllerDelegate, UINavigationControllerDelegate {

....

func initWebView(){
    // JAVASCRIPT PART
    let contentController = WKUserContentController();

    let jScript:String = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";

    let wkUScript:WKUserScript = WKUserScript(source: jScript, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true);


    contentController.addUserScript(wkUScript)
    contentController.add(
        self,
        name: "refreshWebPage"
    )
    contentController.add(
        self,
        name: "forceStepBack"
    )
    contentController.add(
        self,
        name: "setPageTitle"
    )
    contentController.add(
        self,
        name: "allowBackNavigate"
    )
    contentController.add(
        self,
        name: "changeBackNavigationURL"
    )

    contentController.add(
        self,
        name: "changeLeftButtonIconVisibility"
    )
    contentController.add(
        self,
        name: "changeRightButtonIconVisibility"
    )
    contentController.add(
        self,
        name: "clearWebCache"
    )
    contentController.add(
        self,
        name: "changeMobileAndPassword"
    )


    let config = WKWebViewConfiguration()
    config.userContentController = contentController


    self.webView = WKWebView(frame: CGRect.zero, configuration: config)


    self.view.translatesAutoresizingMaskIntoConstraints = false
    self.webView!.navigationDelegate = self
    self.webView!.uiDelegate = self;
    self.webView!.scrollView.bounces = false;
    view = webView

    webView?.loadHTMLString(self.baseURL!, baseURL: nil)

}
...
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        print("JavaScript is sending a message: \(message.body)")
        print("JavaScript is sending a message.name: \(message.name)")

    }

【问题讨论】:

  • 我也是,没有找到任何解决方案...帮助!

标签: wkwebview swift3 xcode8


【解决方案1】:

在我调试了很多次和条件后,我发现:

  1. 你的JS中的函数postMessage()必须有一个参数参数永远不能为空

  2. 参数必须是JSON类型

  3. 例如: webkit.messageHandlers.refreshWebPage.postMessage("status":"ok");

如果您已遵循上述三个建议并正确设置了代理。将调用委托函数didReceiveScriptMessage。希望对您有所帮助。

【讨论】:

  • 为了澄清,没有要设置的委托。 func userContentController(WKUserContentController, didReceive: WKScriptMessage) 是来自WKScriptMessageHandler 协议的方法,被系统调用。
【解决方案2】:

你找到解决方法了吗?因为我也有问题,但幸运的是,我可以发送消息并且 userContentController 确实回调了,但只有消息必须是数字,没有字符串,没有字符。不知道为什么……

已编辑 我已经找到了关于这个的答案。 似乎你必须输入 try catch 并且在我这样做之后它 100% 使用文本数字甚至 json

`<script>
    function callNative(message)  {
    try {
        webkit.messageHandlers.callbackHandler.postMessage(message)
    } catch(err) {
        console.log("Error")
    }
    }
</script>`

别忘了callbackHandler 在 iOS 中必须是同一个词才能使它工作,你不必命名 callbackHandler,你可以命名它,但它必须在两个 Javascript 中相同和 iOS

希望对你有帮助

【讨论】:

【解决方案3】:

我通过只有一个类似的 contentController 解决了这个问题

let contentController = WKUserContentController()
contentController.add(self, name: "MyStuff")

然后在 userContentController 函数中,我解析主体以确定请求的操作和其他参数。如果我发送 {action: "doThis", params: [1,2,3]},我的解析代码将是:

if message.name == "MyStuff" {
    let cmd:NSDictionary = message.body as! NSDictionary
    let action:String = cmd["action"] as! String
    switch action {
    case "doThis":
        // Do my stuff
        break
    default:
        break
    }
}

【讨论】:

    【解决方案4】:

    这是因为基本上window.webkit.messageHandlersUserMessageHandlersNamespace 类型。

    您应该尝试传递字典而不是字符串或数组:

    JavaScript 部分:

    var dictionary = {"key1":"value1", "key2":"value2", "subDictionary": {"name": "foo"}}
    webkit.messageHandlers.refreshWebPage.postMessage(dictionary);
    

    斯威夫特部分:

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            let body = message.body
            if let dict = body as? Dictionary<String, AnyObject> {
                if let test = dict["key1"] {
                    print("JavaScript is sending a message \(value1)")
                }
            }
    }
    

    P.S.(根据我的测试,这适用于 iOS9、iOS10)

    【讨论】:

    • 谢谢 Alessandro - 传递字符串有时对我有用,但不是在 sim 上 - 传递数组有效 - 谢谢!
    【解决方案5】:

    如果来自 JS 则不使用 webkit.messageHandlers.refreshWebPage

    webkit.messageHandlers.refreshWebPage.postMessage("status":"ok")
    

    然后你可以像下面这样将它包装在WKUserContentController,这样你就会从方法中得到回调

        let userController = WKUserContentController() 
        let channelName = "postMessage"
        let wrapperSource = "window.\(channelName) = webkit.messageHandlers.\(channelName);"
        let wrapperScript = WKUserScript(
            source: wrapperSource,
            injectionTime: .atDocumentStart,
            forMainFrameOnly: false)
        userController.addUserScript(wrapperScript)
        userController.add(self, name: "postMessage")
        let configuration = WKWebViewConfiguration()
        configuration.userContentController = userController
        self.wkWebView = WKWebView(
                   frame: self.view.bounds,
                   configuration: configuration
               )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-07
      • 2017-01-02
      • 2016-12-29
      • 1970-01-01
      相关资源
      最近更新 更多