iOS - Communication from Javascript to iOS

iOS - Communication from Javascript to iOS

This is the second part of two series article. You have already read the first part which shows how to transfer data from iOS to JavaScript. In this part we will see how you can transfer data from JavaScript function back to iOS (Swift).

For the clarity purpose and to remove any ambiguity, I am going to replace the word iOS with Swift, since the code we are going to follow is written in the Swift which is the part of larger eco-system iOS

There are certain use cases where certain function is invoked on the web page and native iOS app needs to know about result of operation. For example, one of the app I had previously worked on required user to tap on one of the buttons on web page. This would trigger another function in JavaScript which would return full image URL to display inside an app. This was in fact first use-case I came across which involved communication from JavaScript back to iOS.

Just like the previous post let's start with look at sample HTML code from where we are going to invoke our function.

I have also added a demo code for communication between iOS and JavaScript and it is hosted on the GitHub. It demonstrates two way communication. From iOS to JavaScript and other way around, along with minor examples mentioned in this post

web-side code


<html>

<head>
<script>

    function triggerWithCustomMessage(inputName) {
        var value = {name: inputName, salutation: 'Your Grace'};
        var jsonString = (JSON.stringify(value));
        var escapedJsonParameters = escape(jsonString);
        var appName = 'SampleSwiftCode';
        var actionType = 'PrintData';

        var url = appName + '://' + actionType + "#" + escapedJsonParameters;
        document.location.href = url;
    }

    function invokeMessage() {
        var inputName = document.getElementById('name').value
        triggerWithCustomMessage(inputName)
    }

    </script>
    </head>
<body>
<button onclick='invokeMessage()'>Type and Click</button>
<input type='text' name='firstname' id='name' value='Jamie'><br>
    </body>
</html>

So what does the code above do?

  1. Above code creates a very simple web page with text field and button
  2. User can type any text he wants in the field and press the adjacent button
  3. The button will then trigger a function invokeMessage which will create a custom URL corresponding to the text user entered in the text field. With this URL, JavaScript will use classic document.location.href to redirect web page to that resource
  4. This redirect is then captured by our UIWebView and then app can control whether this URL can be loaded or not. Alternatively, URL is formed of several parts (host, scheme, url, parameters etc). So app can also parse URL to fetch information passed from JavaScript code including the name input by the user in the form

Now, given this let's look at how Swift code looks like for intercepting this request. For the purpose of this example let's assume that user inputs the text say Jaime in the text field and JavaScript construct the full url with known host and scheme to get resulting URL as follows.

sampleswiftcode://PrintData#<parameters>

In short,
scheme = sampleswiftcode

host = PrintData

I am assuming you already have UI ready with UIWebView and the HTML mentioned above has already been loaded. Make sure UIWebView is setup properly and its delegate is set to current view controller

Once the above formality is done, next step is to implement a delegate method as mentioned below which will get called before every web request that fires up in the UIWebView object.


func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
// Scheme = sampleswiftcode
    let requestScheme = request.url?.scheme
// host = PrintData
    let requestHost = request.url?.host
// jsonString is the stringified object passed by JavaScript from the above code
    let jsonString = request.url?.fragment?.removingPercentEncoding
// We will convert this JSON string into Swift object using utility. jsonDictionary = ["name": "Jamie", "salutation": "Your Grace"]
    let jsonDictionary = convertToDictionary(text: jsonString)

    return true
}

// A utility function to convert JSON string into object
// Ref: http://stackoverflow.com/a/30480777
func convertToDictionary(text: String?) -> [String: Any]? {
    guard let text = text else {
        return [:]
    }
    if let data = text.data(using: .utf8) {
        do {
            return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
        } catch {
            print(error.localizedDescription)
        }
    }
    return nil
}

The delegate method will be called as soon as user presses the button. When user presses the button, JavaScript function will redirect web page to another url with document.location.href code which will cause to fire up func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool in the current view controller.

There goes our second and last part of communication between iOS and JavaScript using Swift. If you haven't already, make sure to go through first part as well which shows how to send data from iOS to JavaScript with Swift

Any questions, comments, concerns, queries are welcome. You may send me an email. If not, do not hesitate to message in Twitter to @jayeshkawli