Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I am working on passing data from swift to javascript inside a WKWebView

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:

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:

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.

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.

Thanks

EDIT: I answered how I was able to pass data as JSON below.

like image 425
Deciple Avatar asked Aug 20 '15 09:08

Deciple


People also ask

What is WKWebView JavaScript?

A WKWebView object is a platform-native view that you use to incorporate web content seamlessly into your app's UI. A web view supports a full web-browsing experience, and presents HTML, CSS, and JavaScript content alongside your app's native views.


2 Answers

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.

like image 78
soflare Avatar answered Oct 10 '22 09:10

soflare


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;
}
like image 29
Ashok Avatar answered Oct 10 '22 08:10

Ashok