Hi this is Marin - the author of Touch Code Magazine, I hope you are enjoying my tutorials and articles. Also if you need a bright iPhone developer overseas contact me - I do contract work. Here's my LinkedIn profile
Update your iPhone app with new content – Part 2

Introduction

A couple of months ago I published a tutorial how to update an iPhone application with some new content, which is served by server in Internet. I’m very happy lot of people found it helpful, left comments and there was generally a productive discussion. If you didn’t see it, please head to that article and read it as the present post will be extending on what I discussed in first part – Update your iPhone app with new content – Part 1

What’s in the Part 2 of the tutorial

In general Ray Wenderlich inspired me to build on previous tutorials (with his excellent Cocos2D tutorials) and since few people asked me quite similar questions regarding the way they want to extend my tutorial within their own iPhone apps I decided to add those features directly in Part2. So once again, if ¬†you didn’t check out Part 1 – do it now before starting with Part 2 Update your iPhone app with new content – Part 1

How to know which files were contained in the update?

My example in Part 1 was quite simple – all images were copied into the Documents folder, so in the end they were mixed – originals and the ones that came with an update. Let’s see how to let the app know which files came with an update. Basically I want instead only the pics to put also metadata inside the update zip file. The metadata I want will be a list of the filenames and a message, which gives a bit more information about the current update. This metadata I’ll put in a .plist file since it’s really easy to read its contents in a fashionable way.

So, next to the actual images in the zip file I’m including also a file contents.plist :

<plist version="1.0">
<dict>
	<key>message</key>
	<string>With this update we provide you 4 new high quality images from www.kunstdrom.com!</string>
	<key>contents</key>
	<array>
		<string>2kokoroshin_mid.png</string>
		<string>5princess_mid.png</string>
		<string>8nonmixi_mid.png</string>
		<string>13nwaw_mid.png</string>
	</array>
</dict>
</plist>

I have a string called “message” which is the accompanying message which will show in my app after the new content is downloaded. In the array “contents” I just include a list of file names – for more elaborate cases here will be the spot for you to include all kind of other meta information about the files – licensing, credits, anything you want – for this tutorial I’ll have only the filenames.

The next step is actually very easy – once the zip file is downloaded and unarchived, look for the contents.plist file and read the data needed.

I’m gonna load contents.plist and show the user the names of the files newly downloaded (inside -(void)updateDownload ):

	//load contents.plist
	NSString* contentsPath = [NSString stringWithFormat:@"%@/contents.plist", self.documentsDir];
	NSDictionary* info = [NSDictionary dictionaryWithContentsOfFile: contentsPath];
 
	// load the filenames in a string
	int cnt = 0;
	NSMutableString* files = [NSMutableString string];
	for (NSString* fileName in (NSArray*)[info objectForKey:@"contents"]) {
		[files appendFormat:@"%i. %@\n", ++cnt, fileName];
	}
 
	// show the file list to the user
	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Message"
	message:[NSString stringWithFormat:@"%@\n\n%@", [info objectForKey:@"message"],files]
	delegate:self cancelButtonTitle:@"Close" otherButtonTitles: nil];
 
	[alert show];
	[alert release];

So if you would like to do any further integration of the freshly downloaded files – just go ahead.

Implementing a download progress bar

In the first part of the tutorial while the update is downloading the user see an Activity spinner; that’s good because the app effectively lets the user know that there’s work being done in the background and it’s good when that’s just few seconds (the update file in the first part is only 20KB or so), but when you are downloading bigger update it might be quite annoying for the user. So I’m implementing as well a download progress bar which will better show the user how the download is going and an idea how much is left to wait.

First of all in order to use means to track the download progress I’ll need to use better the NSURLConnection class. I’ll set my ViewController as a delegate to NSURLConnection and that way I’ll handle all the messages which are being sent when there’s a header response from the remote server, when there’s data coming back, etc. Now for some reason the NSURLConnection delegate messages are not wrapped up in a protocol (weird indeed), but here is a list of most of the message the delegate could receive, have a look and familiarize yourselves while we are going to use those next:

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrit

Those are very interesting and we are going to use some of those and I’ll mention what they do in greater detail. Let’s setup a progress bar which updates while the file is being downloaded.

Let’s change the -(void)updateFromInternet method, here’s how to start a NSURLConnection (for the full code look inside the full project):

	responseData = [[NSMutableData alloc] init];
 
	NSURLRequest* updateRequest = [NSURLRequest requestWithURL: [NSURL URLWithString:updateURL]];
	NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:updateRequest delegate:self];
	[connection start];

I’m basically initializing my mutable data instance and then creating a request and passing it to the connection instance. Note that the connection’s delegate is my class. Now let’s handle some messages from the connection instance:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [responseData setLength:0];
    filesize = [[NSNumber numberWithLong: [response expectedContentLength] ] retain];
}

didReceiveResponse is called when the headers of the response are received from the web server – in most cases in those headers there’s also the “Content-length” (accessible via [response expectedContentLength]) which tells the client how long is the response in bytes – I’m gonna use that and I’ll save in “filesize” how big is the file to download. Now I’ll gather the data as it comes and add it up in my responseData instance – since I have already the total length I can also update my progress bar – easy!

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
	[responseData appendData:data];
	NSNumber* curLength = [NSNumber numberWithLong:[responseData length] ];
	float progress = [curLength floatValue] / [filesize floatValue] ;
	progressView.progress = progress;
}

The post was originally published on the following URL: http://www.touch-code-magazine.com/update-your-iphone-app-with-new-content-part-2/

 

  ·

 

Next page of "Update your iPhone app with new content – Part 2"


Marin Todorov

is an independent iOS developer and publisher. He's got more than 18 years of experience in a dozen of languages and platforms. This is his writing project.
» Contact    » Add Marin on Google+

  1. Mark on Monday 5, 2010

    You simply rock

  2. DAVID on Monday 5, 2010

    you are an absolute legend. This has allowed me to complete my project which I have been looking for a way around this problem on for months!

    Thank you!

  3. Marin on Monday 5, 2010

    :) ) thanks David, glad I helped

  4. juan on Monday 5, 2010

    hi….

    i wonder if its posible to make a magazine reader on this way….. through the in app purchase…..

    anyone knows about it?? anyone knows how to do it? (the magazine downloader and reader )

  5. Joe Morgan on Monday 5, 2010

    Really nice tutorials Marin.

    I haven’t dug very deep into your app yet (Will do today though).

    It looks as though the download link is hard wired to a url specific address. I want to (try to) expand your app by getting it to read a custom php script when opened. This way it could inform you that new data is available for download.

    Somehow I’ll have to send info of zips already downloaded (maybe from a basic IOS DB or log file) to PHP script which will then compare with zip packages on server.

    Should be fun, don’t hold your breath though :)

  6. Marin on Monday 5, 2010

    Hey Joe,

    yes what you describe is what an app would normally do – read the output of a server script (try JSON or just PLIST), then try to download files and update.
    One hint: if your app always updates downloads ordered updates do this – 1) when you request the JSON from the server pass as a param the date/time of the last successful update of the app 2) the server script then should take this date and build JSON output with only the updates you created after this date 3) the app downloads them and saves on the iPhone the current date/time

    hope that helps a bit, Marin

  7. [...] a Part 1 of a 2 parts tutorial, if you are returning visitor you should definitely check out Part 2. If you’re a newcomer have a look at this one and the attached demo application and then head [...]

  8. Tony on Monday 5, 2010

    Marin
    This is great. I was wondering if you could write something about how you prevented people from taking your app and buying an addin then placing it on github or something similar to prevent revenue from others buying it. You mentioned this problem on your site or blogs somewhere!
    -Tony