Lite To Paid iPhone Application Data Migrations With Custom URL Handlers

Stephen Lombardo and Zetetic are the creators of the encrypted iPhone data vault Strip.

Apple enforces a number of restrictions on applications in the App Store. Among the most painful is the lack of feature-limited trials. Applications are either completely free, or the customer must pay up front, sight unseen. The proliferation of “Lite” applications is a direct result of this shortcoming. Publishers will often create two application versions: the first is fully functional but costs money, the second is “Lite” and comes with limited features but zero price tag. The goal is for prospective customers to try the free version first and then decide to buy the paid full version separately if they like it.

Because free applications have greater exposure this approach is widely advocated as a means to increase visibility and grow sales. When building a game or other stateless application the approach makes complete sense. However, utility applications often maintain information entered by the device owner. Application authors are faced with a dilemma because the iPhone’s security sandbox prevents one application from reading another application’s files. Thus, when customers upgrade from the Lite application they are penalized by having to re-enter all data!

When we developed our data vault product, Strip, we felt this situation was unacceptable. We wanted to offer Strip Lite, free for people to try, limited to 10 entries. Upgrading customers should be able to import their data from the Lite version. No pain.

The Approach

Strip stores user data in an encrypted SQLite Database. Since we really wanted a way to copy the data file from Strip Lite to Strip we developed a fairly clever solution: use a registered URL handler as a means of communication between application versions. This is how it works:

  1. A customer downloads Strip Lite for free and enters some unique private data. All information is written to a database in the application’s document directory.
  2. When the 10 record limit is hit Strip Lite asks them to upgrade. An upgrade button launches to explain the process and allow the user to download the paid version of the product.
  3. Once Strip is purchased and installed, our customer will launch Strip Lite and click an “Export to Strip” button. Strip Lite reads the application database into an NSData object, Base64 encodes it and then Launches a “strip://” URL with the encoded file contents as a URL parameter.
  4. The full version of Strip is registered as a handler for “strip://” URLs. The OS launches Strip and passed the URL to the handleOpenURL method of the application delegate. It parses and decodes the data and writes the database to the desired location in the new applications Document folder.
  5. Our customer now has access to all the data the originally entered into Strip Lite!

Project Setup

This tutorial assumes that your project is already configured with two targets, one for your full version, and one for the Lite.

Start by creating a new InfoLite.plist file for your Lite version. We use 2 separate .plist files to ensure that the Full version is the only registered URL handler (we don’t want the Lite version responding to upgrade events itself!). It is easiest to just make a copy of the existing Info.plist file named InfoLite.plist.

Next, Open up the Build preferences for the Lite target. Change the Info.plist File property to read InfoLite.plist. This will ensure that the Lite target includes the proper file.

Now open the Info.plist (used by the Full Version) and register a custom URL handler. This is a straightforward process of adding elements as shown in the following screenshot.

Please note that the URL identifier and URL scheme must be unique for your application — see this stepwise overview of the process for reference.

Finally, the application must include code to perform Base64 encoding itself. This functionality is, unfortunately, not directly accessible in the framework SDK. There are a few options in Cocoa, including using OpenSSL’s libcrypto, but the easiest method is to use the encoding libraries from Google Toolbox for Mac which is conveniently distributed under the Open Source Apache License. Download GTMDefines.h, GTMBase64.h and GTMBase64.m, then add them to your project. The GTM code compiles perfectly on the iPhone and even includes web safe variants that are immediately suitable for use in URLs without percent encoding.

The Code

With the project setup complete the Paid version will respond to the custom URL launch! This will facilitate an export from the Lite version to be received by the Full version.

The Lite Version

The Lite application should be extended to add a button to trigger the export on an about, settings, or upgrade page.

The controller action code will read the data file, encode it and then format a URL with the protocol prefix / URL scheme configured in the previous step.

#import "GTMBase64.h" 
NSData *fileData = [NSData dataWithContentsOfFile:@"/path/to/LiteApplication/Documents/file"];
NSString *encodedString = [GTMBase64 stringByWebSafeEncodingData:fileData padded:YES];
NSString *urlString = [NSString stringWithFormat:@"myapp://localhost/importDatabase?%@", encodedString];
NSURL *openURL = [NSURL URLWithString:urlString];
[[UIApplication sharedApplication] openURL:openURL];

The Full Version

The final step is to make your application handle the Open URL event and reverse the encoding process.

Add a handleOpenURL method to the AppDelegate implementation as follows. This will receive the URL, sanity check it, and then parse the query string directly. The resulting binary data is written to the file in the full application’s data directory.

#import "GTMBase64.h" 
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    if([@"/importDatabase" isEqual:[url path]]) {
        NSString *query = [url query];
        NSString *importUrlData = [GTMBase64 webSafeDecodeString:query];

        // NOTE: In practice you will want to prompt the user to confirm before you overwrite their files!
        [importUrlData writeToFile:@"/path/to/FullApplication/Documents/file" atomically:YES];
        return YES;
    return NO;

End Game

We have transferred files of up to 100k this way, and the size of a URL string is theoretically only limited by available memory. That said, this approach is most suitable for applications with small to medium size data transfer requirements. Best of all though, it can be easily used for SQLite databases, XML files, text files, or even extended to handled compressed archives.

Strip has seen steady growth since it’s release as people upgrade from Strip Lite to the full version. Based on download reports and direct comments from customers we believe that much of this is directly attributable to the simple upgrade path. Until (and if at all) Apple begins to allow in-app purchases from within free applications this is a simple and painless way to migrate data between Lite and Paid application versions.

examsheets – – – – –

© 2008-2051 • Mobile Orchard and the Bar-Tree Logo are service marks. ContactAdvertise