Saturday, May 28, 2011

Local Web Views for the iPad and iPhone

Sometimes we need to display complex information in iPhone or iPad applications. The UIWebView is a very handy for doing this. But how do we get dynamic or live data into our UIWebViews? Wouldn't it be nice to have the ability to make a full fledged web application that runs locally on the device?

This post shows you how to do this. The Ikhoyo Web View is a set of classes that make it easy to construct complex web applications that run on the local device. The web views can use live real time data from your application since templating is used to generate the final pages that are displayed in your view.

Ikhoyo web views are a combination of the Mustache templating language to generate xml or html, and Extensible Style Sheets (xsl) to generate the final page. Using xsl is not required, but as you'll see, it's very useful for generating complex html pages.

If you haven't already, go to GitHub and clone our repository. If you're using Xcode 4, go to the workspaces directory and open the ikhoyo-public workspace.

First, let's look at the structure of an Ikhoyo web view. In the ikhoyo-top project, you'll see a directory called xcode-resources/webviews. This contains the web views that we are displaying for this app. Currently, there are two of them, home and sample-web-view. home is what you see when you start ikhoyo-top, and sample-web-view is a detail view that you can select from the master table view on the left.

Look in sample-web-view. There are two files, index.xml and sample.xsl. To start an Ikhoyo web view in your code, you call the start method on IkhoyoWebViewController and pass in the base directory (xcode-resources/webviews/sample-web-view in this case). The start method looks for index.xml and runs it through Mustache with a context that you supply. The context contains any data the Mustache template needs to generate the xml file.

The Mustache template generates an xml file, which is then displayed in the UIWebView. The xml file contains a reference to sample.xsl, telling UIWebView to use that stylesheet to format the html in the web view. The style sheet processing is done inside UIWebView, we don't have to write code to do the transformation.

The style sheet processing is not required, and you can have the Mustache templates generate html directly. We prefer using xsl for anything even slightly complicated because the processing logic in xsl is very powerful, much more powerful than Mustache templates. It also insulates your code from changes. For instance, if you decide at a later date to get the data remotely, then you can use the same style sheet to display the data in the web view.

Let's look a little closer at SampleWebView. Select SampleWebView.xib. Open up the Navigation Controller in the tree and look at the Ikhoyo Web View Controller. This is where we wire up the UIWebView to the IkhoyoWebViewController. You must connect the webView outlet from IkhoyoWebViewController to the web view used to display the generated pages. In this case, the UIWebView is the same as the main view of the controller. You must also connect the delegate outlet on the UIWebView to the IkhoyoWebViewController. You can verify these are connected properly by viewing the connections in the Connections inspector for each object.

Also notice that we include the SampleWebViewContext in the xib file. It's not a UI object, but it's needed by the IkhoyoWebViewController. So why not let Interface Builder instantiate it and wire it up for us instead of doing it manually?

We'll drill down into the workings of the IkhoyoWebViewController later. For now, note that the only thing you need to do to get an IkhoyoWebViewController in your own apps is the following:

  • Make a directory in your bundle to hold the Ikhoyo Web view xml and/or xsl files. We hang our web views off of the xcode-resources/webviews directory.
  • Make a subclass of IkhoyoWebViewContext to hold any local data that your web view displays. We'll show you how this works later.
  • Wire up an IkhoyoWebViewController to a UIWebView with Interface Builder. We showed you how to do this above.
  • Call the start method on the IkhoyoWebViewController to start it up.

Most of the coding for Ikhoyo Web Views is either making the Mustache templates (which are usually quite simple), or the xsl style sheets (which can be quite complex). In other words, the only Objective C coding that you need to write is for the IkhoyoWebViewContext, which supplies the local data to the templates.

Let's switch back to some internals and see how the IkhoyoWebViewController does it's thing, then we'll delve into details of Mustache templates and xsl.

Click on IkkhoyWebViewController.m in the ikhoyo-ui project. Look at the start method. start expects the base directory of the web view. It looks for index.xml in the base directory and sends it through Mustache with the supplied context. The code for this is:
NSString* template = [NSString stringWithContentsOfFile:path 
  usedEncoding:&enc error:&error];
NSString* result = [GRMustacheTemplate renderObject:self.context 
  fromString:template error:&error];
The result is a string of xml which is displayed in the UIWebView with:
[self.webView loadData:data MIMEType:mime textEncodingName:@"utf-8" 
  baseURL:self.baseUrl];
For xml, the MIMEType must be 'text/xml', or the data won't be interpreted as xml, and any xsl processing won't occur.

Now let's switch back to the Mustache template, xsl style sheet, and IkhoyoWebViewContext. Look in xcode-resources/webviews/sample-web-view/index.xml. This is the Mustache template. You can read up on the details of Mustache templates here. All we're really doing is extracting some of the data from the context and inserting it into our xml file. The Objective C Mustache processor (which is included in ikhoyo-ui) uses key-value coding to find the things it needs in the context. For this example, we added a list of Items in the context (the listOfItems field). Mustache takes this list and inserts it into index.xml. The data is then rendered with the sample.xsl style sheet when it's loaded in the UIWebView.

Notice this line at the top of index.xml:
<?xml-stylesheet type="text/xsl" href="sample.xsl"?>
This tells the UIWebView to process the xml with the sample.xsl style sheet before displaying it in the view. This works exactly the same in the Safari web browser (other browsers also). In fact, you can generate a test xml file and do all your debugging in Safari before putting it into your app. It will save you a lot of time.

This sample is quite simple, but you're not limited to doing simple things. You can have a complete web application running in an Ikhoyo Web view by adding to index.xml and sample.xsl. It's a normal html page being generated and rendered, so anything a UIWebView accepts is valid.

No comments:

Post a Comment