Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript call to Swift from UIWebView

I am trying to make a call from a javascript function in a UIWebView to Swift in iOS 10. I have setup a very basic project just to try and get this working, the code is below.

import UIKit

class ViewController: UIViewController, UIWebViewDelegate  {    
  @IBOutlet var webView: UIWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let url = Bundle.main.url(forResource: "products", withExtension: "html")
        let request = NSURLRequest(url: url! as URL)
        webView.loadRequest(request as URLRequest)
    }

    @IBAction func closeDocumentViewer() {
        displayView.isHidden = true;
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

If I just one to receive a string from a javascript function what would I have to add to the above?

like image 534
Tony Goodchild Avatar asked Nov 23 '16 10:11

Tony Goodchild


People also ask

Is UIWebView deprecated?

Apple is phasing out UIWebView, which is used by developers for integrating web content into an app in a quick and secure manner. Apple is replacing UIWebView (and WebView) with WKWebView, an updated version, as UIWebView has been deprecated.

When was UIWebView deprecated?

It is supported in iOS and macOS, and by Mac Catalyst. Note: The App Store will no longer accept new apps that use UIWebView as of April 2020 and app updates that use UIWebView as of December 2020. Since iOS 12, Apple began warning developers about migrating to WKWebView, UIWebView's successor.

What is the difference between UIWebView and WKWebView?

Unlike UIWebView, which does not support server authentication challenges, WKWebView does. In practical terms, this means that when using WKWebView, you can enter site credentials for password-protected websites.

Can I use WebView in iOS?

As mentioned above, to load the web content in the iOS application, we can use the WebView object. All we need to do is, create a WKWebView object, set it as a view, and send it a request to load web content.


1 Answers

I would suggest looking into using WKWebView instead UIWebView. You then won't need to register custom URL scheme. Additionally, UIWebView is obsolete and WKWebView has a lot of advantages, most notably performance and rendering as it runs in a separate process.

Link to Apple documentation and recommendation to use WKWebView https://developer.apple.com/reference/webkit/wkwebview/

Important

Starting in iOS 8.0 and OS X 10.10, use WKWebView to add web content to your > app. Do not use UIWebView or WebView.

That said, it's very simple to setup a native to javascript bridge:

import WebKit

class ViewController: UIViewController, WKScriptMessageHandler {
   var webView: WKWebView?
    override func loadView() {
        super.loadView()
        
        webView = WKWebView(frame: self.view.frame)
        webView?.configuration.userContentController.add(self, name: "scriptHandler")
        
        self.view.addSubview(webView!)
    }
    
    public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        print("Message received: \(message.name) with body: \(message.body)")
    }
// rest of code
}

Then in your javascript code, call it:

window.webkit.messageHandlers["scriptHandler"].postMessage("hello");

I have written a library that leverages this and adds some fancy javascript syntax. https://github.com/tmarkovski/BridgeCommander

To use it, just reference the project (or add the swift and javascript files to your Xcode project) and call

    webView = WKWebView(frame: self.view.frame)
    let commander = SwiftBridgeCommander(webView!)
    
    commander.add("echo") {
        command in
        command.send(args: "You said: \(command.args)")
    }

You then will be able to use callback syntax in javascript like this

var commander = new SwiftBridgeCommander();
commander.call("echo", "Hello", function(args) {
        // success callback
    }, function(error) { 
        // error callback
});
like image 131
Tomislav Markovski Avatar answered Oct 14 '22 07:10

Tomislav Markovski