Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift webview: How to call correctly swift code from javascript?

Tags:

I'm trying to make my javascript interact with swift code but unfortunately i didn't succeed.

For the moment, i just tried to change the headers colors and display a message like you will see in the code below.

Here's my (index.html) code:

<!DOCTYPE html> <html>     <head>         <title>Test</title>         <meta charset="UTF-8">     </head>     <body>         <h1>WebView Test</h1>         <script type="text/javascript" src="main.js"></script>     </body> </html> 

Here's my (main.js -JavaScript) code:

function callNativeApp () {     try {         webkit.messageHandlers.callbackHandler.postMessage("Send from JavaScript");     } catch(err) {         console.log('error');     } }  setTimeout(function () {     callNativeApp(); }, 5000);  function redHeader() {     document.querySelector('h1').style.color = "red"; } 

Here's my (ViewController.swift) code:

import UIKit import WebKit  class ViewController: UIViewController, WKScriptMessageHandler {      @IBOutlet var containerView : UIView! = nil      var webView: WKWebView?      override func loadView() {         super.loadView()          var contentController = WKUserContentController();         var userScript = WKUserScript(             source: "redHeader()",             injectionTime: WKUserScriptInjectionTime.AtDocumentEnd,             forMainFrameOnly: true         )         contentController.addUserScript(userScript)         contentController.addScriptMessageHandler(             self,             name: "callbackHandler"         )          var config = WKWebViewConfiguration()         config.userContentController = contentController          self.webView = WKWebView()         self.view = self.webView!     }      override func viewDidLoad() {         super.viewDidLoad()         // Do any additional setup after loading the view, typically from a nib.         var url = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("index", ofType: "html")!)         var req = NSURLRequest(URL: url)         self.webView!.loadRequest(req)     }      func userContentController(userContentController: WKUserContentController!,didReceiveScriptMessage message: WKScriptMessage!) {             if(message.name == "callbackHandler") {             println("JavaScript is sending a message \(message.body)")             } }      override func didReceiveMemoryWarning() {         super.didReceiveMemoryWarning()         // Dispose of any resources that can be recreated.     }   } 
like image 343
adam Avatar asked Sep 13 '14 20:09

adam


People also ask

Can you use JavaScript with Swift?

The JavaScriptCore framework provides the ability to evaluate JavaScript programs from within Swift, Objective-C, and C-based apps. You can use also use JavaScriptCore to insert custom objects into the JavaScript environment.

How is Swift code executed?

Swift code is compiled into machine code. Thus your compiled Swift program can be run as a standalone program - A user doesn't need to have Swift or Xcode installed to run your compiled Swift program.


2 Answers

You have everything set up properly, but you aren't giving your WKWebViewConfiguration instance to the WKWebView. Since the configuration has the details of the Javascript/Swift bridge, you can't talk back and forth.

override func loadView() {     // ...     var config = WKWebViewConfiguration()     config.userContentController = contentController      self.webView = WKWebView(frame: self.view.frame, configuration: config)     self.view = self.webView! } 
like image 168
Nate Cook Avatar answered Sep 24 '22 12:09

Nate Cook


my 2 cents, using a javascript callback with JSON ... for full class definition and layout, refer to adam's code

import UIKit import WebKit  class ViewController: UIViewController, WKScriptMessageHandler {     var webView: WKWebView?     ... 

then

override func loadView() {     let theConfiguration = WKWebViewConfiguration()     let contentController = theConfiguration.userContentController      // alert fix, at start to allow a JS script to overwrite it     contentController.addUserScript( WKUserScript(         source: "window.alert = function(message){window.webkit.messageHandlers.messageBox.postMessage({message:message});};",         injectionTime: WKUserScriptInjectionTime.AtDocumentStart,         forMainFrameOnly: true     ) )     contentController.addScriptMessageHandler(self, name: "messageBox")      self.webView = WKWebView(frame: self.view.frame, configuration: theConfiguration)      // and here things like: self.webView!.navigationDelegate = self     self.view = self.webView!  // fill controllers view } 

and specifically

func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {      if message.name == "messageBox" {         let sentData = message.body as! Dictionary<String, String>          let message:String? = sentData["message"]          let alertController = UIAlertController(title: nil, message: message, preferredStyle: UIAlertControllerStyle.Alert)         alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment:"btnOK"), style: .Default, handler: nil))         self.presentViewController(alertController, animated: true) {}     } } 
like image 38
BananaAcid Avatar answered Sep 22 '22 12:09

BananaAcid