sviluppiamo comunicazione con weLaika Advertising

Fastlane + Ionic = <3

Tags: mobile, build, android, ios, fastlane
Matteo Piotto -
Matteopiotto

Here at weLaika we loved Capistrano - and we still love it, because it’s easy and complete. When we started to develop and deploy Rails applications, we appreciated its help to build and deploy complex applications.

When we began to work in WordPress ecosystem, we didn’t find any “Capistrano” tool, so we developed it Wordmove.

But is there a “Capistrano” for mobile applications? Is there a tool that can help us to deploy mobile application to stores? Yes, and it’s called fastlane.

Fastlane

Fastlane is a set of Ruby gems that help to simplify and automate the app deployment and release process within a single streamlined workflow¹: by creating a custom list of sequential build tasks called lanes and using the tools provided, called actions, you are able to deploy to App Store / Play Store with a single command line.

XKCD

The result is that you can do more frequent, and smaller, releases that can be deployed by anyone in your team, using a simple configuration.

Requirements

First, to get fastlane up and running, we need:

  • OSX / macOS Sierra
  • Ruby 2.0 or newer
  • Xcode (for iOS builds)
  • Android SDK (for Android builds)
  • Paid Apple Developer Account (for iOS builds)
  • Paid Google Developer Account (for Android builds)

Since fastlane is a collection of Ruby scripts, you must have the right version of Ruby installed (2.0.0). OS X 10.9 (Mavericks) and later come with Ruby 2.0. Check this out with this command:

1
$ ruby -v

To check whether the Xcode Command Line Tools (CLT) are installed, type:

1
$ xcode-select --install

If the Xcode CLTs are already installed, you will get this error:

1
xcode-select: error: command line tools are already installed, use "Software Update" to install updates

If not, Terminal will go ahead and install the Xcode CLTs for you.

To build an APK you’ll need to have on your development machine the Android SDK. If you don’t have it, you can install it using homebrew

1
brew install android-sdk

Next, run the “Android SDK Manager

1
android

And install at least the Android SDK tools, Android SDK platform-tools, Android SDK Build tools.

Getting started

We will use the Ionic v2 tutorial app as sample app; if you don’t know how to use Ionic read the Ionic installation tutorial and come back!

1
2
3
$ ionic start MyFastlaneDemo tutorial --v2
$ cd MyFastlaneDemo
$ ionic state restore

Setup

To install fastlane globally run

1
$ sudo gem install fastlane --verbose

Then run this command inside the root folder of your Ionic app

1
$ fastlane init

Fastlane will ask for your Apple ID and other information, and then it generates a fastlane configuration based on the information you provided.

When fastlane asks

1
Couldn't automatically detect the project file, please provide a path:

that’s because fastlane tries to find the Xcode project in the root folder - but in a ionic project it’s inside the platforms/ios/ folder, so in this example it will be platforms/ios/MyFastlaneDemo.xcodeproj (replace MyFastlaneDemo with the name of the project if you changed it, of course). Fastlane, after the login with your Apple ID, will try also to create the app on iTunes Connect for you.

If you need more info on setting up fastlane, there is a good quick-start section in fastlane documentation.

The configuration file, fastlane/Appfile, will contains all the essential information and fastlane/Fastlane will contains lanes and actions that are needed to release your app.

The Fastlane file will looks like

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
default_platform :ios

platform :ios do
  desc "Submit a new Beta Build to Apple TestFlight"
  desc "This will also make sure the profile is up to date"
  lane :beta do
    # match(type: "appstore") # more information: https://codesigning.guide
    gym # Build your app - more options available
  end

  desc "Deploy a new version to the App Store"
  lane :release do
    # match(type: "appstore")
    # snapshot
    gym # Build your app - more options available
    deliver(force: true)
  end
  # You can define as many lanes as you want
end

iOS build

Fastlane has been developed for iOS projects and it contains everything you need to build and deploy iOS apps.

We are in a team and therefore we need to easily sync our certificates and profiles across us: thanks to fastlane Match we can use a GIT repo. Run

1
$ match init

and follow the usage instruction in Match documentation.

The build process for an iOS app contains several steps: sync of our certificates and profiles, build of the app using Ionic, and packing everything.

Replace the platform iOS section with the following lines:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
platform :ios do
  desc "Compile a new build for for appstore"
  lane :release do
    app_name_sanitized = 'MyFastlaneDemo'
    ios_project_path = "platforms/ios/#{app_name_sanitized}.xcodeproj"
    # Compile the ionic app
    sh("ionic build ios --release")
    # Get certificate
    cert
    # Get provisioning profile
    match(type: "appstore", app_identifier: app_identifier, readonly: true)
    sigh(
      force: false
    )
    # Recreate schemes to ensure a smooth transition from cordova to gym
    recreate_schemes(
      project: ios_project_path
    )
    # Archive app into ipa
    gym(
      scheme: app_name_sanitized,
      project: ios_project_path,
      export_method: 'app-store'
    )
  end
end

You can create another lane to build, for example, the ad-hoc release: you just need to set correctly some variables.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[...]
# Get certificate
cert
# Get provisioning profile
match(type: "adhoc", app_identifier: app_identifier, readonly: true)
sigh(
  adhoc: true,
  force: false
)
# Recreate schemes to ensure a smooth transition from cordova to gym
recreate_schemes(
  project: ios_project_path
)
# Archive app into ipa
gym(
  scheme: app_name_sanitized,
  project: ios_project_path,
  export_method: 'ad-hoc'
)

Android lanes

Thanks to AppFoundry you can add some actions to build Android apps correctly: copy sign_apk.rb and zipalign.rb from their Github repo to your fastlane/actions folder. You will get

1
2
$ ls fastlane/actions/
sign_apk.rb              zipalign.rb

Add the following lines to your .gitignore file:

1
2
3
# Fastlane
fastlane/.env
fastlane/release-cred/*.keystore

Create a .env file inside the fastlane folder and add there the KEY_PASS and STORE_PASS variables, that contain the keystore password and the store password. For example

1
2
KEY_PASS = "qwertyuiop1234567890"
STORE_PASS = "qwertyuiop1234567890"

Create the folder release-cred and there you must add the Android keystore file (if you don’t have one, you can create it via command-line.

Now we have all the actions we need to automatize the build process for Android.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
platform :android do
  desc "Compile a new build for Android"
  lane :release do |options|
    app_android_key = 'MyFastlaneDemo'
    ssh("ionic build android --release")
    sign_apk(
      apk_path: "platforms/android/build/outputs/apk/android-release-unsigned.apk",
      signed_apk_path: "platforms/android/build/outputs/apk/android-release-signed.apk",
      keystore_path: "fastlane/release-cred/android.keystore",
      alias: app_android_key,
    )
    zipalign(apk_path: "#{lane_context[SharedValues::SIGNED_APK_PATH]}")
  end
end

Let’s build'em

You can now run fastlane using

1
$ fastlane ios release

or

1
$ fastlane android release

and wait for them to be compiled.

XKCD

Add magic stuffs

We use Crosswalk in our hybrid projects, so we can build two Android apks: one for x86 and another one for armv7. Thanks to fastlane we can automatize that with two private lanes and use them in the main lane.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
desc "Do a new arm v7 Android build using jarsigner and zipalign."
private_lane :android_arm_release do |options|
  sign_apk(
      apk_path: "platforms/android/build/outputs/apk/android-armv7-release-unsigned.apk",
      signed_apk_path: "platforms/android/build/outputs/apk/android-armv7-release-signed.apk",
      keystore_path: "fastlane/release-cred/android.keystore",
      alias: app_android_key,
  )

  zipalign(apk_path: "#{lane_context[SharedValues::SIGNED_APK_PATH]}")
end

desc "Do a new x86 Android build using jarsigner and zipaliagn."
private_lane :android_x86_release do |options|
  sign_apk(
      apk_path: "platforms/android/build/outputs/apk/android-x86-release-unsigned.apk",
      signed_apk_path: "platforms/android/build/outputs/apk/android-x86-release-signed.apk",
      keystore_path: "fastlane/release-cred/android.keystore",
      alias: app_android_key,
  )

  zipalign(apk_path: "#{lane_context[SharedValues::SIGNED_APK_PATH]}")
end

You can also deploy a new beta build to HockeyApp and automatically notify the projects’ HipChat room:

1
2
3
4
5
hockey(
    api_token: ENV['HOCKEY_IOS_API_TOKEN'],
    ipa: "./releases/#{app_name_sanitized}.ipa"
)
hipchat(message: "Successfully deployed a new <b>iOS</b> build to HockeyApp<br/><a href='#{lane_context[SharedValues::HOCKEY_DOWNLOAD_LINK]}'>#{lane_context[SharedValues::HOCKEY_DOWNLOAD_LINK]}</a>")

In this snippet, Gym builds the IPA in a specific folder of the project, and the actions for HockeyApp and HipChat have been configured within the environment file.

You can integrate the build process with a lot of external services: you can find a list on fastlane documentation page, for example Slack/Flock/Email/Notification, Crashlytics, or tagging the git repo with the version of the build.

You can also release the build directly to iTunes Connect (documentation) or to the Play Developer Console (documentation).

Checkout the fastlane examples to learn how to integrate all these actions in a real-world mobile application.