How to call javascript function from .js file in swift

15.2k views Asked by At

I tried to call a Javascript function from swift using below code but can't access the Javascript function

This is how I create the Javascript context object:

lazy var context: JSContext? = {
        let context = JSContext()

        guard let
            JSPath = Bundle.main.path(forResource: "IAV", ofType: "html")
            else {
                print("Unable to read resource files.")
                return nil
        }


        do {
            let iav = try String(contentsOfFile: JSPath, encoding: String.Encoding.utf8)
            _ = context?.evaluateScript(iav)
        } catch (let error) {
            print("Error while processing script file: \(error)")
        }

        return context
    }()

//Set value to js

func setToken(Token:String)
    {
        let jsmethod = context?.objectForKeyedSubscript("setIAVToken")
        let passParameter = jsmethod?.call(withArguments: [Token])
    }

The content of html file is



sample IAV form

</head>  


<body > <header> </header> <main>
<h1>Registration Form</h1>  
<form id="myform" method="post">  
 <div id="mainContainer">   <input type="button" id="start" value="Add Bank"> </div>  

var value="dhjhsd";

var setIAVToken = function(token) {
value= token;
}


$('#start').click(function() {
var iavToken = value;
alert(iavToken)
dwolla.configure('uat');
dwolla.iav.start('iavContainer', iavToken, function(err, res) {
console.log('Error: ' + JSON.stringify(err) + ' -- Response: ' + JSON.stringify(res));
});
}); </script> </html>
3

There are 3 answers

14
Poles On

In case of objective c do the following:

  • #import <JavaScriptCore/JavaScriptCore.h> in header file.

  • Next use this code inside viewcontroller.

NSString *jsPath = [[NSBundle mainBundle] pathForResource:@"JSFileName" ofType:@"js"];

NSString *scriptString = [NSString stringWithContentsOfFile:jsPath encoding:NSUTF8StringEncoding error:nil];

JSContext *context = [[JSContext alloc] init];
    context = [[JSContext alloc] init];
    [context evaluateScript:scriptString];
    JSValue *function = context[@"setMessage"];
    JSValue* result = [function callWithArguments:@[@"your custom string"]]; //pass the string whatever you want.
    [result toString]; // This will give the value in string format.
0
Poles On

Edit the html, use <input type="button" id="start" value="Add Bank" onClick="setMessage()"> instead of <input type="button" id="start" value="Add Bank">

Also add <input type="hidden" id="token" value="Token value"> inside the form to pass the token value.

In the javascript method:

<script>
  function setMessage() {
  var iavToken = document.getElementById("token").value;
  alert(iavToken)
  dwolla.configure('uat');
  dwolla.iav.start('iavContainer', iavToken, function(err, res) {
  console.log('Error: ' + JSON.stringify(err) + ' -- Response: ' +  JSON.stringify(res));
  });
  } 
</script>

Next invoke the javascript function using the following objective c.

NSString * jsCallBack = [NSString stringWithFormat:@"setMessage()"]; 
 [webView stringByEvaluatingJavaScriptFromString:jsCallBack];

P.S: You need to add <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> (or if you have the js file locally add it.) in the html to work with the js.

0
denis_lor On

You should probably use WKWebView (which is the new way to load web content in a webview in iOS since it uses WebKit and has lots of improvements like better memory allocation than it does WebView).

In a swift file WebviewBridging.swift in iOS you could have something like

import UIKit
import WebKit

class WebviewBridging: UIViewController, WKNavigationDelegate {

    var webView: WKWebView?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Create a WKWebView instance
        webView = WKWebView (frame: self.view.frame, configuration: webConfig)
        view.addSubview(webView!)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let url = Bundle.main.url(forResource: "index", withExtension: "html")!
        webView!.loadFileURL(url, allowingReadAccessTo: url)
    }

    func callJSFunctionFromSwift(){
        webView!.evaluateJavaScript("changeBackgroundColor('red')", completionHandler: nil)
    }
}

In an index.html file on your iOS project folder you could have something like:

<html>
    <head>
    </head>
    <body>
    <script>
    function changeBackgroundColor(colorText) {
        document.body.style.background = colorText;
    }
    </script>
    </body>
</html> 

Whenever you will call callJSFunctionFromSwift() in swift it will communicate with the WKWebView through XPC communication and evaluate your javascript code that will trigger the javascript function in index.html.