James Edward James Edward - 3 months ago 115
iOS Question

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.

Answer

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.