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

Dec*_*ple 7 iphone xcode ios swift swift2

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

我有一个自定义类:

class AllInfo: AnyObject {
    var title = "Special Title"
    var description = "Special Description"
}
Run Code Online (Sandbox Code Playgroud)

并初始化它

var info = AllInfo()
Run Code Online (Sandbox Code Playgroud)

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

source: "changeDisplay('\(info)')"
Run Code Online (Sandbox Code Playgroud)

我的问题是如何在javascript中访问此对象.我试图像javascript对象一样访问它以及没有运气的关联数组.这是js功能:

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

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

所以我的问题是:

我可以将AnyObject传递给JavaScript并访问它吗?如果没有,我应该使用什么类型的swift类,以便我可以轻松传递它.

我很想在swift中创建一个javascript对象并传递它,但我觉得有更好的方法.

谢谢

编辑:我回答了我如何能够以下面的JSON传递数据.

Ash*_*hok 14

在.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)")
    }
}
Run Code Online (Sandbox Code Playgroud)

在.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;
}
Run Code Online (Sandbox Code Playgroud)


Dec*_*ple 5

回答我自己的问题:

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

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

var allInfoRawSwift = ["title": "This is the title", "description": "this is the description"]
Run Code Online (Sandbox Code Playgroud)

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

let allInfoJSON = try NSJSONSerialization.dataWithJSONObject(allInfoRawSwift, options: NSJSONWritingOptions(rawValue: 0))
Run Code Online (Sandbox Code Playgroud)

将 JSON 转换为字符串:

let allInfoJSONString = NSString(data: allInfoJSON, encoding: NSUTF8StringEncoding)!
Run Code Online (Sandbox Code Playgroud)

然后添加源属性,如:

source: "changeDisplay(\(allInfoJSONSting))"
Run Code Online (Sandbox Code Playgroud)

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

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

谢谢


sof*_*are 5

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.

I created a project named XWebView which provides language binding styled API based on the raw message passing of WKWebView. It's written in Swift.

Regarding your example, the object has to be injected in javascript namespace firstly:

let webView = WKWebView(frame: frame, configuration: WKWebViewConfiguration())
webView.loadPlugin(AllInfo(), namespace: "someInfo")
Run Code Online (Sandbox Code Playgroud)

You can access the object in javascript:

console.log(window.someInfo.title);
window.someInfo.title = "Some title";
Run Code Online (Sandbox Code Playgroud)

To expose an Swift object to javascript, properties and methods must be dynamic dispatching. This means, properties must be dynamic, methods must has @objc attribute. (See https://developer.apple.com/swift/blog/?id=27 for dynamic dispatching). For simple, inherit from NSObject.

  • 看下面我更简单的解决方案..没有 XWebView 或动态调度等 (2认同)