While developing myDrumPad, I came across an interesting problem for my in-app purchase support. The app allows users to download additional packs of sounds (referred to as “sound packs” in the app) that they can use to tap out songs and rhythms. The sound packs themselves were a collection of CAF-encoded uncompressed PCM audio files, with a single configuration file describing the labels and arrangement of the sound files on the drum pad’s grid of buttons.
I wanted to be able to add additional sound packs without issuing a new release of the app, but since the information describing the sound packs is largely static, I didn’t want to have to worry about maintaining a dynamic server for the app to continue functioning. I wanted it to largely be “fire and forget”.
What I came up with is, I think, a best of both worlds. The app functions without needing me to maintain a server, but I can still dynamically add additional resources to the app instantly. Read on to find out more.
Every app needs an editor
Since I started my career as a web developer, I’m quite comfortable with Perl, CPAN and all the rest if the technologies that tend to come on the standard Linux LAMP stack. So I created an administrator interface on a password-protected server that let’s me or any of my sound maintainers upload sounds, configure and layout new drum pads, and all that information is stored in a PostgreSQL database.
The interface includes some fancy Ajax actions that lets a user drag-and-drop sound packs onto the categories they should be listed in, and shows the sound packs as a grid of buttons that can be dragged around to arrange and organize them. A final useful feature is that each sound pack can have its own publication status (draft, or published).
Amazon S3 to the rescue
However, this interface isn’t used during the operation of the app. To prevent my users from experiencing strange errors or even outages from the server, once a sound pack or category is published, it’s sound files and configuration files are uploaded to a private Amazon S3 bucket. The app, at start-up, checks the modification times of the configuration files, and if they’ve changed, it downloads the latest version and syncs those changes to a Core Data database. All the S3 interaction on iOS is handled by the ASIS3ObjectRequest class.
And this is what drives the entire application. When browsing for new sound packs, or reviewing the sound packs already downloaded, the labels pulled down from the server is what’s used.
In-App store purchase process
Not everything on my pack store is a paid resource. Some sound packs are distributed free of charge. But the ones that have an IAP AppStore ID results in the app querying Apple’s StoreKit API to fetch the localized price for the sound packs, which subsequently is stored in Core Data as well.
This process has a few moving parts to it, but since my server-side is essentially static files generate at publication time, and downloaded from a very reliable and secure server, I can rest easy in the knowledge that the different types of error conditions are greatly reduced.
After the configuration is synced from S3, the store is nothing more than a set of Core Data-driven UITableViewController interfaces.
Future revisions to this model
In another music app I’m building I’d like to do something very similar with downloadable packs of sounds, but I would like to allow users to share the creations they make and participate with each other. At the same time I still don’t want to introduce additional points of failure.
My expectations are that I’ll be able to have the app itself create and upload recordings that users make, as well as any config files representing their creations, to Amazon S3 resources. The apps themselves can traverse the directory hierarchy of S3 to browse and discover other user’s recordings, all without the need for a central server.
If any server is necessary, the amount of work it would have to do will be very minimal since the critical-path of uploading and managing resource files will be handled directly between the iOS client app and Amazon S3.
What are your thoughts on this technique? Do you have any suggestions for how I can streamline the process?