Intermediate Fastlane
Introduction
So by now, if you’ve been working on mobile development for any longer than a few weeks, you’ve probably used Fastlane. I know I talk about it a lot in this blog, but it’s genuinely one of my favorite tools out there, and I think most people don’t use it to its full potential. So in this post, I’m going to show you some more advanced Fastlane features that you might not have seen before.
Separate Fastfiles
When you write your normal code, you won’t put everything in the same massive file, right? (RIGHT?) So why would you do that with your Fastlane setup? You can split your Fastlane setup into multiple files, which can make it easier to manage and understand.
I like to have all of my Fastlane files have fastfile
in the name, so I can easily see which files are Fastlane files. So for example, I’ll have the main Fastfile
, and a separate VersionBumpingFastfile
for all of my version bumping logic (Which you can learn more about here!).
The way you do this is by using the import
method in your Fastfile
. So if you have a file called VersionBumpingFastfile
in the same directory as your Fastfile
, you can import it like this:
#!/usr/bin/ruby
# frozen_string_literal: true
fastlane_version '2.225.0'
import 'VersionBumpingFastfile'
# The rest of your normal Fastfile here..
By doing it like this, you can now call any lane in your VersionBumpingFastfile
from your main Fastfile
, or as standalone commands from the terminal, and you get the nice separation of concerns that you’re used to in your normal code.
before_all
and after_all
Think about your normal XCTest suite (I know I know, you’re using the shiny new test framework, but try to remember what the olden days looked like). You have setUp
and tearDown
methods that run before and after each test, respectively. Fastlane has similar hooks that you can use to run code before and after your entire Fastlane run.
This is particularly useful if you’ve got things that need to happen regardless of which lane you’re running. For example, you might want to set up some environment variables, or clean up some files before you start running your lanes. You can do this with the before_all
and after_all
hooks in your Fastfile
.
before_all do
setup_circle_ci
end
lane :beta do
build_app(scheme: "MyApp")
upload_to_testflight
end
after_all do |lane|
clean_build_artifacts
end
This sets up the environment for CircleCI
and cleans up files after the Fastlane run. There are also some great examples of this on the Fastlane docs here, where they use the after_all
block to notify a Slack channel when the Fastlane run is complete, which is mega useful.
Embrace the lane syntax
I know we’re all coming from different languages and different syntax, but Fastlane has its own way of doing things. Let’s look at some lane patterns that can make your code more readable and maintainable.
Firstly, the is_ci
helper is your friend. It helps you write conditional lane logic. For example, instead of writing:
lane :deploy do |options|
if ENV['CI'] == 'true'
match(type: "appstore")
end
build_ios_app
end
You can write:
lane :deploy do |options|
match(type: "appstore") if is_ci
build_ios_app
end
You can also use lanes to handle error conditions elegantly:
lane :push_to_git do |options|
begin
push_to_git_remote
rescue => ex
handle_git_error(error: ex)
end
end
private_lane :handle_git_error do |options|
UI.error(options[:error])
create_git_branch
push_to_git_remote(force: true)
end
Another way you can make your lanes more readable is by using early returns for validation. For example, instead of writing:
lane :release do |options|
if options[:version]
if options[:version].match(/\d+\.\d+\.\d+/)
increment_version_number(
version_number: options[:version]
)
build_app
upload_to_app_store
else
UI.user_error!("Invalid version format")
end
else
UI.user_error!("Version is required")
end
end
You can write:
lane :release do |options|
UI.user_error!("Version is required") unless options[:version]
UI.user_error!("Invalid version format") unless options[:version].match(/\d+\.\d+\.\d+/)
increment_version_number(
version_number: options[:version]
)
build_app
upload_to_app_store
end
Conclusion
These are by no means the end all be all of Fastlane tips, but they’re some of the more advanced features that I think a lot of people don’t know about. There are a lot more great features, some of them are documented here, and some of them are just waiting for you to discover them. I hope this post has been helpful, and that you can take your Fastlane skills to the next level!