iOS UIWebView to Native Code Communication

If you are like a lot of companies these days you want to leverage your old content but also use the lasted advances in mobile computing. One way to do this is by making hybrid apps that are part native code and part web content. This is where the UIWebView comes into play. With the UIWebView we can wrap our content in native code, use native elements such as buttons and menus to help with performance, while allowing web content to be consumed.

But how do you send messages to the native code from HTML and JavaScript? It’s not as hard as you might think. The best way I have found is by using the NSURLProtocol.

Assumptions:
– Working knowledge of objective-c, HTML and JavaScript
– Basic grasp of UIWebView

Lets Begin!
Start by creating a single view application
single view application

Give your application a name (I called mine WebToAppCommunication).
Once its open create a new group (right click on the root folder and select New Group) and call it jsDocs.

Next you will need to create a new .js file (File>New>File…) and choose Other Empty file.
Screen Shot 2014-08-07 at 2.24.08 PM

Name the file communicate.js

Now that we have the new .js file lets add some code
The first thing we add is the log function. All this is doing is sending an ajax call to a specific URL that our app will in turn listen for. We will name it debuglogger

function log(msg) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', "http://debuglogger/" + encodeURIComponent(msg));
    xhr.send(null);
}

The next function will just be a function that we will call from within in the app. In this case we are just going to call this function that will in turn call the log function and send us back the message. NOTE: this function can be called from any js code as well but for this article I’m just calling it from the app to illustrate the message.

function sendMessage(){
    log("FROM WEB: This could be any String");
}

Now to make sure this file is put in with the build lets go ahead and add it to the build phase. Click the main project and navigate to the build tab. Then expand the Copy Bundle Resource area and click the + button. Navigate to the communicate.js file and add it.

Next lets make our web console class. Start by adding a new File (File>New>File…) only this time we will select Objective-C Class. Make sure you add NSURLProtocol as subclass from.
Screen Shot 2014-08-07 at 3.20.27 PM
Name the file WebConsole (I named mine WTA_WebConsole) and then open the .h file and add the enable the + sign means we don’t need to create an instance of the class to use it. Now the method it should look something like this.

#import <Foundation/Foundation.h>

@interface WTA_WebConsole : NSURLProtocol
+ (void) enable;
@end

Now open the .m file and past in the following code. This first part just registers the web console class to start it listening for messages. The second part handles any incoming requests. In this case you listen for the debuglogger and print out a log message to the console. But you can do pretty much what every you want with it at this point.

+ (void) enable {
    [NSURLProtocol registerClass:[WTA_WebConsole class]];
}

+ (BOOL) canInitWithRequest:(NSURLRequest *)request {
    if ([[[request URL] host] isEqualToString:@"debuglogger"]){
        NSLog(@"%@", [[[request URL] path] substringFromIndex: 1]);
    }
    
    return FALSE;
}

Ok lastly we need to enable the console. So to do this we well add

[WTA_WebConsole enable];

to your main ViewController’s viewDidLoad method. Don’t forget to add the import

#import "WTA_WebConsole.h"

That’s pretty much it for the communication aspect of the code. The only thing left to is create a way to call the JavaScript. The way I am going to do this is by just creating a simple button the calls the function we created called sendMessage()

I’m not really going to go deep into all the details on how to hook up a button and the UIWebView. Here are the highlights. In your ViewController .h file you will need the following

@interface WTA_ViewController : UIViewController<UIWebViewDelegate>
- (IBAction)makeMessage:(id)sender;
@property (weak, nonatomic) IBOutlet UIWebView *basicWebview;
@property (weak, nonatomic) IBOutlet UITextView *messageContainer;

Now in your ViewController .m file you need to know when the webpage is loaded so you can put your custom.js in there you will need to add webViewDidFinishLoad

-(void)webViewDidFinishLoad:(UIWebView *)webView {
    
    NSString *jsFile = @"communicate.js";
    NSString *jsFilePath = [[NSBundle mainBundle] pathForResource:jsFile ofType:nil];
    NSURL *jsURL = [NSURL fileURLWithPath:jsFilePath];
    
    NSString *javascriptCode = [NSString stringWithContentsOfFile:jsURL.path encoding:NSUTF8StringEncoding error:nil];
    [_basicWebview stringByEvaluatingJavaScriptFromString:javascriptCode];
    
}

Lastly lets put in a webpage. To do that just add the following code to the viewDidLoad

    NSString *website = @"https://bitcows.com";
    NSURL *url = [NSURL URLWithString:website];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
     _basicWebview.delegate = self;
    
    [_basicWebview loadRequest:request];

GET THE FULL CODE PROJECT HERE

Loading Facebook Comments ...