How to Pass a Swift Object to JavaScript (Wkwebview/Swift)

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

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.

How to call this javascript function from WKWebView Swift?

According to your code, the parameter result should contain the property url. We suppose that the url contains the JSON data you want to pass.

Try the following 2 approaches:

// Approach 1:
func callJS() {
let json = "{ url:\"An url with json?\"}"
let scriptString = "let result=\(json); appQrHandlerSet(result);"
webView?.evaluateJavaScript(scriptString, completionHandler: { (object, error) in

})
}

// Approach 2:
func initWebViewWithJs() {
let config = WKWebViewConfiguration()
config.userContentController = WKUserContentController()

let json = "{ url:\"An url with json?\"}"
let scriptString = "let result=\(json); appQrHandlerSet(result);"
let script = WKUserScript(source: scriptString, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true)
config.userContentController.addUserScript(script)

webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 320, height: 400), configuration: config)
}

How can I send data from swift to javascript and display them in my web view?

You should ask the Location Manager to update the location for you instead of setting up a 1-second NSTimer to do it yourself. And to pass data to Javascript, you can use evaluateJavaScript method of WKWebView:

import UIKit
import WebKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {
weak var webView: WKWebView!
let locationManager = CLLocationManager()

override func viewDidLoad() {
super.viewDidLoad()

createWebView()
locationManager.delegate = self
locationManager.startUpdatingLocation()
locationManager.requestWhenInUseAuthorization()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

func createWebView() {
let url = NSBundle.mainBundle().URLForResource("my_page", withExtension: "html")!

let webView = WKWebView()
webView.loadFileURL(url, allowingReadAccessToURL: url)
webView.translatesAutoresizingMaskIntoConstraints = false

self.view.addSubview(webView)

// Auto Layout
let views = ["webView": webView]
let c1 = NSLayoutConstraint.constraintsWithVisualFormat("H:|[webView]|", options: [], metrics: nil, views: views)
let c2 = NSLayoutConstraint.constraintsWithVisualFormat("V:[webView]|", options: [], metrics: nil, views: views)
let c3 = NSLayoutConstraint(item: webView, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide , attribute: .Bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activateConstraints(c1 + c2 + [c3])

// Pass the reference to the View's Controller
self.webView = webView
}

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let lastLocation = locations.last!

let dict = [
"lat": lastLocation.coordinate.latitude,
"long": lastLocation.coordinate.longitude
]
let jsonData = try! NSJSONSerialization.dataWithJSONObject(dict, options: [])
let jsonString = String(data: jsonData, encoding: NSUTF8StringEncoding)!

// Send the location update to the page
self.webView.evaluateJavaScript("updateLocation(\(jsonString))") { result, error in
guard error == nil else {
print(error)
return
}
}
}
}

And my_page.html:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0">
<title>This is a test page</title>
<script type="text/javascript">
function updateLocation(data)
{
var ele = document.getElementById('location');
ele.innerHTML = 'Last location: lat = ' + data['lat'] + ', long = ' + data['long'];
}
</script>
</head>
<body>
<p id="location">Last location:</p>
</body>
</html>

If you are testing this in the Simulator, choose Debug > Location > City Run to see it update continuously (as if you are running through a park).



Related Topics



Leave a reply



Submit