Skip to content

Instantly share code, notes, and snippets.

@hoishing
Last active November 26, 2022 13:20
Show Gist options
  • Save hoishing/d19de7176fc4c5c713c1335ec62046a2 to your computer and use it in GitHub Desktop.
Save hoishing/d19de7176fc4c5c713c1335ec62046a2 to your computer and use it in GitHub Desktop.
Using Javascript with WKWebView

Using Javascript with WKWebView

Harnessing The Power of Both Languages in Your Apps

WebKit allows us to use javascript along side with the native swift code. On one hand, we could call the javascript statements in swift. On the other hand, javascript from web view could be able to trigger a delegate method defined in swift code. This gives us a two way communication between the native swift code and javascript used by a web view.

Basic Setup

Here we have a window with a WKWebView showing some text. It has 2 buttons inside. One for showing the text and triggering a swift handler, the other for hiding the text. Also, we have a native button that triggers a javascript function to hide the text.

Triggering Javascript Functions from Swift

The IB outlet and action of the app as follow. Note that we simply use evaluateJavaScript(_:completionHandler:) to trigger some javascript in the web view, hideText() is a custom method we defined inside javascript.

@IBOutlet var webV: WKWebView!
    
@IBAction func showJSAlert(_ sender: Any) {
   let js = "hideText();"
   webV.evaluateJavaScript(js, completionHandler: nil)
}

Receiving Javascript Messages

To receive message from the javascript, we need to provide a message name for javascript to call upon. We just name it “jsHandler”. After that we load the html and javascript into the web view.

override func viewDidLoad() {
   super.viewDidLoad()
   webV.configuration.userContentController.add(self, name: "jsHandler")
   let bundleURL = Bundle.main.resourceURL!.absoluteURL
   let html = bundleURL.appendingPathComponent("try.html")
   webV.loadFileURL(html, allowingReadAccessTo:bundleURL)
}

We also need to adopt the WKScriptMessageHandler protocol in our view controller, and implement the userContentController(_:didReceive:) method. For simplicity, we just print out the message received from the javascript.

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
   if message.name == "jsHandler" {
       print(message.body)
   }
}

The HTML and javascript we loaded as follow. Note that in the showText() method, the window.webkit.messageHandlers.jsHandler.postMessage() is the method we use to trigger the delegate method implemented in our view controller.

<!DOCTYPE html>
<html>
<head>
    <script>        
        function hideText() {
            document.getElementById("demo").style.display = "none";
        }
    
        function showText() {
            document.getElementById("demo").style.display = "block";
            window.webkit.messageHandlers.jsHandler.postMessage("trigger from JS");
        }
    </script>
</head>
<body>
    <p id="demo">Hello World.</p>
    <input type="button" onclick="showText()" value="Show Text and Trigger Handler">
    <input type="button" onclick="hideText()" value="Hide Text">
</body>
</html>

Download Sample Project

@IBOutlet var webV: WKWebView!
@IBAction func showJSAlert(_ sender: Any) {
let js = "hideText();"
webV.evaluateJavaScript(js, completionHandler: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
webV.configuration.userContentController.add(self, name: "jsHandler")
let bundleURL = Bundle.main.resourceURL!.absoluteURL
let html = bundleURL.appendingPathComponent("try.html")
webV.loadFileURL(html, allowingReadAccessTo:bundleURL)
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "jsHandler" {
print(message.body)
}
}
<!DOCTYPE html>
<html>
<head>
<script>
function hideText() {
document.getElementById("demo").style.display = "none";
}
function showText() {
document.getElementById("demo").style.display = "block";
window.webkit.messageHandlers.jsHandler.postMessage("trigger from JS");
}
</script>
</head>
<body>
<p id="demo">Hello World.</p>
<input type="button" onclick="showText()" value="Show Text and Trigger Handler">
<input type="button" onclick="hideText()" value="Hide Text">
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment