Swift webview: How to call correctly swift code from javascript?
24,927
Solution 1
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!
}
Solution 2
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) {}
}
}
Related videos on Youtube
Author by
adam
Updated on December 22, 2020Comments
-
adam over 3 years
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. } }
-
robert over 5 yearsApple's Documentation for loadView developer.apple.com/documentation/uikit/uiviewcontroller/… says: "Your custom implementation of this method should not call super." That may not be obvious in the accepted answer.
-
-
Dev over 8 yearsPlease note calling
self.view.frame
in theloadView()
method causesEXC_BAD_ACCESS
crash. -
Eduard over 8 years@Dev what should I call instead self.view.frame if it's casugin
EXC_BAD_ACCESS
-
sandrom over 7 years@Dev it only does if you forget to call super.loadView() beforehand
-
Heitor about 5 yearsHi, could you help me by providing the MacOS version of it?
-
Heitor about 5 yearsWhat about the MacOS version?