An iOS5 Ready Native Web App Template
Posted on Fri Feb 24 2012 10:00:34 GMT+0000 (UTC)
Several months ago, I wrote a template/tutorial on developing a Native iOS Web App that seized the phone's camera functionality. Since then it has been a relatively popular article on my blog, iOS5 was released and I've also received some questions/feedback. So, I thought it might be appropriate to revise this template, based on the previous one and go over the changes. Download the code here.
So lets briefly discuss what we are going to do:
- This template will use ARC (Automatic Reference Counting) introduced in iOS5
- We won't use Interface Builder at all in this template
- We will instead create a subclass of UIViewController and place a webview on top programatically
- The class will automatically detect objc:// schema links and try to run that method in a custom delegate class we will build
The HTML stuff
The XCode Project
Now we can move on to our XCode project. You can build your own or follow along in the sample code. I've used a simple View Based Application. First thing, we will temporarily ignore the UIViewController that XCode makes for us with the template and create our own file from scratch - Call it "WebViewController" and its contents will be as follows:
The code is well commented but let's look at the functionality of this class from a high level.
- On viewDidLoad the class instantiates a UIWebView programatically and adds it to the view
- We set the class as the UIWebView Delegate, so it will listen directly to the UIWebView we added
- The class has two functions to load either a URL or a local .html file
- We receive a callback from the UIWebView to ask permission to follow any link with webView:shouldStartLoadWithRequest:navigationType:
- We listen in the callback specifically for "objc" schemed links and we fire the appropriate method on our WebViewControllerDelegate if it can respond to this method
- "objc" schemed links can also send string parameters. For example, "objc://doThis/then/that" would run a method
and the NSArray would have 2 NSStrings : @"then",@"that"
- For convenience sake if there is only 1 parameter, it will pass as a
(NSString *) instead
Speaking of our WebViewControllerDelegate, let's look at it next:
The WebViewControllerDelegate is only responsible for dealing with methods that are intended to be called from HTML. In my previous template, the equivalent delegate class was also the UIWebViewDelegate, so it was the gatekeeper for following links as well. However, I feel it is wrong to do this for one important reason: You should have a fresh delegate capable of only responding to methods you actually want exposed to HTML. Using the old method from my previous template, we were effectively exposing methods more methods that we wouldn't really ever want to call. With that, you could argue that my UIImagePickerController related methods shouldn't even be in this delegate. If this template was more complex, I would have moved it out.
To summarize the functionality we are seeing:
- We have a takeCameraImage: function which checks if your device has a camera and then launches a UIImagePickerController
- We also have a takeLibraryImage: function which opens the photo library instead
One last step
So with that, we are set up and ready to do some Native iOS HTML'in , there's just one more thing. Go back to our original UIViewController that we ignored at the start and subclass it from WebViewController instead, like so:
And it's just that easy. In one simple line in our viewDidLoad we are now capable of loading HTML files that can call exposed obj-c methods that we write. The nice thing about this template, is you can subclass it to your heart's content and reuse the functionality easily in multiple places across a more complex app.