如何将 swift 对象传递给 javascript (WKWebView / swift)

Posted

技术标签:

【中文标题】如何将 swift 对象传递给 javascript (WKWebView / swift)【英文标题】:How do I pass a swift object to 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 传递。

【问题讨论】:

【参考方案1】:

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

    创建 json:

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

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

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

    发送:

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:***.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 控制台并检查全局变量。

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

谢谢

【讨论】:

以上是关于如何将 swift 对象传递给 javascript (WKWebView / swift)的主要内容,如果未能解决你的问题,请参考以下文章

IOS/Swift:将表视图中的对象传递给详细视图控制器

如何将 NSData 参数传递给在 swift 3 中调用的目标 c 方法?

iOS Swift 如何从 UIWebView 将 JSON 字符串和数组或字典传递给 Javascript?

使用 UITapGestureRecognizer、UIImageView 和 UITableViewCell 将参数传递给 Swift 中的选择器

如何将额外的参数传递给自定义UIView类以便在swift中进行初始化

如何将库类或对象传递给片段?