How do I pass a swift object to javascript (WKWebView / swift)

Answering my own question:

JSON is (probably) the best type to pass to javascript.

I removed the class and instead created an NSDictionary like (or type your class as NSDictionary):

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

Then convert it to JSON (inside do/catch if swift 2):

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

The convert JSON to string:

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.

Let me know if there's a better way or if you have any tips.

Thanks


In .swift, define and call this method

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

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;
}

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")

You can access the object in 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 @objc attribute. (See https://developer.apple.com/swift/blog/?id=27 for dynamic dispatching). For simple, inherit from NSObject.