Often times in web applications you interact with web services to add interesting functionality to your apps. Most times you use your server to interact with a web service and pass the results onto the client. JSONP or similar techniques can be used to call those services from the client and bypass your server. Using UIWebView in iOS allows us to inject JavaScript into rendered pages and interact with them. This allows us to roll our own API’s and not have to do any server side logic.

A good example of this is using Google Translate to translate strings between natural languages. You could sign up for the service and call it from your server. The pricing for this interaction is listed here. However, if you browse to Google Translate you can see that if you type something into the input box on the left, the web page will autodetect the source language and display the results in the box on the right.

So, we can create a UIWebView in an iOS app and inject JS into this page and return the results back to the app.

First, we create a UIWebView and load the Google translate url into the webview. After the page loads, we inject JS to listen for changes on the box on the right:


    //listen for the onchange for the result box
    NSString *js = @"var resultBox = document.getElementById('result_box'); "     "var resultChecks = 0;"     "var checkForResult = function() { "     "  resultChecks += 1;"     "  if(resultChecks > 100) {"     "     window.location = 'lu://error/1';"     "  }"     "  else if(resultBox.childNodes.length < 1) { "     "     setTimeout(checkForResult, 50); "     "  }"     "  else {"     "    var translation = ''; "     "    for(var i = 0; i < resultBox.childNodes.length; i++) { "     "       var text = resultBox.childNodes[i].innerText;"     "       if(text) { "     "           if(i > 0) { translation += ' '; } "     "           translation += text; "     "       } "     "    }"     "    window.location = 'lu://translated/'+translation; "     "  }"     "};"     "setTimeout(checkForResult, 50);";
    [_webView stringByEvaluatingJavaScriptFromString:js];

Notice this line in the JS: window.location = lu://translated/'+translation
This allows us to listen for url changes in the web view and then respond to them in Objective C code. Here we execute a callback whenever a string is translated:


    if([scheme isEqualToString:@"lu"]) {
        NSString *host = request.URL.host;
        if([host isEqualToString:@"translated"]) {
            NSString *translationText = [request.URL.pathComponents objectAtIndex:1];
            NSDictionary *sourceAndCallback = [_sourcesAndCallbacks objectAtIndex:0];
            [_sourcesAndCallbacks removeObjectAtIndex:0];
            void (^success)(NSString*) = [sourceAndCallback objectForKey:@"success"];
            success(translationText);
            //NSLog(@"translation: %@", translationText);
            NSURL *googleTranslateUrl = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", GOOGLE_TRANSLATE_HOST]];
            [_webView loadRequest:[NSMutableURLRequest requestWithURL:googleTranslateUrl]];
        }

To translate a string, we inject the source string into the box on the left:


    //inject the text to be translated into the source textarea
    NSString *js = [NSString stringWithFormat:@"var source = document.getElementById('source'); "                     "source.value = '%@';", source];
    [_webView stringByEvaluatingJavaScriptFromString:js];

There is a full example and source available at: https://github.com/jhurt/GoogleTranslateiOS

GoogleTranslateiOS

Also please note that this code is for demonstration purposes only. It can obviously break when translate.google.com changes so use with caution.

I hope this example showed you how to roll your own API’s in iOS using JavaScript injection. Enjoy buddies!

This entry was posted in iOS, Technical. Bookmark the permalink.