【问题标题】:How do I pass a swift object to javascript (WKWebView / swift)如何将 swift 对象传递给 javascript (WKWebView / swift)
【发布时间】:2015-11-13 20:11:06
【问题描述】:

我正在将数据从 swift 传递到 WKWebView 中的 javascript

我有一个自定义类:

class AllInfo: AnyObject {
    var title = "Special Title"
    var description = "Special Description"
}

并用

初始化它
var info = AllInfo()

然后我有一个 WKWebView,我通过它传递一个 WKUserScript,我有一个源属性:

source: "changeDisplay('\(info)')"

我的问题是如何在 javascript 中访问这个对象。我试图像 javascript 对象以及关联数组一样访问它,但没有运气。这是js函数:

function changeDisplay(passedInfo) {
    document.querySelector('h1').innerHTML = passedInfo.title
    document.querySelector('h2').innerHTML = passedInfo.description
}
setTimeout(function () {changeDisplay();}, 5000);

编辑:当我尝试访问这样的对象时,我得到了未定义。

所以我的问题是:

我可以将 AnyObject 传递给 JavaScript 并访问它吗? 如果没有,我应该制作什么类型的 swift 类,以便我可以轻松通过它。

我很想在 swift 中创建一个 javascript 对象作为字符串并传递它,但我觉得有更好的方法。

谢谢

编辑:我在下面回答了我如何能够将数据作为 JSON 传递。

【问题讨论】:

    标签: ios iphone xcode swift swift2


    【解决方案1】:

    这是我的建议(使用 json 作为数据示例):

    1. 创建 json:

    var json = ["value1": "一", "value2": "二"]

    1. 编码为字符串(我没有使用base64):

    guard let json = 试试? JSONEncoder().encode(permissionsJSON), 让 jsonString = String(data: json, encoding: .utf8) else { 返回 }

    1. 发送:

    webView.evaluateJavaScript("window.evite.webview.yourName('(jsonString)')")

    【讨论】:

      【解决方案2】:

      这是来自 Ashok 接受的答案的 Swift 代码更新,与 Swift 3.0.2 兼容:

      func evaluateJavaScriptForData(dictionaryData: [String: AnyObject]) {
          // Convert swift dictionary into encoded json
          let serializedData = try! JSONSerialization.data(withJSONObject: swiftObject, options: .prettyPrinted)
          let encodedData = serializedData.base64EncodedString(options: .endLineWithLineFeed)
          // This WKWebView API to calls 'reloadData' function defined in js
          webView.evaluateJavaScript("reloadData('\(encodedData)')", completionHandler: { result, error in
              print("Completed Javascript evaluation.")
              print("Result: \(result)")
              print("Error: \(error)")
          })
      }
      

      【讨论】:

      • 上面的引号不正确这里是如何传递数据 let script = "getSessionIdUserId('(sessionId)', '(userId)')" self.webView?.evaluateJavaScript(script, completionHandler: { (obj:Any?, error:Error?) in })
      【解决方案3】:

      将原生对象传递给 javascript 很复杂,尤其是对于在多进程模式下运行的 WKWebView。任何有关本机对象的操作都需要跨越进程边界。 WKWebView 在原生和 javascript 之间没有语言绑定支持。但是,WKWebView 支持消息传递 API。对于 JS 和 native 之间的复杂交互,您必须将其包装起来。

      我创建了一个名为XWebView 的项目,它基于 WKWebView 的原始消息传递提供语言绑定样式的 API。它是用 Swift 编写的。

      关于您的示例,必须首先将对象注入到 javascript 命名空间中:

      let webView = WKWebView(frame: frame, configuration: WKWebViewConfiguration())
      webView.loadPlugin(AllInfo(), namespace: "someInfo")
      

      您可以在 javascript 中访问该对象:

      console.log(window.someInfo.title);
      window.someInfo.title = "Some title";
      

      要将 Swift 对象公开给 javascript,属性和方法必须是动态调度的。这意味着,属性必须是动态的,方法必须具有@objc 属性。 (有关动态调度,请参阅https://developer.apple.com/swift/blog/?id=27)。简单来说,继承自 NSObject。

      【讨论】:

      • 看看下面我更简单的解决方案.. 没有 XWebView 或动态调度等
      【解决方案4】:

      在.swift中,定义并调用这个方法

      func evaluateJavaScriptForData(dictionaryData: [String: AnyObject]) {
          // Convert swift dictionary into encoded json
          let serializedData = try! NSJSONSerialization.dataWithJSONObject(dictionaryData, options: .PrettyPrinted)
          let encodedData = serializedData.base64EncodedStringWithOptions(.EncodingEndLineWithLineFeed)
          // This WKWebView API to calls 'reloadData' function defined in js
          webView.evaluateJavaScript("reloadData('\(encodedData)')") { (object: AnyObject?, error: NSError?) -> Void in
              print("completed with \(object)")
          }
      }
      

      在 .js/.html 文件中

      function reloadData(sBinaryParam) {
          // This 'atob' decodes the Base64 encoded data sent by swift
          var sDecodedParam = window.atob(sBinaryParam);
          var oData = JSON.parse(sDecodedParam);
          // This 'oData' is your js object (dictionary)
          return true;
      }
      

      【讨论】:

      • 完美。这很好用。但是我认为这适用于任何 JSON 响应。而不是自定义对象。
      • @BlackFlam3 你能不能先把自定义对象转成 JSON 对象?
      • @Crashalot 是的,我确实错过了一些东西。所以我发现将 JSON 转换为自定义对象很容易,而且可能我需要编写一个反向函数来将自定义对象转换为 JSON。
      • 如果数据中包含汉字,则此方法无效。不幸的是,atob 无法解码 UTF-8:stackoverflow.com/questions/30106476/…
      【解决方案5】:

      回答我自己的问题:

      JSON 是(可能)传递给 javascript 的最佳类型。

      我删除了该类,而是创建了一个类似 NSDictionary 的类(或将您的类键入为 NSDictionary):

      var allInfoRawSwift = ["title": "This is the title", "description": "this is the description"]
      

      然后将其转换为 JSON(在 do/catch if swift 2 中):

      let allInfoJSON = try NSJSONSerialization.dataWithJSONObject(allInfoRawSwift, options: NSJSONWritingOptions(rawValue: 0))
      

      将 JSON 转换为字符串:

      let allInfoJSONString = NSString(data: allInfoJSON, encoding: NSUTF8StringEncoding)!
      

      然后添加源属性,如:

      source: "changeDisplay(\(allInfoJSONSting))"
      

      要进行调试,最好让您的函数为您传递的任何内容设置一个全局变量,然后使用 safari 的开发人员模式访问 Web 控制台并检查全局变量。

      如果有更好的方法或者您有任何提示,请告诉我。

      谢谢

      【讨论】:

        猜你喜欢
        • 2016-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-23
        • 1970-01-01
        • 2016-09-20
        • 1970-01-01
        • 2023-03-06
        相关资源
        最近更新 更多