i3Factory World

Your Iphone, iPad & Android Application Factory

Browsing Posts tagged Market

Icona Newsstand Icon

The iOS5 revolution

A lot of water has flowed under the bridge since our first part of this tutorial. We’re sorry for the delay, but at the time of writing we were aware of the new featured introduced with iOS5 but we were still under NDA and not authorized to disclose anything about the SDK. Finally we’re now able to provide our example magazine app with the double iOS4/iOS5 compatibility.

 

I will not spend my time explaining all the Newsstand features, all in all we’re creating a magazine app here and the Newsstand implementation details go beyond our original purposes. I have written a two parts tutorial in my personal blog that you can read here and here, and that covers all Newsstand aspects and the required (by Apple reviewers) subscriptions. In short, Newsstand is both a new way to present magazines in the iPad and iPhones, where the original icon is replaced by a cover of the magazine or newspaper and is placed under a special group dedicated to collect all Newsstand icons installed by the user. For the developer it is also a framework, called Newsstand Kit, that introduces a new methodology to organize, download and install the app content.

The example app

The screenshot shows the final appearance of the app. A set of nine magazines with their nine fruity cover. You can download a magazine, see the progress bar change while the operation is in progress and finally read it. The other screenshot shows the appearance in the Newsstand. The typical icon has been replaced by a magazine-like representation inside the Newsstand group. The same, if run on an iPad with iOS4 installed will show the classical icon instead.



The full app code is available on GitHub. Don’t consider it as a production code, so please don’t try to reuse as it is with your clients unless you have tested it in all possible corner cases. Anyway it can be considered as a valid starting point for real apps. Essentially the principles behind the code architecture have been depicted in Part I of this tutorial; if you haven’t read it yet I recommend to jump to that article before entering in this one, at least to understand the key components of such an app. The driving aim is to keep the issues management (controller, don’t confuse it with “view controller”) separated as much as possible from the UI concerns. This means that in theory the whole code behind the Store Manager and Issue Models part can be reused even in a Mac OSX app, as they relationship with UI stuff is minimum.

I have setup this app using the basic single window Xcode template and then added the two main components in the application delegate startup method:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// here we create the “Store” instance
_store = [[Store alloc] init];
[_store startup];self.shelf = [[[ShelfViewController alloc] initWithNibName:nil bundle:nil] autorelease];
_shelf.store=_store;self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.rootViewController = _shelf;
[self.window makeKeyAndVisible];
return YES;
}

The two components are:

  • the Store class, which represents the Store Manager block in the app architecture; this Class is a subclass of NSObject and is not linked to the user interface.
  • the ShelfViewController represents the UI of the application. It is linked to the store using a specific property. Note that the controller will not access the store exposed properties, but will get the needed information via a simple API. We could have used a delegate pattern instead, but as both blocks are essentially custom blocks in a custom app, there is not much need to define a protocol for their interaction. We can say that the controller part has been split in two parts, one for the UI, the shelf, and one for the back-end, the Store. Their link is such that the Shelf depends on the Store (strict link), not viceversa. Any Store to Shelf communication is done using lazy methods, based on notifications.

The app has then been integrated with the new Newsstand requirements in the info plist. Again have a look at Apple docs or my tutorial for a detailed guide.

Models and Controllers

We have one model in this app, it is the Issue model which represents a single magazine issue in the store or in the user library. There is also one controller, which is the Store. As I said this controller is not a UI component but the app back-end is self sufficient with these two components. In theory we can retrieve the store status and download magazines even without any user interface. This is a basic concept in magazine apps, where many events happen in the background are not related to direct user interaction: this means that the app should be capable to perform several tasks even if the user interface has not been loaded at all.

The role of the Issue class is to represent all relevant magazine properties, that is a unique identifier, a title, a release date, a link to the cover image, obviously the link (URL) to the content (which can be a pdf file, an epub file or a zip file for complex packages). In particular the unique identifier is a piece of data that must be maintained along the full life of the issue: it is the only way to uniquely identify a particular issue, independently of localization issues (e.g. the title can change in different countries, but not the unique ID). Besides it is the link to the Newsstand way to identify issues (the NKIssue‘s name field) and it can be also used to link the product with the App Store if we’re going to implement In App Purchases.

Other than this role, the Issue class will have a central role in the downloading of a magazine. Essentially the Store class will schedule a download but it will be monitored (progress) and then finished (effective magazine installation) by the Issue class.

Finally this class has limited capabilities to represent a magazine already downloaded and available in the user library. For this we provide the simple isIssueAvailableForRead that will be used by the user interface to know which action is possible with an issue (read or download) and eventually display the contents.

The Store class is the app controller. It is initialized at the very beginning of the app and its instance is never released. Besides immediately after initialization this class will fetch the store contents from the publisher server. In the example we decided to implement the store contents as a simple property list, and we instruct the store to retrieve this property list, decode it and create the Issue objects, and finally download their cover images. All this is done asynchronously using the Grand Central Dispatch and at the end a notification will be sent to inform all interested objects (in particular the view controller) that the store contents are ready and the UI can be safely displayed. Note that the store status is represented by a property status. We have overridden its setter method to post a notification that informs any interested observer of the new state. For simplicity we decided to limit the possible statuses to “not initialized”, “downloading”, “ready” and “error”. A more complex app can introduce extra states if needed. Finally as a fallback in case of missing connection (the user must be able to access his/her content even if not connected to the Internet) we reload a locally saved copy of the store.

The central piece of the code is in the downloadStoreIssues method of the class, that we report below:

-(void)downloadStoreIssues {
self.status=StoreStatusDownloading;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0), ^{
NSArray *_list = [[NSArray alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://www.viggiosoft.com/media/data/iosblog/magazine/store.plist"]];
if(!_list) {
// let’s try to retrieve it locally
_list = [[NSArray alloc] initWithContentsOfURL:[self fileURLOfCachedStoreFile]];
}
if(_list) {
// now creating all issues and storing in the storeIssues array
[_list enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSDictionary *issueDictionary = (NSDictionary *)obj;
Issue *anIssue = [[Issue alloc] init];
anIssue.issueID=[issueDictionary objectForKey:@"ID"];
anIssue.title=[issueDictionary objectForKey:@"Title"];
anIssue.releaseDate=[issueDictionary objectForKey:@"Release date"];
anIssue.coverURL=[issueDictionary objectForKey:@"Cover URL"];
anIssue.downloadURL=[issueDictionary objectForKey:@"Download URL"];
anIssue.free=[(NSNumber *)[issueDictionary objectForKey:@"Free"] boolValue];
[anIssue addInNewsstand];
[storeIssues addObject:anIssue];
[anIssue release];
// dispatch cover loading
if(![anIssue coverImage]) {
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:anIssue.coverURL]];
if(imgData) {
[imgData writeToURL:[anIssue.contentURL URLByAppendingPathComponent:@"cover.png"] atomically:YES];
}
});
}
}];
// let’s save the file locally
[_list writeToURL:[self fileURLOfCachedStoreFile] atomically:YES];
[_list release];
self.status=StoreStatusReady;
} else {
ELog(@”Store download failed.”);
storeIssues = nil;
self.status=StoreStatusError;
}
});
}

Note that in the code above for simplicity I have queued the cover downloading immediately after the property list download. Probably this is not the best way to do this, as we are adding extra networking steps before presenting the app status, with possible delays if network conditions are not good. We can do this in an example where we know that the number of issues is limited, probably in a real app it makes more sense to do this in a background job and then notify the UI to update its status every time a new cover is ready to be displayed.

The view controller

The user interface will wake up immediately, and will change its appearance based on the notifications coming from the store. When the notification center will deliver the store “I’m ready” message to the UI, this one will load all UI issue representations (the CoverView class in the code, a basic view with really minimum application logic) and show the shelf to the user.

At this point the app terminated its back-end processing and is waiting for user commands. Here we have two possibilities:

  • A magazine has been downloaded, the user will see a “READ” button, clicking on it he will be able to read it. In our example all our content is made of pdf files, we decided to use the Quick Look framework in iOS, it is enough for our purposes.
  • A magazine has not been downloaded yet, the user will see a “DOWNLOAD” button, clicking on it the download will start and we’ll show a progress bar. At the end we need to replace the button label and hide the progress. We’ll see this part in more detail.

The view controller is dependent on the store. In order to get the issues information (number of issues, detail of each issue) it will not access directly to the store properties but will use a very simple API, made of three methods:

/* “numberOfIssues” is used to retrieve the number of issues in the store */
-(NSInteger)numberOfStoreIssues;/* “issueAtIndex:” retrieves the issue at the given index */
-(Issue *)issueAtIndex:(NSInteger)index;/* “issueWithID:” retrieves the issue with the given ID */
-(Issue *)issueWithID:(NSString *)issueID;

Based on this information, and on the Issue properties, it will create the Issue view representation (CoverView) and place it on the screen.

Downloading a magazine

In a magazine app there are three critical sections: retrieve and display of the store contents, download the contents and finally read them (a good PDF or epub reader is mandatory in an app like that; it’s not the purpose of this tutorial, aimed to explain the architecture and the techniques needed to make such an app, but it is a relevant part in the user experience).

My approach in the magazine download is that the user must be completely free to do any action and such actions shouldn’t interfere with the result of the download. Now many apps take a shortcut: they put a spinner in the center of the screen, then block any user interaction with the UI objects behind the spinner and ask the user to wait. It’s easy to do this, but it is not the better user experience. While waiting the user can read another issue, can navigate inside the store or decide to switch temporarily to another application or finally can temporarily lose the network. Newsstand Kit provides a system level methodology that simplifies (in some cases) the developer life but at the same time removes any excuse on not doing a good job in term of user experience.

As soon as the user triggers a new download, the view controller will send its download request to the store class. In the code below you can see the scheduleDownloadOfIssue: code. This method will prepare the network request and will send it in the background. Note how we split the app behavior based on the operating system version we’re on. If it is iOS5 then we must use the Newsstand approach – where the downloading will be managed by the system in a Newsstand queue – , if we are in iOS4 we’ll follow a classic methodology based on NSOperation: in this case I missed for simplicity to get the content length of the content to be downloaded, so in the iOS4 case the progress bar will not be displayed. This information instead if provided “for free” by Newsstand.

-(void)scheduleDownloadOfIssue:(Issue *)issueToDownload {
NSString *downloadURL = [issueToDownload downloadURL];
NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadURL]];
if(isOS5()) {
// iOS5 : use Newsstand
NKIssue *nkIssue = [issueToDownload newsstandIssue];
NKAssetDownload *assetDownload = [nkIssue addAssetWithRequest:downloadRequest];
[assetDownload downloadWithDelegate:issueToDownload];
} else {
// iOS4 : use NSOperation
NSURLConnection *conn = [NSURLConnection connectionWithRequest:downloadRequest delegate:issueToDownload];
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(startDownload:) object:conn];
if(!downloadQueue) {
downloadQueue = [[NSOperationQueue alloc] init];
downloadQueue.maxConcurrentOperationCount=1;
}
[downloadQueue addOperation:op];
[downloadQueue setSuspended:NO];
}
}// iOS4 only
-(void)startDownload:(id)obj {
NSURLConnection *conn = (NSURLConnection *)obj;
[conn start];
}

In the two cases I’d like to emphasize the fact that the Store initiates the download operation but then it will delegate any further processing to the interested part, the is the Issue to be downloaded. So it will be the Issue class that will monitor the download and then will finalize it.

The Issue class will behave as delegate of the download operation triggered by the Store class. The delegate protocol changes if you’re using Newsstand or not. In the former case you will need to be compliant with the NSURLConnectionDownloadDelegate protocol while in the latter the protocol to be respected will be the un-documented (or: documented in the header files only!) NSURLConnectionDataDelegate which is a “spin-off” of the classic NSURLConnectionDelegate. The difference between the two protocols in that one will write in the file system, the other in memory. Again don’t use the “data” approach for production purposes, here we’re loading the whole content in memory and then saving on disk when the content has been completely downloaded: really not the best approach if your content is hundred of megabytes, your app will certainly crash.

In order to visually track the progress and then update the user interface, we decided, being coherent of our principles, to keep the application store controller independent on any UI choice. To do this we make use of KVO and Notifications. Essentially when the view controller starts a download, it will set itself and the magazine view as notification observers of the download result, in order to update its status as soon the download terminates (with success or with error):

-(void)downloadIssue:(Issue *)issue updateCover:(CoverView *)cover {
cover.progress.alpha=1.0;
cover.button.alpha=0.0;
[issue addObserver:cover forKeyPath:@"downloadProgress" options:NSKeyValueObservingOptionNew context:NULL];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(issueDidEndDownload:) name:ISSUE_END_OF_DOWNLOAD_NOTIFICATION object:issue];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(issueDidFailDownload:) name:ISSUE_FAILED_DOWNLOAD_NOTIFICATION object:issue];
[[NSNotificationCenter defaultCenter] addObserver:cover selector:@selector(issueDidEndDownload:) name:ISSUE_END_OF_DOWNLOAD_NOTIFICATION object:issue];
[[NSNotificationCenter defaultCenter] addObserver:cover selector:@selector(issueDidFailDownload:) name:ISSUE_FAILED_DOWNLOAD_NOTIFICATION object:issue];
[_store scheduleDownloadOfIssue:issue];
}

Both the cover view and the view controller will need to unregister from the notification center as soon as the download operation terminates. Besides to allow the cover view to keep track of the progress status, as the download starts it will be registered as a KVO observer of the downloadProgress property of the Issue. This means that for each change of this property, that will occur during the downloading phase, the cover view will be informed of the change to update the progress bar (so we have here a separation again of the back-end property, the download progress, from the UI, the UIProgressBar). The cover view will unregister itself as soon as download terminates.

When the download terminates, the Issue instance will copy the downloaded content to the final destination. In the Newsstand framework this destination is specified by the system, in iOS4 will copy it in the Caches directory to be compliant with iCloud requirements (yes, iOS4 doesn’t work with iCloud but our app is the same for both generations of the OS, so we must be good citizens in any case).

In the Newsstand case we’ll also need to update the cover image for the Newsstand icon. We’ll do it with a simple command inside the code that manages the download termination (at the end we also send the end of download notification we mentioned previously):

-(void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL {
// copy the file to the destination directory
NSURL *finalURL = [[self contentURL] URLByAppendingPathComponent:@”magazine.pdf”];
ELog(@”Copying item from %@ to %@”,destinationURL,finalURL);
[[NSFileManager defaultManager] copyItemAtURL:destinationURL toURL:finalURL error:NULL];
[[NSFileManager defaultManager] removeItemAtURL:destinationURL error:NULL];
// update Newsstand icon
[[UIApplication sharedApplication] setNewsstandIconImage:[self coverImage]];
// post notification
[self sendEndOfDownloadNotification];
}

Conclusions

This is the conclusion of this tutorial. We decided after a long interval to make an effort to propose a complete app valid for both iOS4 and iOS5 environments. In the code you will find more interesting stuff, e.g. a “hook” to the Store Kit: this is a typical issue not considered by developers when they make applications that sell magazines. In such case storing the issue price in the publisher server is not of help as we must retrieve the pricing information from the only relevant source, that is the App Store. To do this our app must – asynchronously – query the iTunes store for the prices of all the publications and then display them once retrieved. I’m not adding this extra step in the code, just the hook as placeholder for future extensions, but of course if required by our readers I can extend this tutorial further. I would appreciate any suggestion and any contribution in the GitHub hosted code, I would like to see the example code provided with this tutorial as a good skeleton for new apps. If you didn’t enjoy this article, at least you can enjoy the literature classics (and a Django manual…) that I used to create my PDF files.

Carlo Vigiani

Domanda di tablet del primo quarter 2011Leggiamo il rapporto di ChangeWave Research e sfogliamo il sito InvestorPlace (http://www.investorplace.com/25527/explosion-in-corporate-tablet-demand) che ci relaziona sui risultati di un nuovo sondaggio condotto lo scorso mese in materia di utilizzo aziendale di dispositivi tablet, come iPad di Apple.

Con le offerte di nuovi tablet come l’ardesia HP 500 e il Dell Streak, la ricerca rileva che le imprese ancora preferiscono l’ iPad.

In termini di uso corrente, il 7% degli intervistati aziendali  dicono che la loro azienda fornisce agli impiegati dispositivi Tablet.

iPad di Apple (82%) resta di gran lunga il Tablet più popolare per fini commerciali. HP (Slate, 11%) e Dell (Streak, 7%) mostrano un interesse tra gli utenti aziendali – ma entrambi rimangono molto indietro la quota preponderante di Apple sul mercato.
L’uso del tablet in azienda dovrebbe aumentare a picco, si prevede un utiulizzo di tablet nel primo trimestre del 2011co una penetrazione del 14%, il doppio del numero attuale. Tali società prevedono di iniziare ad utilizzare tablet all’inizio del prossimo anno e hanno in programma di adottare per il 78% il dispositivo tablet iPad di Apple.

Grafico a barre
Grafico a barre

Secondo un report pubblicato da Gartner ( consultabile sul sito Gartner) , i cellulari venduti nel corso del 2009 sono stati 1.2 miliardi, con una leggera flessione rispetto a quello dell’intero 2008 (-0.9%).
I dati dell’ ultimo trimestre del 2009 (340 milioni di dispositivi venduti) invece segnano una crescita dell’ 8.3% rispetto allo stesso periodo dell’anno precedente.

I dati sui produttori di cellulari ci mostrano che a guidare il mercato rimane Nokia, con il 36.4% sul totale dei dispositivi venduti, seguita da Samsung al 19.5%

I dati sulle vendite di apparati non si distaccano dai numeri che prendono in considerazione i Sistemi Operativi , e infatti a guidare il mercato dei sistemi troviamo ancora Symbian (Divenuto Open Source) che e’ istallato sui telefoni Nokia. Al secondo posto abbiamo Blackberry (RIM) al 19.9% e al terzo iPhone OS con il 14,4%

E’ necessario notare che i dati sul sistema operativo prendono in considerazione il solo mercato dei telefoni cellulari, e non tiene conto del fatto che il sistema oprativo di Apple viene istallato anche sul’ipod touch.

iPhone 3GS 880 mila vendite nel 2009

iPhone 3GS 880 mila vendite nel 2009

Gartner Group, una delle principali societa’ di consulenza strategica per l’Information Technology , in un suo report rileva che gli iPhone venduti in Italia nel corso del 2009 sono stati 883.000 con un boom di vendite durante il periodo natalizio.
Una crescita del 226% rispetto al 2008 che porta Apple al 5° posto nella classifica dei produttore di telefoni in Italia, portando il nostro paese al 3° posto dopo Francia e Gran Bretagna.

L’incremento dellle vendite, secondo i dati trimestrali, è avvenuto dopo il lancio delle offerte dell’operatore cellulare Tre (H3G) per l’iPhone 3GS.

Un successo che dovra’ essere finalmente preso in considerazione dalle aziende italiane che possono contare su milioni di persone.