Fastlane Fastfile

:  ~ 2 min read

I previously wrote that I can't wait to start using Fastlane full-time, but I never really got to it, since I lost about a day or so and didn't manage to get the provisioning and signing to work.

Since then quite a few updates were issued and things got easier, so I finally managed to make the switch. I will walk through the process in a few posts.

First things first, our release process is more or less release to Hockey with a debug build until a desired state has been reached, release again to Hockey with a release build and make sure everything is working properly, then release to the App Store.

desc "Deploy a new major version to the App Store"
lane :release do
  [..]
end
desc "Deploy a new version to Hockey with debug / release settings"
lane :hockey_debug / :hockey_release do
  [..]
end
[...] etc

Most of the code inside the lanes are the same, differences being the type of the release, the branch check, the slack output message and other minor things. So instead of duplicating code over and over, all lanes call the same build_app(type) method:

lane :release do
  build_app 'Release'
end
lane :hockey_debug / :hockey_release do
  build_app 'Debug' / 'Beta'
end
[...] etc

And the build_app(type) method looks like this:

def build_app(type)
  cert(
    development: type == 'Debug',
    username: dev_username,
    team_id: team_id
  )
  
  pem(
    development: type == 'Debug',
    generate_p12: true,
    app_identifier: app_identifier,
    username: dev_username,
    team_id: team_id,
    p12_password: "xxx",
    pem_name: "aps_#{type}",
    save_private_key: true
  )
  
  sigh_params = {
    app_identifier: app_identifier,
    username: dev_username,
    team_id: team_id,
    team_name: team_name,
    output_path: "./fastlane/profiles",
    filename: "#{type}.mobileprovision"
  }
  
  if type == 'Beta'
    sigh_params[:adhoc] = true
  elsif type == 'Debug'
    sigh_params[:development] = true
  end
  
  sigh sigh_params
  
  ipa_params = {
    workspace: "xxx.xcworkspace",
    configuration: "#{type}",
    scheme: "#{type}",
    # the auto-increment build number script is at the bottom.
    # Because archiving builds again, that would mean
    # the build number would be increased twice. We don't really need the archive anyway.
    archive: false,
    sdk: "iphoneos",
    clean: true
  }
  
  # Special case, because setting the signing to Automatic in Xcode
  # uses the Release profile, but we want the AdHoc profile.
  if type == 'Beta'
    ipa_params[:embed] = "./fastlane/profiles/adhoc.mobileprovision"
  end
  ipa ipa_params
  
  hockey_params = {
    api_token: "xxx",
    notify: (type == "Release") ? "0" : "1", # 0 = Do not notify, 1 = Notify
    status: (type == "Release") ? "1" : "2", # 1 = Download restricted, 2 = Downloadable
    release_type: "0", # Beta, Store creates a new app alltogether
    dsym: Actions.lane_context[Actions::SharedValues::DSYM_OUTPUT_PATH]
  }
  
  if type != 'Release'
    hockey_params[:tags] = 'alpha'
  end
  hockey hockey_params
end

Pretty straighforward and easy to set up: use cert to check and refresh the certificates, pem to check and refresh the push certificates (it lets you know if you have over 30 days left on them, or not), sigh to refresh and download the provisioning profiles, ipa to build the .ipa file (it uses the adhoc profile for the Beta builds) and, finally hockey to upload the build to Hockey, with the required settings.

The script to increment the build number, as promised - go to your Build Phases tab, click on Editor -> Add Build Phase -> Add Run Script Build Phase and paste this in there:

buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

Next post I will talk about adding major / minor / patch release types and editing the plist to auto-increase the version number.