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
How to Make App Wait Until Firebase Request Is Finished
Your Credentials Do Not Allow Access to This Resource Twitter API Error
Ios-Charts How to Put Uiimage Beside a Point
Swift - Set Delegate for Singleton
How to Make Playground Execution Time Is as Fast as If We Run in iOS Application
Collectionview Flowlayout Overlapping When Scrolling Not Working
How to Use Tap Gesture in Accessibility in Swift
How to Send Emails in Swift Using Mailgun
No Such Module "Sinch" Xcode 9.1 Swift 4
Why Clusterannotationformemberannotations in Mkmapview Is Not Called
Swift - Uitableview Didselectrowatindexpath & Diddeselectrowatindexpath Add & Remove Indexpath Ids
Uitraitcollection Clarification
How to Update a Swiftui View State from Outside (Uiviewcontroller for Example)
How to Call the Apple Wallet from iOS App Using Swift
Replay Kit Not Working iPad iOS11 Bug
Uibezierpath + Cashapelayer - Animate a Circle Filling Up
Indexing into Array of Functions: Expression Resolves to an Unused L-Value