Software Engineer at Capital One UK
Fastlane released support for Android in 2015 when it was acquired by Fabric. And as you may know, Google acquired Fabric in 2017. The acquisition surely benefits the fastlane team to improve the integration between their tool and the Android environment to be even more seamless. Today, fastlane is widely adopted across the Android and iOS communities.
In the past few weeks, I’ve been played around with fastlane and got it to publish an app to Play Console. I started from scratch. I had no past experience with fastlane or Ruby, the scripting language fastlane uses. But I’ve got to tell you, it’s so straight forward, yet, so powerful at the same time.
Table of contents:
On a quick search to find something along the lines of “Ruby for fastlane”, I came across this article, Everything You Need to Know About Ruby for iOS Development from Big Nerd Ranch. Although it says “for iOS Development”, it fits this purpose really well as a lot of third-party tools in the world of iOS development use Ruby: Cocoapods, xcpretty, and of course, fastlane. This article gave me enough knowledge to get started with fastlane.
Here are my short notes from the article:
rvm
Means Ruby Version Manager. It is a command-line tool which allows you to easily install, update, manage, and work with multiple ruby environments.
rbenv
Another tool for managing different ruby environments.
In Ruby, libraries or tools are packaged up as gems. fastlane is written in Ruby, that’s why you can install it via the command gem install fastlane
.
Bundler is a Ruby gem that allows you to specify all your gems in a file named Gemfile. Think of this one like the dependencies block in your app’s build.gradle where you specify dependencies.
And you can install Bundler by executing gem install bundler
as it’s also a gem.
After you installed Bundler, you can install the gems you specified in Gemfile by executing bundle install
.
One thing to keep in mind about gems is that they’re tied to specific versions of Ruby. This could introduce the problem of running a project on different machines with different versions of gems. But don’t you worry, Bundler has got us covered.
The first time bundle install
is executed on a project, a Gemfile.lock will be created. This is a lock file which maintains the exact version of each gem of the project. So no matter whose machine the project is running on, the gems will always be the same.
And you can just run bundle update
to update the versions of your gems.
Supply is a command-line tool for updating Android apps to the Google Play Store. Basically, it means you can do the publishing from the command line with commands prefixed with fastlane supply ...
. Supply comes bundled with fastlane, so no extra installation needed. Installing fastlane is covered in part 4. You can read more about Supply here: https://docs.fastlane.tools/actions/upload_to_play_store/. And you may notice that the link ends with upload_to_play_store, this is because “supply” is just an alias for “upload_to_play_store”.
This step is very well explained on the Supply intro page. Assuming you already have your Google Play Console set, you can just follow the steps below (copied from https://docs.fastlane.tools/actions/upload_to_play_store/)
This guide is for Mac users (sorry Windows users). There are at least two ways to install Ruby on Mac, through brew or just use the pre-installed Ruby on your Mac in which you will only need to install a few tools like rvm
and rbenv
. I recommend using the pre-installed Ruby as even if you install the new one from brew, fastlane might pick up the old one.
brew install ruby
export PATH="/usr/local/opt/ruby/bin:$PATH"
to .bash_profile
or .zshrc
if you use zshell.If you’re a mobile developer who’s starting from scratch like me, chances are you have never touched Ruby, so you need to update it first.
You can run ruby -v
to check the current version of Ruby on your machine.
Before updating Ruby, we first need to install rvm. As mentioned above, rvm helps us manage ruby environments. It is also the standard for upgrading your Ruby installation on macOS
\curl -L https://get.rvm.io | bash -s stable --ruby\curl -L https://get.rvm.io | bash -s stable --ruby
gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
source /Users/Mac/.rvm/scripts/rvm
rvm list known
rvm install ruby-<version-number>
rvm install ruby-2.6.5
rvm install current && rvm use current
First things first, make sure you have the latest version of the Xcode command line tools installed:
xcode-select --install
There are a few ways to install fastlane
You can just intall the gem as fastlane is also a Ruby gem:
gem install fastlane
The other way is installing through Bundler as mentioned in the Ruby crash course for fastlane
section. To do this, add gem "fastlane"
to the Gemfile
file as well as specifying the source like this
source "https://rubygems.org"
gem "fastlane"
Then you can install fastlane by running
bundle install
Or just run
brew cask install fastlane
You can check the version of you fastlane by running
fastlane -v
Now that you’ve got everything ready (the json secret file for connecting to Play Console, Ruby, and fastlane installed), cd
to your project and run
fastlane init
You’ll be asked to provide the package name for your app and path to the json secret file. Fastlane will also give you a brief of files that are being generated and what they do.
If it shows an error when trying to run the bundle update
command with a suggestion It is likely that you need to grant write permissions for that path
. Just continue until it finishes. And then run
sudo bundle update
This command fetches new versions of your gems. But if bundle install
hasn’t been executed on the project before, this will act like the bundle install
command by fetching the gems specified in Gemfile and create Gemfile.lock to maintain the Ruby versions of the gems of this project. (This also means running sudo bundle install
would yield the same results here.)
Looking into your project root folder right now, you’ll see a few new files namely: Gemfile, Gemfile.lock, fastlane/Appfile, and fastlane/Fastfile.
As mentioned, this is where the gems are listed. If you didn’t edit this file before, fastlane would auto-generate this with gem "fastlane"
as well as the source where it can be fetched, source "https:rubygems.org"
.
Although we only have one gem at this point, the fastlane gem depends on loads of other gems. Therefore, if you have a sneak peek on this one, you’ll see a long list of gems, including things like googleauth
and google-api-client
.
This is where you define the configuration information that is global to your app, e.g. Package Name and Path to the json secret file, so you don’t have to enter it every time you run the fastlane commands.
Here live the lanes. A lane is a set of automation script to perform a task. You can create a lane to do things like running gradle commands, screenshots, post an update to Slack, or publish to the Play Store. For example, this is the contents of the auto-generated Fastfile
default_platform(:android)
platform :android do
desc "Runs all the tests"
lane :test do
gradle(task: "test")
end
desc "Submit a new Beta Build to Crashlytics Beta"
lane :beta do
gradle(task: "clean assembleRelease")
crashlytics
# sh "your_script.sh"
# You can also use other beta testing services here
end
desc "Deploy a new version to the Google Play"
lane :deploy do
gradle(task: "clean assembleRelease")
upload_to_play_store
end
end
First of all, the platform is specified. Then, in the android
platform block, there are three lanes, test, beta, and deploy.
The test lane just runs the gradle command test
. This is equivalent to executing gradle test
from the command line.
The beta lane runs gradle clean assembleRelease
and upload a new build to Crashlytics Beta.
And the deploy lane runs gradle clean assembleRelease
and upload to the Play Store.
The commands in lanes are called fastlane actions. You can find out more about all the available actions at https://docs.fastlane.tools/actions/.
If you entered “y” when it asked whether to download existing metadata, you’d also see a folder called metadata. If you have published your app before, all the metadata, app descriptions, screenshots and images, changelogs, title, and video, will be downloaded into this folder. This is where you’ll edit your metadata, add a new version changelog, or update some screenshots so that these get changed automatically for your apps without touching the Play Console.
With the default lanes specified, you can run bundle exec fastlane
, it’ll ask you which lane you want to run. You can have a go with the test lane to see the magic. You can shortcut the lane picking step by suffixing your command with the lane name like this.
bundle exec fastlane test
When I ran bundle exec fastlane deploy
, there was a problem with my Keystore file location. I didn’t keep my Keystore file at root. And for some reason, fastlane couldn’t find my Keystore file even though Android Studio could if I try to build a release from it. So I moved my Keystore to root, gitignored it, and update the signingConfigs block in app/build.gradle
to the following:
android {
signingConfigs {
release {
keyAlias 'app_key_alias'
keyPassword 'app_key_password'
storeFile rootProject.file('app_key_store.jks')
storePassword 'app_store_password'
}
}
...
}
Before, the storeFile
was something like
storeFile file('/Users/Mac/.../app_key_store')
Now to the steps I think would apply to everyone.
If this is an update to your existing app, make sure you don’t forget to update your versionCode
and versionName
to new ones.
You won’t get an error if you forget this, but it can cause confusion. If you’ve pulled metadata from the existing listing on Play Console, you’ll see a text file under a similar location to this fastlane/metadata/android/en-GB/changelogs
. The text file should be named the same as your versionCode
. So make sure you update the file name and the content of the file to be the updates you want under the What’s new section of your app on Play Store. e.g. 20.txt
Lastly, the deploy
lane is needed to be updated with the release credentials. It seems redundant as we already have these credentials specified in app/build.gradle - signingConfigs/release
. But I kept getting this error:
Google Api Error: apkNotificationMessageKeyUpgradeVersionConflict: APK specifies a version code that has already been used. - APK specifies a version code that has already been used.
And adding the credentials fixed it.
desc "Deploy a new version to the Google Play"
lane :deploy do
gradle(
task: "clean assembleRelease",
properties: {
"android.injected.signing.release.file" => "key-store.jsk",
"android.injected.signing.store.password" => "H63JAV",
"android.injected.signing.key.alias" => "key_alias",
"android.injected.signing.key.password" => "KEYPASSWORD"
}
)
upload_to_play_store
end
And now you can just run bundle exec fastlane deploy
, brew some tea, and wait for Google Play confirmation email that your update has been released 🎉
If you have any questions, please ask me at @landtanin. Also, I’m clearly new to this world of fastlane and automation. So if you have comments or suggestions, please let me know. Thanks for reading!