I have a VIewController with WKWebView to display HTML content to my users. What I need is to get some information from my project side(swift codes) such as app version, data reports to javascrtript side. On the side of js, I'll be able to generate html codes or display elements based on swift function calls.
Here are some codes in my ViewController:
class AboutViewController: UIViewController
{
@IBOutlet weak var webView: WKWebView!
{
didSet {
setJS()
}
}
private let jsCtx = JSContext()
private func setJS() {
let obj = MyVersionClass()
jsCtx.ctx.setObject(
obj,
forKeyedSubscript: "versionObj")
}
override func viewDidLoad() {
super.viewDidLoad()
// build url
webView.loadFileURL(
url,
allowingReadAccessTo: url)
let request = URLRequest(url: url)
webView.load(request)
}
MyVersionClass is defined as:
import JavaScriptCore
@objc protocol JSAppVersionProtocol: JSExport
{
func getAppVersion() -> String
static func createObj() -> MyVersionClass
}
class MyVersionClass: NSObject, JSAppVersionProtocol
{
static func createObj() -> MyVersionClass {
let obj = MyVersionClass()
return obj
}
func getAppVersion() -> String {
...
}
}
The class AboutViewController will load an html file with js defined in script section
<head>
<script type="text/javascript" src="../version.js"></script>
</head>
<body onload="updateVersion()">
...
<span id="appVersion">To be updated with my app version
</span>
....
JS code:
function updateVersion()
{
let e = document.getElementById("appVersion");
var ver =versionObj.getAppVersion();
// another try, see following codes
// var ver =versionObj.createObj().getAppVersion();
e.innerHTML = ver;
}
I tested the js function call in my AbountViewController class right after I setObject like this:
let result = jsCtx.evaluateScript("versionObj")
print("\(result)"
I got the result in console like this:
<MyApp.JSAppVersion: 0x282aa0af0>
I also tried to setObject like this:
jsCtx.ctx.setObject(
MyVersionClass.self,
forKeyedSubscript: "versionType")
// My test of script function
let result = jsCtx.evaluateScript("versionType")
print("\(result)" // result is <MyApp.MyVersionClass>
However, it seems that my js does not know what my swift function code is. It fails to get the app version.
Not sure what is missing or wrong? How can I set up mu swift function available in js side?
JavaScriptCore is not the droid you’re looking for here. There’s no supported way to share a JavaScriptCore context between your app and a WKWebView
[1].
The standard approach for this with WKWebView
is to use the WKUserContentController
class to install a script message handler.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] That’s because the WKWebView
runs all of its JavaScript is a separate process for security reasons. For general background on this, watch WWDC 2018 Session 207 Strategies for Securing Web Content.