JavaScript Call to Swift from Uiwebview

Javascript call to Swift from UIWebView

You must a custom URL Scheme such as myawesomeapp and intercept requests to it using:

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool

Fire a call to native code using window.location=myawesomeapp://hello=world, and get the query params you pass from request.URL.query in the native code.

For more information, see my question about UIWebViews here: JavaScript synchronous native communication to WKWebView

Call swift function with javascript using UIWebview

Implement listenInSwift like this:

function listenInSwift() {
window.location = 'yoururlscheme://somehost?greeting=hello'
}

Then listen for this URL with this code in your UIWebViewDelegate class:

func webView(_ webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType navigationType: UIWebViewNavigationType) -> Bool {
if request.URL.scheme == 'yoururlscheme' {
print('Hello JavaScript...')
}
}

Don't forget to register your URL Scheme (in this case 'yoururlscheme') in Xcode.

To load a local file in the web view, try this:

let baseURL = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath);
let relativePath = "www/\(file)"
let fileURL = NSURL(string: relativePath, relativeToURL: baseURL);
let URLRequest = NSURLRequest(URL: fileURL!);
webView.loadRequest(URLRequest)

UIWebView and JavaScriptInterface in Swift

For WKWebView: source here

JavaScript

function callNativeApp () {
try {
webkit.messageHandlers.callbackHandler.postMessage("Hello from JavaScript");
} catch(err) {
console.log('The native context does not exist yet');
}
}

Swift

import WebKit
class ViewController: UIViewController, WKScriptMessageHandler {

@IBOutlet var containerView: UIView? = nil

var webView: WKWebView?

override func loadView() {
super.loadView()

let contentController = WKUserContentController()
contentController.addScriptMessageHandler(self, name: "callbackHandler")
let config = WKWebViewConfiguration()
config.userContentController = contentController

self.webView = WKWebView( frame: self.containerView!.bounds, configuration: config)
self.view = self.webView

}

override func viewDidLoad() {
super.viewDidLoad()

//I use the file html in local
let path = NSBundle.mainBundle().pathForResource("index", ofType: "html")
let url = NSURL(fileURLWithPath: path!)
let req = NSURLRequest(URL: url)
self.webView!.loadRequest(req)

}

func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {// edit: changed fun to func
if (message.name == "callbackHandler"){
print("\(message.body)")
}
}

}

For UIWebView: source here

JavaScript in HTML

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
(function(){
$(window).load(function(){

$('.clickMe').on('click', function(){
window.location = "foobar://fizz?Hello_from_javaScript";
});
});
})(jQuery);
</script>

Swift

import UIKit
class ViewController: UIViewController, UIWebViewDelegate {

@IBOutlet weak var Web: UIWebView!

override func viewDidLoad() {
super.viewDidLoad()

let path = NSBundle.mainBundle().pathForResource("index", ofType: "html")
let url = NSURL(fileURLWithPath: path!)
let req = NSURLRequest(URL: url)
Web.delegate = self
Web.loadRequest(req)
}

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if request.URL?.query != nil {
print("\(request.URL!.query!)")
}
return true
}

}

Inject Javascript into Webview - Swift

Just do:

let js = "var myelement = document.getElementById(\"test\");myelement.innerHTML= \"New Text\";"
webView.evaluateJavaScript(js, completionHandler: nil)

If you are using UIWebView instead of WKWebView, do this:

let js = "var myelement = document.getElementById(\"test\");myelement.innerHTML= \"New Text\";"
_ = webView.stringByEvaluatingJavaScript(from: js)

Javascript console log in UIWebView in Swift

Here's a basic implementation for the UIWebView:

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

// Create the web view.
let webView = UIWebView()
webView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(webView)
webView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
webView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
webView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
webView.delegate = self
webView.loadRequest(URLRequest(url: URL(string: "https://www.google.com.py")!))
}
}

extension ViewController: UIWebViewDelegate {
func webViewDidFinishLoad(_ webView: UIWebView) {
let js = "console.log = function() {window.location = 'logger://webview?' + JSON.stringify(Array.prototype.slice.call(arguments))}"
webView.stringByEvaluatingJavaScript(from: js)
}

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if request.url?.scheme == "logger" {
guard let data = request.url?.query?.removingPercentEncoding?.data(using: .utf8) else { return true }
guard let obj = try? JSONSerialization.jsonObject(with: data, options: []) else { return true }
guard let jsonData = try? JSONSerialization.data(withJSONObject: obj, options: .prettyPrinted) else { return true }
guard let json = String(data: jsonData, encoding: .utf8) else { return true }
print(json)
}
return true
}
}

Example

console.log(4, 3.53, 'Hello', {d: {f: 4}}, function() {}, undefined, null, true)

Prints the following in Xcode log:

[
4,
3.5299999999999998,
"Hello",
{
"d" : {
"f" : 4
}
},
null,
null,
null,
true
]

Caveats

  • This only prints logs executed after the page has loaded.
  • Since we're using JSON.stringify, we can't print the following types: function, undefined
  • Since we're using JSON.stringify, true and false are
    printed as 1 and 0, respectively

Controlling website within Xcode/ Swift UIWebView

Check this question and responses:

Calling Javascript using UIWebView

  1. Create a js method to receive your barcode.
  2. When the page is already loaded, you can call it by using stringByEvaluatingJavaScriptFromString.

    let codebar = "34244342342424234"
    webView.stringByEvaluatingJavaScriptFromString("methodName("\(codebar)");")


Update

I used this method some time ago: evaluateJavaScript in WKWebView, this example loads a jQuery and then change the background:

var navigator : WKWebView!

func runJS(js:String) {
navigator.evaluateJavaScript(js) {
res, error in
print(res ?? "no res", error ?? "no error")
}
}

@IBAction func changeBackground(_ sender: Any) {
navigator.evaluateJavaScript("jQuery('body').css('background', 'magenta!important')") {res, error in print(error ?? "no error buton 1")}
}

@IBAction func loadJQuery(_ sender: Any) {
//Load jQuery library using plain JavaScript
runJS(js: "(function(){ " +
"var newscript = document.createElement('script'); " +
"newscript.type = 'text/javascript'; " +
"newscript.async = true; " +
"newscript.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js'; " +
"(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(newscript); " +
"})();")
}


Related Topics



Leave a reply



Submit