How to Pass Data from JavaScript to Swift Within a Wkwebview

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



Leave a reply



Submit