{"id":283,"date":"2014-08-08T01:48:52","date_gmt":"2014-08-08T01:48:52","guid":{"rendered":"http:\/\/bitcows.com\/?p=283"},"modified":"2014-08-08T01:48:52","modified_gmt":"2014-08-08T01:48:52","slug":"ios-uiwebview-to-native-code-communication","status":"publish","type":"post","link":"https:\/\/bitcows.com\/?p=283","title":{"rendered":"iOS UIWebView to Native Code Communication"},"content":{"rendered":"<p>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 <em>UIWebView<\/em> comes into play. With the <em>UIWebView<\/em> 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.<\/p>\n<p>But how do you send messages to the native code from HTML and JavaScript? It&#8217;s not as hard as you might think. The best way I have found is by using the <em>NSURLProtocol<\/em>.<\/p>\n<p><strong>Assumptions:<\/strong><br \/>\n&#8211; Working knowledge of objective-c, HTML and JavaScript<br \/>\n&#8211; Basic grasp of UIWebView<\/p>\n<p><strong>Lets Begin!<\/strong><br \/>\nStart by creating a single view application<br \/>\n<img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2014\/08\/Screen-Shot-2014-08-07-at-2.19.13-PM.png\" alt=\"single view application\" width=\"400\" class=\"alignnone size-full wp-image-284\" \/><\/p>\n<p>Give your application a name (I called mine WebToAppCommunication).<br \/>\nOnce its open create a new group (right click on the root folder and select New Group) and call it jsDocs.<\/p>\n<p>Next you will need to create a new .js file (File>New>File&#8230;) and choose Other Empty file.<br \/>\n<img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2014\/08\/Screen-Shot-2014-08-07-at-2.24.08-PM.png\" alt=\"Screen Shot 2014-08-07 at 2.24.08 PM\" width=\"400\" class=\"alignnone size-full wp-image-286\" \/><\/p>\n<p>Name the file communicate.js<\/p>\n<p>Now that we have the new .js file lets add some code<br \/>\nThe 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<\/p>\n<pre class=\"prettyprint\">function log(msg) {\n    var xhr = new XMLHttpRequest();\n    xhr.open('GET', \"http:\/\/debuglogger\/\" + encodeURIComponent(msg));\n    xhr.send(null);\n}<\/pre>\n<p>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. <em>NOTE: this function can be called from any js code as well but for this article I&#8217;m just calling it from the app to illustrate the message.<\/em><\/p>\n<pre class=\"prettyprint\">function sendMessage(){\n    log(\"FROM WEB: This could be any String\");\n}<\/pre>\n<p>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.<br \/>\n<img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2014\/08\/Screen-Shot-2014-08-07-at-3.14.03-PM.png\" alt=\"\" width=\"600\" class=\"alignnone size-full wp-image-289\" \/><\/p>\n<p>Next lets make our web console class. Start by adding a new File (File>New>File&#8230;) only this time we will select Objective-C Class. Make sure you add <em>NSURLProtocol<\/em> as subclass from.<br \/>\n<img decoding=\"async\" src=\"http:\/\/bitcows.com\/wp-content\/uploads\/2014\/08\/Screen-Shot-2014-08-07-at-3.20.27-PM.png\" alt=\"Screen Shot 2014-08-07 at 3.20.27 PM\" width=\"600\" class=\"alignnone size-full wp-image-291\" \/><br \/>\nName the file WebConsole (I named mine WTA_WebConsole) and then open the .h file and add the <em>enable<\/em> the + sign means we don&#8217;t need to create an instance of the class to use it. Now the method it should look something like this.<\/p>\n<pre class=\"prettyprint\">#import &lt;Foundation\/Foundation.h&gt;\n\n@interface WTA_WebConsole : NSURLProtocol\n+ (void) enable;\n@end<\/pre>\n<p>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.<\/p>\n<pre class=\"prettyprint\">+ (void) enable {\n    [NSURLProtocol registerClass:[WTA_WebConsole class]];\n}\n\n+ (BOOL) canInitWithRequest:(NSURLRequest *)request {\n    if ([[[request URL] host] isEqualToString:@\"debuglogger\"]){\n        NSLog(@\"%@\", [[[request URL] path] substringFromIndex: 1]);\n    }\n    \n    return FALSE;\n}<\/pre>\n<p>Ok lastly we need to enable the console. So to do this we well add <\/p>\n<pre class=\"prettyprint\">[WTA_WebConsole enable];<\/pre>\n<p> to your main ViewController&#8217;s <em>viewDidLoad<\/em> method. Don&#8217;t forget to add the import<\/p>\n<pre class=\"prettyprint\">#import \"WTA_WebConsole.h\"<\/pre>\n<p>That&#8217;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 <em>sendMessage()<\/em><\/p>\n<p>I&#8217;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<br \/>\n<strong><UIWebViewDelegate><\/strong><\/p>\n<pre class=\"prettyprint\">@interface WTA_ViewController : UIViewController&lt;UIWebViewDelegate&gt;<\/pre>\n<pre class=\"prettyprint\">- (IBAction)makeMessage:(id)sender;\n@property (weak, nonatomic) IBOutlet UIWebView *basicWebview;\n@property (weak, nonatomic) IBOutlet UITextView *messageContainer;<\/pre>\n<p>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 <em>webViewDidFinishLoad<\/em><\/p>\n<pre class=\"prettyprint\">-(void)webViewDidFinishLoad:(UIWebView *)webView {\n    \n    NSString *jsFile = @\"communicate.js\";\n    NSString *jsFilePath = [[NSBundle mainBundle] pathForResource:jsFile ofType:nil];\n    NSURL *jsURL = [NSURL fileURLWithPath:jsFilePath];\n    \n    NSString *javascriptCode = [NSString stringWithContentsOfFile:jsURL.path encoding:NSUTF8StringEncoding error:nil];\n    [_basicWebview stringByEvaluatingJavaScriptFromString:javascriptCode];\n    \n}<\/pre>\n<p>Lastly lets put in a webpage. To do that just add the following code to the <em>viewDidLoad<\/em><\/p>\n<pre class=\"prettyprint\">\n    NSString *website = @\"http:\/\/bitcows.com\";\n    NSURL *url = [NSURL URLWithString:website];\n    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];\n    \n     _basicWebview.delegate = self;\n    \n    [_basicWebview loadRequest:request];<\/pre>\n<p><a href=\"https:\/\/github.com\/djmason9\/WebToAppCommunication\">GET THE FULL CODE PROJECT HERE<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&hellip;<\/p>\n<p class=\"more-link\"><a href=\"https:\/\/bitcows.com\/?p=283\" class=\"themebutton\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":310,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[15,16],"tags":[37,49],"class_list":["post-283","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ios","category-code-examples","tag-code","tag-ios-2"],"_links":{"self":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/posts\/283","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=283"}],"version-history":[{"count":0,"href":"https:\/\/bitcows.com\/index.php?rest_route=\/wp\/v2\/posts\/283\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=\/"}],"wp:attachment":[{"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=283"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=283"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bitcows.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=283"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}