By Thom Parkin

RubyMotion Workflow Customizations

By Thom Parkin


RubyMotion is a set of tools that simplifies the development of iOS applications, compiling source code to native iOS machine language. It shares its heritage with MacRuby, making it a familiar option for experienced Rubyists to develop applications for iPhone/iPod/iPad.
RubyMotion provides direct access to iOS Classes and Libraries, RubyGems and supports the mixing of Ruby and Objective-C style calling conventions.
The structure of an iOS application observes MVC (like Rails) and RubyMotion’s Command-Line workflow is driven by a Rakefile; just like Rails.

Your standard workflow in RubyMotion will probably include Bundler and RVM { As of this writing, RubyMotion requires a minimum of Ruby 1.9 }


But these similarities to Ruby on Rails are, in many cases, only superficial.

In this article I want to focus on the Rakefile that is used in RubyMotion applications. And I hope to provide some help in keeping your work a bit more organized (and DRY) once you have several RubyMotion applications in development.

The techniques and ideas I present here are my own – carry no particular warranty – and are presented as guidance. You are encouraged to take what is presented here and expand it or adjust it to suit your needs.

If you create something particularly interesting or unique, I hope you share it with the community (in a Gist or repository on Github) and comment to this post.

The RubyMotion Project Structure

To instantiate a new application (project) the command is simply motion create applicationName

This builds the structure of a RubyMotion application like this:


If you are familiar with iOS development (perhaps you have worked in Objective-C with XCode), the appdelegate.rb may be recognizable.

  • The resources directory is where all images, icons and other resources should be maintained.
  • The .gitignore has many sensible defaults already defined for you. Although you will still need to git init a repository for your project.
  • The spec directory is for the tests (you ARE writing tests for your Ruby, are you not?). RubyMotion uses Bacon (an RSpec clone). And a sample spec is created by default.This build system that generates these files is Open Source on Github at HipByte/RubyMotion.The part of this system that will be the focus of this article is the Rakefile.

The RubyMotion Rakefile is the “Heart and Soul” of your CLI workflow. Very much like Rails, most tasks you need are just a rake command away. You can create customized tasks by editing it and get a list of current tasks with a call to rake -T.

Here is the list of rake commands for RubyMotion 1.32

rake archive               # Create an .ipa archive
rake archive:distribution  # Create an .ipa archive for distribution (AppStore)
rake build                 # Build everything
rake build:device          # Build the device version
rake build:simulator       # Build the simulator version
rake clean                 # Clear build objects
rake config                # Show project config
rake ctags                 # Generate ctags
rake default               # Build the project, then run the simulator
rake device                # Deploy on the device
rake simulator             # Run the simulator
rake spec                  # Same as 'spec:simulator'
rake spec:device           # Run the test/spec suite on the device
rake spec:simulator        # Run the test/spec suite on the simulator
rake static                # Create a .a static library

Rake Holds Configuration Details

Unlike Rails, where you rarely need to modify the Rakefile unless you are developing customized commands, in RubyMotion much of the configuration details that are specific to your application will be in this file. In other words, each application in RubyMotion will have its own – unique – version of the Rakefile.

Most libraries and gems that you wish to require (due to the static compilation, RubyMotion cannot support ‘include’) will be referenced in the Rakefile. The specific icons used in your application and the Codesign credentials must be added to the Rakefile.

Also, any credentials for APIs you may be using are read from the Rakefile.

{You can always check on the current configuration with the commmand rake config (see above)}

The Dilema

I have always been quite hesitant to include the Rakefile in my Git repository; particularly on projects I may offer publicly. But since it is an essential part of the whole process it cannot simply be excluded.

How to obscure any ‘proprietary’ credentials while providing the necessary configuration details has been a point of much discussion in the RubyMotion community. One obvious solution (and a very popular one) is to define “environment variables” for those sensitive pieces of data.

Although that works well, I want more flexibility and prefer something less tightly coupled to any particular device (I work on multiple computers).

My Solution

In my RubyMotion workflow I have chosen to define the Rakefile as a symbolic link in every project. My Rakefile symlink points to a single Rakefile that lives in a parent directory. This is a very DRY approach to managing the Rakefile, all “proprietary” credentials, and any customization (as far as additional Rake Tasks). In order to provide the necessary flexibility, I have modified that base Rakefile to load from a app_properties.rb that lives in every application’s home directory.

Here is an example of a generic Rakefile. This assumes the Rakefile exists just one level up from any RubyMotion project. {This file has been anonymized for publication}

#-*- coding: utf-8 -*-

require 'motion/project'

# custom rake tasks can go here

desc "Open latest crash log"
task :log do
  app = Motion::Project::App.config
  exec "less '#{Dir[File.join(ENV['HOME'], "/Library/Logs/DiagnosticReports/#{}*")].last}'"

require './app_properties'  #this is the call to a file that exists in every project
props =
props.requires.each { |r| require r } if props.requires.size > 0

Motion::Project::App.setup do |app| =
  app.identifier = props.identifier
  app.delegate_class = props.delegate
  app.version = props.version.scan(/d+/).flatten.first
  app.short_version = props.version.scan(/d+/).first #required to be incremented for AppStore (
  app.icons = props.icons
  app.device_family = props.devices
  app.interface_orientations = props.orientations
  app.provisioning_profile = props.provisioning
  app.codesign_certificate = props.developer_certificate
  if props.testflight?
        require 'motion-testflight'
    app.testflight.sdk = 'vendor/TestFlight'
    app.testflight.api_token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    app.testflight.team_token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    app.testflight.distribution_lists = ['Developers', 'Testers']
  if props.pixate?
      require 'rubygems'
      require 'motion-pixate'
    app.pixate.user = 'USER ID'
    app.pixate.framework = 'vendor/PXEngine.framework'

And a sample of the app_properties.rb file that would be in the root of every RubyMotion project.

class AppProperties
  VERSION = '0.9'
  APP_DELEGATE = 'AppDelegate' #default
  COMPANY_NAME = 'com.websembly.'

  def name
     'App Name Here'

  def version

  def requires  #add libraries to listed in Rakefile as 'require'

  def frameworks

  def contributors
    ["Thom Parkin" => ""]

  def developer_certificate
    'iPhone Developer: Thom Parkin (1337THX1138)'

  def provisioning
    './provisioning' #symlink

  def testflight?

  def pixate?

  def delegate

  def icons
    icn = ["#{}.png", "#{}-72.png", "#{}@2x.png"]

  def devices
    [:iphone, :ipad]

  def orientations
    [:portrait, :landscape_left, :landscape_right] #:portrait_upside_down

  def identifier


You may notice that the provisioning profile is also a symlink.

And so, in each of my RubyMotion projects the Rakefile that is generated by the RubyMotion create command gets replaced by a personalized app_properties.rb file that contains the generic instructions plus those things unique to that application (like the application name).

The flexibiliy and value of this continues to grow as I expand my use of libraries and additional helpers in my RubyMotion workflow. For example, I recently started using Pixate in my RubyMotion projects. In order to add this capability to all my RubyMotion projects, I simply updated the master Rakefile and can include the necessary references in each app_properties.rb file where it applies.

As I said before, this is ONE WAY to accomplish this effect. It may not be the best way and I invite you to enhance it. If you do, please let me know.

Login or Create Account to Comment
Login Create Account
Get the most important and interesting stories in tech. Straight to your inbox, daily.