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.
Pass JavaScript variable to Swift
I thought I would answer this myself.
First, ensure your class is conforming to the correct protocols: WKScriptMessageHandler
is required and you may also need WKNavigationDelegate
.
Before initializing your WKWebView add a userContentController to its configuration. This is what will act as a 'bridge' from your JavaScript to Swift.
var webView = WKWebView()
let configuration = WKWebViewConfiguration()
configuration.userContentController.add(self, name: "messageName")
webView = WKWebView(frame: .zero, configuration: configuration)
Now initialize the userContentController()
function and handle the received content within it. Ex.
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("Name: \(message.name)")
print("Body: \(message.body as! String)")
}
Now within the JavaScript inside your evaluateJavaScript()
add the following line to push whatever data to Swift:
window.webkit.messageHandlers['messageName'].postMessage('Message Body!');
Now, when that JavaScript line is called Swift will output the following:
Name: messageName
Body: Message Body!
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).
How can I send data from javascript to swift?
Hi Make use of below code. Here the below code keeps looking for message from javascript and specifically for "paymentHandler"
import WebKit
class PaymentGateWayViewController: UIViewController,UIWebViewDelegate,WKScriptMessageHandler{
var containerView = UIView()
var webView: WKWebView?
override func loadView() {
super.loadView()
containerView = UIView(frame: self.view.bounds)
self.view.addSubview(containerView)
}
override func viewDidLoad() {
super.viewDidLoad()
let contentController = WKUserContentController();
contentController.add(self,name: "paymentHandler")
let config = WKWebViewConfiguration()
config.userContentController = contentController
self.webView = WKWebView(frame: self.containerView.bounds,configuration: config)
self.view = self.webView!
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if(message.name == "paymentHandler") {
print("JavaScript is sending a message \(message.body)")
}
}
SwiftUI WKWebview how to transfer variable to html?
You need to make a coordinator within your WebView. The coordinator should be the webview delegate. You need a delegate otherwise
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
will never be called. This article does the same with MapKit but the pattern is the same: https://www.hackingwithswift.com/books/ios-swiftui/communicating-with-a-mapkit-coordinator
Related Topics
How to Write a Script to Edit a JSON File
R Networkd3 Package: Node Coloring in Simplenetwork()
How to Show Modal Window in Controller's Action
Wkwebkit JavaScript Execution When Not Attached to a View Hierarchy
Passing Array of Objects from Js to Rails
What Is an Exclamation Point in JavaScript
Shiny: Start the App with Hidden Tabs, with No Delay
How to Get All Arguments of a Function as Single Object Inside That Function
How to Render a Partial from JavaScript
Syntaxerror: Unexpected Token Function - Async Await Nodejs
Remove Duplicates Form an Array
How to Include Js.Erb File in View Folder
In R, How to Display Value on the Links/Paths of Sankey Graph
Elliptic Curve Cryptography with Sjcl in Js and Openssl in Ruby
Xmlhttprequest Status 0 (Responsetext Is Empty)
How to Prevent the Backspace Key from Navigating Back
$.Deferred: How to Detect When Every Promise Has Been Executed