Hybrid iPhone Applications

Increase your speed to market by building a hybrid application for iPhone

Hybrid Applications

Last week we learned how to build “Native Web” applications for Android.

That was fun, but what exactly is a hybrid application?

A true native application is one that is written with the SDK of the target platform — Java for Android, Objective-C/Cocoa Touch for iPhone.

A relatively new term has become main-stream in the mobile space — the hybrid application.

No, this doesn’t mean we run it on soybeans or ethanol — this term has come to describe the “native web” approach where the application is written and compiled in the “SDK”, however the primary user interface is implemented in HTML, CSS and Javascript running inside of the platform’s “web” control. This is the web developer’s on-ramp to mobile application development and when used judiciously, can lower your time to market for the right kind of applications.

Last week was Android’s turn — this week we build an iPhone application to see how the hybrid architecture works here.

In this article we build a simple application for iPhone which leverages the UIWebView control to display our own, albeit simplistic, HTML interface. While the high-level architecture is very similar to what we saw for Android, the implementation is a bit different. I personally prefer the Android approach, however the iPhone approach is certainly workable.

As a further piece of information before we get started: there are more sophisticated tools available to build these kinds of applications. Appcelerator Titanium and the PhoneGap project are top of mind. If you want to get started right away building applications for the Apple App Store, you might want to check out one of those tools.

If you are curious as to just how this works for iPhone and you are perhaps one of those people whose favorite HTML editor is “vi” or “notepad”, stick around and check out this week’s application.

To give credit where it is due, I have modeled this approach after the techniques used by the PhoneGap project. If there are more clever ways of doing this that you have run across, please let me know!

iPhone Application

One of the goals of our application is to be “native” — meaning that it can be installed on the device, run off-line (if desired) and ultimately be distributed to other users. The most likely scenario for that distribution is via the App Store. The image below shows the launcher screen of the iPhone simulator with our application’s icon circled.

hia_home_screen.png

When we load the application by selecting the icon, our application presents a super simple HTML interface — remember we are more interested in the inner-workings of this application than its visual appeal. Excuses, excuses…

The page contains a single link to Linux Magazine (of course…), three buttons, an HTML <span> and a graphic. Here is the HTML used in the application.

<html>
<body>
<center>
<a href='http://linux-mag.com'>Visit Linux Magazine</a><br />
<br />
<br />
<button style="color:red" onclick="document.location = 'linuxmag://color/background?red'";>Cornell Big Red</button><br />
<button style="color:blue" onclick="document.location = 'linuxmag://color/background?blue'";>Blue Devils</button><br />
<button style="color:green" onclick="document.location = 'linuxmag://color/background?green'";>Green Wave</button><br />
Msg:<span style="background-color:yellow"id='msg'>something of interest can go here....</span>
<br /><br />
<img src="lmlogo.jpg" />
</center>
</body>
</html>

The image below shows the application as it appears when the app is launched:

hia_justloaded.png

Selecting the link will bring up the target link:

hia_linuxmag.png

Note that we have not included any browser navigation tools like back, forward, etc. in this application — this link is here just to show that we can link to an external site if desired, though that is not the focus of this application. We will learn more about how links are handled in just a moment when we start looking at the Objective-C code.

Returning our focus to the buttons on our HTML page — each is labeled with a colored piece of text, listing a couple of NCAA basketball power houses along with an another Ivy Leage team. Selecting any of the buttons causes the time to be written to the HTML page with a different back-color as shown here:

hia_red.png

Sorting out exactly how this happens is the purpose of this application. Now, to be fair, this functionality certainly doesn’t require a native application — it is merely demonstrative of higher-purpose functionality that a hybrid application can perform. Let’s look at how this works in Objective-C.

Delegation

Our project is constructed in X-Code. For those who missed the memo, you can only develop native, or in this case hybrid, iPhone applications on an Intel-based Mac. The screen show below shows our project loaded in X-Code:

hia_xcode.png

For all the busy-ness of the X-Code project, we are mostly concerned with the hiaAppDelegate.* files. Let’s look first at the header file:

//
//  hiaAppDelegate.h
//  hia
//
//  Created by Frank Ableson on 12/7/09.
//  Copyright MSI Services, Inc. 2009. Use as you like :)
//

#import <UIKit/UIKit.h>

@interface hiaAppDelegate : NSObject <UIApplicationDelegate,UIWebViewDelegate> {
    UIWindow *window;
	UIWebView *browser;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) UIWebView *browser;
@end

Most of the code around property and nonatomic etc. are beyond our focus right now. What we want to look at is the fact that this particular class implements the “UIWebViewDelegate” protocol and that we define an instance of the UIWebView class. This is how we interface with HTML, CSS and Javascript. Using this class in the way we do is what makes this application a “hybrid” app.

The UIWindow was created as part of the automagically iPhone project when you select “New Project”. One thing to make note of here is the IBOutlet keyword — that indicates that this particular variable is connected to a “widget” defined in the InterfaceBuilder application, X-Codes drag-n-drop GUI builder.

That is the usual and ordinary way user interface elements are created in iPhone development. However, please note that we are NOT using that approach for working with our UIWebView. Remember your early commitment to vi and notepad?

By keeping all of our interactions with the UIWebView class directly in code, it will hopefully take some of the mystery out of working with it. Let’s see how our UIWebView object is instantiated.

The code for the method applicaitionDidFinishLaunching is shown below, along with comments to help you understand what is happening.

  • Make the main window visible.
  • Setup the UIWebView control, set its dimensions.
  • Assign the delegate, which will allow us to override default behavior — this is the key to the hybrid application and is discussed further below.
  • Setup a local file to be loaded into the UIWebView. Seems like a lot of work to say, “load index.html”.
  • Add the browser to the main screen.
  • If you prefer a more “immersive” experience, you can remove the application’s status bar by uncommenting the last line.
- (void)applicationDidFinishLaunching:(UIApplication *)application {    

   // show main window
	[window makeKeyAndVisible];

   // instantiate the UIWebView object -- assign it to the variable "browser"
   // set the control to take most of the screen via the CGRectMake macro
	browser = [[UIWebView alloc] initWithFrame:CGRectMake(0,20,320,460)];

	// assign the object's delegate
   browser.delegate = self;		

   // load up the index.html file included in the project
	NSURL *startUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle]  pathForResource:@"index" ofType:@"html"]];
	NSURLRequest * startRequest = [NSURLRequest requestWithURL:startUrl];
	[browser loadRequest:startRequest];

	// add the control to the main window
	[window addSubview:browser];

//	[[UIApplication sharedApplication] setStatusBarHidden:YES];
}

At this point our application is running, and the index.html file is rendered into the UIWebView, drawn to the main window. What happens when the user selects something? The method shouldStartLoadWithRequest is invoked. Here is the code and some basic explanation.

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
	NSURL *url = [request URL];

	NSLog([NSString stringWithFormat:@"URL is : [%@]",[url absoluteString]]);

	switch(navigationType) {
		case UIWebViewNavigationTypeLinkClicked:
			NSLog(@"Nav type: Link selected.");
			break;
		case UIWebViewNavigationTypeFormSubmitted:
			NSLog(@"Nav type: Form Submitted.");
			break;
		case UIWebViewNavigationTypeBackForward:
			NSLog(@"Nav type: Back/Forward");
			break;
		case UIWebViewNavigationTypeReload:
			NSLog(@"Nav type: Reload");
			break;
		case UIWebViewNavigationTypeFormResubmitted:
			NSLog(@"Nav type: Form Re-Submitted?");
			break;
		case UIWebViewNavigationTypeOther:
			NSLog(@"Nav type: Other");
			break;
		default:
			NSLog(@"Nav type: Something else...");
			break;
	}
	if ([[url scheme] isEqualToString:@"linuxmag"]) {
		NSLog([NSString stringWithFormat:@"host is [%@] query is [%@] path is [%@] paramterString is [%@]",(NSString *) [url host],(NSString *) [url query],(NSString *) [url path],(NSString *) [url parameterString]]);

		if ([[url host] isEqualToString:@"color"]) {
			if ([[url path] isEqualToString:@"/background"]) {
				[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.getElementById('msg').style.backgroundColor = \"%@\";",[url query]]];
			}
		}
	    [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.getElementById('msg').innerHTML = \"%@\";",[[NSDate date] description]]];
	   return NO;
	}
	return YES;
}
  • This code is invoked prior to the browser control loading new content.
  • For fun, we examine the navigationType. To be candid, I was just curious as to what it would do — you may find some value in it. In particular, watch this as you load an external page with multiple image and script links downloaded. The NSLog() function drops message to the debug window in X-Code.
  • We look at the “scheme”. This is typically http or ftp. To customize content for our hybrid application, we define our own “scheme”. In this case, we use the keyword linuxmag. If the code encounters a link with linuxmag, we handle it in a special fashion.
  • Assuming we’re working with one of our linuxmag URLs, we then break down the URL into host, query and path. Based on these values we can perform various application-specific functionality.
  • To interact with the html content, we use the stringByEvaluatingJavaScriptFromString message. You just have to love those verbose names!
  • We update the back-color by manipulating the style and then populate the innerHTML to contain the date.

If we want tell the browser to not load a particular page, we can filter them out by returning NO rather than YES.

Unlike the Android approach of mapping Javascript functions directly to Java functions, this approach requires us to crack each URL and parse out the various elements — including scheme, path, and query name/value pairs if you are so inclined.

It may be a consequence of running on the emulator, but I felt that the application was a bit more sluggish than the Android application we built last week. Fast or slow, this approach is perfectly valid, and arguably more consistent with an Ajax-ian feel to it where so much takes place with constructed URLs as opposed to more function calls within the Javascript environment. I personally prefer the Android approach, but this works too.

Regardless of how you feel about having to parse-out commands from URLs, the advantage of the hybrid approach to iPhone application development is that you can focus your HTML skills on the UI and then do basic Objective-C coding for the plug-and-chug portions of your application, without getting caught up in the myriad of Cocoa Touch classes. Let CSS do the work for you. This won’t work for every application but for many line of business applications, this approach can speed time to market.

As usual, the code for this application is available on the Code Hosting site.

Well, that wraps up our introduction to the hybrid iphone application. And, just for fun, the first reader to name the basketball team I played for (hint, it’s in the html), I’ll send a copy of the Unlocking Android ebook.

Fatal error: Call to undefined function aa_author_bios() in /opt/apache/dms/b2b/linux-mag.com/site/www/htdocs/wp-content/themes/linuxmag/single.php on line 62