In the Fall of 2011, we had a client come to us because they wanted a way to produce iOS applications with minimal developer effort. Basically, they had a ton of content, and they wanted to be able to cleanly package it up in different iOS apps and get them in the App Store. They had an existing firm delivering apps, but they weren't pleased with the quality of the work or the ongoing cost to produce new apps.
After some discovery and planning conversations, we decided that we would build an Objective-C App Framework that would serve as the base of all their apps. It would be a fully-functional iOS application that's just waiting for content. We could then build a Compiler that would configure and seed the App Framework to become a branded and unique application for each package of content they want to sell.
Of course, we decided that Ruby was a great tool to solve the compilation problem. We knew that we needed to run distinct tasks in different queues. and resque solved that problem wonderfully. The configuration and seed process required that we grab source files from AWS S3 buckets, modify XML and JSON files, and insert some records in a SQLite database that lives on the iOS device. Ruby has great interfaces to interact with everything we needed there too (AWS::S3,, Nokogiri, ActiveSupport::JSON, sqlite3).
The last step in the process was the real kicker. We ultimately needed to be able to compile these seeded applications into IPAs that could be submitted to the App Store and uploaded to TestFlight for internal review. For this job, we used Wizard of Xcode (WOX), and it works great.
Essentially, you just have to set up some rake tasks that define what you need to do, and everything just works from there. Take a look at the Rakefile below.
# Rakefile include Rake::DSL require 'bundler' Bundler.require Wox::Tasks.create :info_plist => 'SeededApp/SeededApp-Info.plist', :sdk => 'iphoneos', :configuration => 'Release' do build :release, :developer_certificate => 'iPhone Distribution: Client Inc.' do ipa :app_store, :provisioning_profile => 'WildcardAppStoreProfile' ipa :adhoc, :provisioning_profile => 'WildcardAdHocProfile' do testflight :publish, :api_token => 'nphsZ6nVXMl0brDEsevLY0wRfU6iP0NLaQH3nqoh8jG', :team_token => 'Qfom2HnGGJnXrUVnOKAxKAmpNO3wdQ9panhtqcA', :distribution_lists => ['Client QA Group'], :notify => true end end end
That Rakefile defines a few different tasks for you, but the most important ones are rake ipa:app_store and rake testflight:publish.
- Running rake ipa:app_store will generate an IPA file using an App Store Release provisioning profile that's ready to be uploaded directly into iTunes Connect.
- Running rake testflight:publish will generate an IPA file using an Ad Hoc Release provisioning profile, and using the TestFlight API, upload the IPA and notify your testers that a new build is available.
Pretty slick. For our purposes, we wrote some more code on top of this to push the App Store ready IPA up to AWS S3 after compilation. So basically, the client hits an API endpoint to notify the compiler that a new bundle of content is available, and we automate the entire configuration, compilation, and distribution process using some background workers. In the end, the client is getting exactly what they wanted – a system that allows them to publish new applications with zero developer interaction.