xcode 如何将 swift 对象传递给 javascript (WKWebView / swift)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32113933/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I pass a swift object to javascript (WKWebView / swift)
提问by Deciple
I am working on passing data from swift to javascript inside a WKWebView
我正在将数据从 swift 传递到 WKWebView 中的 javascript
I have a custom class:
我有一个自定义类:
class AllInfo: AnyObject {
var title = "Special Title"
var description = "Special Description"
}
and initialize it with
并用它初始化
var info = AllInfo()
I then have a WKWebView with which i pass a WKUserScript with which I have a source property of:
然后我有一个 WKWebView,我用它传递了一个 WKUserScript,我有一个源属性:
source: "changeDisplay('\(info)')"
My problem is how do I access this object in the javascript. I have attempted to access it like a javascript object as well as associative array with no luck. Here's the js funciton:
我的问题是如何在 javascript 中访问这个对象。我试图像 javascript 对象以及关联数组一样访问它,但没有运气。这是js函数:
function changeDisplay(passedInfo) {
document.querySelector('h1').innerHTML = passedInfo.title
document.querySelector('h2').innerHTML = passedInfo.description
}
setTimeout(function () {changeDisplay();}, 5000);
EDIT: When I do attempt to access the object like this, I get undefined.
编辑:当我尝试像这样访问对象时,我得到了未定义。
So my questions are:
所以我的问题是:
Can I pass an AnyObject to JavaScript and access it? If not, what type should I make the swift class so that I can easily pass it.
我可以将 AnyObject 传递给 JavaScript 并访问它吗?如果没有,我应该制作什么类型的 swift 类,以便我可以轻松地通过它。
I am tempted to just create a javascript object in swift as a string and pass that, but I feel there's a better way.
我很想在 swift 中创建一个 javascript 对象作为字符串并传递它,但我觉得有更好的方法。
Thanks
谢谢
EDIT: I answered how I was able to pass data as JSON below.
编辑:我在下面回答了我如何能够将数据作为 JSON 传递。
采纳答案by soflare
Passing a native object to javascript is complex, especially for WKWebView which runs in multi-process mode. Any operation regarding the native object needs to cross process boundary. WKWebView has no language binding support between native and javascript. However, WKWebView supports message passing API. You have to wrap it for complex interactions between JS and native.
将本机对象传递给 javascript 很复杂,尤其是对于在多进程模式下运行的 WKWebView。任何有关本机对象的操作都需要跨越进程边界。WKWebView 没有原生和 javascript 之间的语言绑定支持。但是,WKWebView 支持消息传递 API。您必须将其包装起来以实现 JS 和本机之间的复杂交互。
I created a project named XWebViewwhich provides language binding styled API based on the raw message passing of WKWebView. It's written in Swift.
我创建了一个名为XWebView的项目,它基于 WKWebView 的原始消息传递提供语言绑定样式的 API。它是用 Swift 编写的。
Regarding your example, the object has to be injected in javascript namespace firstly:
关于您的示例,必须首先将对象注入 javascript 命名空间:
let webView = WKWebView(frame: frame, configuration: WKWebViewConfiguration())
webView.loadPlugin(AllInfo(), namespace: "someInfo")
You can access the object in javascript:
您可以在 javascript 中访问该对象:
console.log(window.someInfo.title);
window.someInfo.title = "Some title";
To expose an Swift object to javascript, properties and methods must be dynamic dispatching. This means, properties must be dynamic, methods must has @objcattribute. (See https://developer.apple.com/swift/blog/?id=27for dynamic dispatching). For simple, inherit from NSObject.
要将 Swift 对象暴露给 javascript,属性和方法必须是动态调度的。这意味着,属性必须是动态的,方法必须具有@objc属性。(有关动态调度,请参阅https://developer.apple.com/swift/blog/?id=27)。简单来说,继承自 NSObject。
回答by Ashok
In .swift, define and call this method
在 .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)")
}
}
In .js/.html file
在 .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;
}
回答by Deciple
Answering my own question:
回答我自己的问题:
JSON is (probably) the best type to pass to javascript.
JSON(可能)是传递给 javascript 的最佳类型。
I removed the class and instead created an NSDictionary like (or type your class as NSDictionary):
我删除了该类,而是创建了一个 NSDictionary 之类的(或将您的类键入为 NSDictionary):
var allInfoRawSwift = ["title": "This is the title", "description": "this is the description"]
Then convert it to JSON (inside do/catch if swift 2):
然后将其转换为 JSON(在 do/catch if swift 2 中):
let allInfoJSON = try NSJSONSerialization.dataWithJSONObject(allInfoRawSwift, options: NSJSONWritingOptions(rawValue: 0))
The convert JSON to string:
将 JSON 转换为字符串:
let allInfoJSONString = NSString(data: allInfoJSON, encoding: NSUTF8StringEncoding)!
Then add the souce propery like:
然后添加源属性,如:
source: "changeDisplay(\(allInfoJSONSting))"
To debug, it's best to have your function just set a global variable to whatever your passing, then use safari's developer mode to access a web console and inspect the global variable.
要调试,最好让您的函数只为您传递的任何内容设置一个全局变量,然后使用 safari 的开发人员模式访问 Web 控制台并检查全局变量。
Let me know if there's a better way or if you have any tips.
如果有更好的方法或您有任何提示,请告诉我。
Thanks
谢谢
回答by Jamie Birch
Here's an update of the Swift code from Ashok's accepted answer, compatible with Swift 3.0.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)")
})
}
回答by Anastasiia Staiko
Here is my suggestion (using json as data example):
这是我的建议(使用 json 作为数据示例):
- Create json:
- 创建json:
var json = ["value1": "One", "value2": "two"]
var json = ["value1": "一", "value2": "二"]
- Encode to a string (I'm not using base64):
- 编码为字符串(我没有使用 base64):
guard let json = try? JSONEncoder().encode(permissionsJSON), let jsonString = String(data: json, encoding: .utf8) else { return }
守卫让 json = 试试?JSONEncoder().encode(permissionsJSON), let jsonString = String(data: json, encoding: .utf8) else { return }
- Send:
- 发送:
webView.evaluateJavaScript("window.evite.webview.yourName('(jsonString)')")
webView.evaluateJavaScript("window.evite.webview.yourName('(jsonString)')")