Apr 11

This Device Has Expired

This week Apple displayed their control over all iPhone developers by bricking all iPhones and iPod Touch devices used for development. The installed firmware expired at 12:01 am on April 8th. Much, much later in the afternoon Apple released an updated firmware.

Exploring iPhone Graphics Part 1

Pete begins a new trail, this time about graphics. Great stuff as usual.

iPhone OS 2.0 has embedded YouTube support

More and more integration type features are added to Safari for the 2.0 release.

written by Nick

Apr 09

Say you want each customer to accept your Terms of Service, or some other legalese, before they can use your iPhone application.

Display the screen upon startup

The standard AppDelegate code generated by Xcode creates and displays your first application screen. Here’s a way that you can use the hidden property of UIView to display your new screen first without disrupting the flow of the rest of the application.

// Create window
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
[window setBackgroundColor:[UIColor whiteColor]];
    
// Set up main view navigation controller
MainMenuViewController *navController = [[MainMenuViewController alloc] init];
	
// Create a navigation controller using the new controller
navigationController = [[UINavigationController alloc] initWithRootViewController:navController];
navigationController.navigationBarStyle = UIBarStyleDefault;
	
[navController release];

// Create Terms of Service screen	
tosController = [[TermsOfServiceViewController alloc] init];
[window addSubview:[tosController view]];
navigationController.view.hidden = YES;

// Add the navigation controller's view to the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];

Most of this is boilerplate code, more or less generated by Xcode. What’s new starts at line 14. Instantiate the new TermsOfServiceViewController and add it to the view. Standard stuff. The important line is #17, which hides the navigationController.

Dismiss the new screen

Now that the Terms of Service screen is displayed and the Main Menu is hidden we need a way to dismiss the ToS screen and return to the normal application flow.

In your AppDelegate class create a new method:

- (void)termsOfServiceAccepted
{
	tosController.view.hidden = YES;
	navigationController.view.hidden = NO;
}

In the TermsOfServiceController you would have a button that the user has to tap:

UIButton *acceptButton = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
acceptButton.frame = CGRectMake(kLeftMargin, 
						applicationFrame.size.height - kBottomMargin - kButtonHeight, 
						applicationFrame.size.width - kLeftMargin - kRightMargin, 
						kButtonHeight);
[acceptButton setTitle:NSLocalizedString(@"ButtonAcceptTermsOfService", @"") forStates:UIControlStateNormal];
[acceptButton addTarget:self action:@selector(termsOfServiceAccepted:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:acceptButton];

When the button is tapped, the selector is called which in turn calls the above method in the AppDelegate.

- (void)termsOfServiceAccepted:(id)sender
{
	id applicationDelegate = [[UIApplication sharedApplication] delegate];
	[applicationDelegate termsOfServiceAccepted];
}

Only show the screen once

With this code the ToS screen is displayed every time the application is started. That will quickly get annoying. So let’s add some code to only show it once by using a boolean stored in NSUserDefaults.

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if (![userDefaults boolForKey:TERMS_OF_USE_ACCEPTED]) {
	tosController = [[TermsOfServiceViewController alloc] init];
	[window addSubview:[tosController view]];
	navigationController.view.hidden = YES;
}

And in the termsOfServiceAccepted method set the boolean in NSUserDefaults.

- (void)termsOfServiceAccepted
{
	tosController.view.hidden = YES;
	navigationController.view.hidden = NO;

	// Store acceptance in UserDefaults
	NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
	[userDefaults setBool:YES forKey:TERMS_OF_USE_ACCEPTED];
}

Now the ToS screen is only shown until the user taps the accept button. Your customers will be happy, as will your lawyers.

written by Nick \\ tags: , ,

Apr 08

When you add a framework to your project in Xcode, make sure you use Path Type = “Relative to Current SDK”. There is no option for this when you add the framework. So after the framework has been added to your project, command-click on the framework and select Get Info.

Your paths should look something like this:
System/Library/Frameworks/AudioToolbox.framework

Why is this important?

When you start developing using both the iPhone simulator and an actual iPhone device you technically switch SDK based on your target. And it’s a real pain to have to adjust all the framework paths each time.

written by Nick

Apr 07

First you need to add your file to the Resources folder of your Xcode project. Then you can access the file like this (assuming the file is called MyFile.txt):

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"MyFile" ofType:@"txt"];
NSData *myData = [NSData dataWithContentsOfFile:filePath];
if (myData) {
	// do something useful
}

Here’s a complete example reading a help text file into a UIWebView.

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"HelpDoc" ofType:@"htm"];
NSData *htmlData = [NSData dataWithContentsOfFile:filePath];
if (htmlData) {
	[webView loadData:htmlData MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:[NSURL URLWithString:@"http://iphoneincubator.com"]];
}

If you want to read the file into a string, which you can then display in a UITextView, for example, then do this:

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"important" ofType:@"txt"];
if (filePath) {
	NSString *myText = [NSString stringWithContentsOfFile:filePath];
	if (myText) {
		textView.text= myText;
	}
}

written by Nick \\ tags: , , ,

Apr 04

Five good iPhone related blog posts from around the web this past week:

Five Factors Shifting the Future of Malware and Platform Security

RoughlyDrafted Magazine publishes great, in-depth articles. Next time you grumble about the iPhone code signing process, consider the alternative.

Exploring iPhone Audio Part 4

Pete continues his excellent iPhone SDK audio trail. Lots of source code. My favorite type of post.

Is it possible to create multiline UITableView text cells?

AppStoreDeveloper.com is a growing forum for SDK developers. Here’s one of the livelier threads from the past week.

iPhone Dev SDK – The source for iPhone and iPod Touch development!

That’s a promising title for a blog. I just discovered Chris’ blog this week. Definitely worth adding to your RSS reader.

Best of April Fool’s Day online

There were many iPhone related April Fools jokes this week. TUAW has a good roundup.

written by Nick

Apr 03

A UIWebView is great for displaying rich text; you just format your text as HTML. But how do you display images in a UIWebView?

Since the iPhone is almost always connected you could just use a regular image tag referencing an image on a server somewhere:

<img src="http://example.com/img/foo.png" />

But that is less than optimal. What you really want to do is reference an image on the iPhone. One way to do this is to embed the image in the HTML using the data: URI scheme. Here’s an example:

<img src="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP
C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA
AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J
REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq
ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0
vr4MkhoXe0rZigAAAABJRU5ErkJggg==" alt="Red dot" />

Here’s a great tool for converting any small image to the base64 encoding required by data:image:
www.abluestar.com/utilities/encode_base64/index.php

Adding images this way will allow you to create great looking, self-contained help files and about us pages for your iPhone applications.

Update: See this post for an alternate way to display images: UIWebView – Loading External Images and CSS

written by Nick \\ tags: , ,

Apr 02

In light of yesterday’s “announcements” and rumors about the 3G iPhone, it’s good to remind yourself that there will eventually be new iPhones with different properties and capabilities than the current generation.

Developing for the iPhone is great because it’s a single platform. If you have ever tried to adapt a J2ME application for dozens of different phones, you know how painful that is. But don’t take the “single platform” idea too far and assume things like screen size.

Always ask the device about it’s capabilities and dimensions. For example, [[UIScreen mainScreen] bounds] will give you the size of the screen your application can work with. Don’t hardcode 320 x 480 pixels. A good way to test your UI is to allow it to rotate between portrait and landscape mode. If the UI can handle that without breaking or looking distorted, it will probably adapt to other screen sizes as well.

Going back to the 3G example, how would you know if an iPhone is 3G connected to a 3G network? There is nothing specific to 3G in the current API. There is a kSCNetworkReachabilityFlagsIsWWAN flag in SCNetworkReachability which is defined as “EDGE, GPRS, or other cell connection”. That could include 3G. But since there is a significant speed difference between EDGE and 3G it would be nice if Apple added another flag specifically for 3G reachability.

Another possibility is the UIDevice class, and specifically it’s model property. Currently this contains “iPhone” or “iPod Touch”. An “iPhone 3G” model string would make it pretty clear that a phone is 3G capable. But that’s a pretty crude way of describing capabilities. And it puts the onus on each application to map device names to specific capabilities. When you think about all the different iPod models you realize that this will get out of hand pretty quickly.

What we really need is a new capabilities API or framework where an application can query the device for specific information such as screen size, RAM size, network capabilities, etc.

written by Nick \\ tags: , , ,

Apr 01

An interesting quantum mechanics effect makes it possible for some lucky owners of the current generation iPhone to connect to high-speed 3G networks today.

Hubert Hochsztapler, a researcher at the institute for nano-technology at The Royal Institute of Technology in Sweden, discovered back in 2004 that old GSM cellphones could be used as 3G phones using the quantum tunneling phenomenon.

Would it work on the iPhone?

The iPhone was not tested by Hubert Hochsztapler and his colleagues, but our own lab reports today confirm that most current iPhones are already 3G capable. No new hardware is required.

The iPhone contains an accelerometer which measures minute movements of the iPhone. This turns out to be a great benefit to achieving the 3G capability. But due to interference from the accelerometer when it’s inactive, you first need to open an application on the iPhone that makes use of the accelerometer. The Safari browser is an excellent choice, since it will also allow you to visibly enjoy the effects of the faster data connection provided by 3G.

First turn the iPhone from portrait mode to landscape mode, back and forth a couple of times to ensure that the accelerometer is engaged and working. You should see the display change between portrait and landscape mode. Now start downloading a very large web page and simultaneously begin shaking the iPhone lightly along its y-axis. Think of the iPhone as the yoke of an aircraft. You want to avoid pitching and rolling the iPhone as you’re shaking it.

If you hit the right shaking-frequency (41 Hz seems to be optimal), the electrons in the iPhone will reach their tunnel state and the radio transmitter will “tunnel-up” and connect to the AT&T 3G network in your area (if one is available).

Impact on Apple’s stock price?

A Gartner analyst recently reported that Apple has already placed an order for 10 million units of the new 3G iPhone from their manufacturers in Asia. But when current iPhone owners discover that their iPhone already is 3G capable, they will not upgrade as Steve Jobs has decreed they should. This will effectively turn Apple’s 10M order into one big iBrickload of phones, says April F. Olson, an analyst covering the AAPL stock for Hochs Securities.

It doesn’t work with all firmwares

This technical trick has been confirmed to work only on non-jailbroken 1.1.4 firmware phones (also known as the 4.1 release in the U.S.).

Please report your success with your “new” 3G iPhone in the comments below.

written by Nick \\ tags:

Mar 31

Beta 2 of the iPhone SDK was launched last week and as advertised it now includes Interface Builder. Unfortunately somebody forgot to tell the documentation department at Apple about this. There is no documentation about Interface Builder related to the iPhone to be found anywhere. Zip. Nada. Nothing.

Of course there’s the general Introduction to Interface Builder User Guide, but does not deal with any of the specifics for building an iPhone interface.

Online forums are filled with messages from bewildered iPhone developers. Some brave bloggers have posted tutorials, which in many cases feel like putting a square peg into a round hole just to get the darn thing working.

I’ve found one tutorial that stands out from the crowd and actually makes sense from a Model-View-Controller (MVC) perspective. Check out Scott’s Reason #2: Interface Builder is buggy and has no documentation on his curiously named “I Hate the iPhone SDK” blog.

written by Nick \\ tags:

Mar 27

If you’re using a UIWebView to display rich text from a string of HTML (as I described yesterday) you can even include HTML links to external URLs.

However when the external web page is displayed it is done using the same scale as your local HTML page. Unless the two pages are about equal in size, the visual transition is less than pleasing.

You can use the scalesPageToFit property of UIWebView to fix this. See line 13:

- (void)loadView
{
  // Create a custom view hierarchy.
  CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
  UIView *view = [[UIView alloc] initWithFrame:appFrame];
  view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
  self.view = view;
  [view release];

  CGRect webFrame = [[UIScreen mainScreen] applicationFrame];
  webView = [[UIWebView alloc] initWithFrame:webFrame];
  webView.backgroundColor = [UIColor whiteColor];
  webView.scalesPageToFit = YES;
  [self.view addSubview:webView];
}

But this causes another problem: your internal HTML page probably looks a lot smaller than you would like. To fix this we’ll use a trick that web app developers use to optimize web sites for the iPhone.

To the HTML code add a meta viewport tag:

<meta name="viewport" content="width=320"/>

The complete code looks like this:

NSString *html = @"<html><head><title>The Meaning of Life</title><meta name=\"viewport\" content=\"width=320\"/></head><body><p>...really is <b>42</b>!</p></body></html>";
[webView loadHTMLString:html baseURL:nil];

written by Nick \\ tags: , ,