· 6 min read Posted by Gustavo Fão Valvassori
Fastlane in Kotlin Multiplatform projects

Fastlane is a tool for mobile development (iOS and Android) that allows you to automate tasks such as building, testing, and deploying your app. It can save you a lot of time and effort, especially with tedious tasks.
As a Kotlin Multiplatform Developer, this is especially helpful as it centralize all your build steps in a single place. If your project has multiple modules, things can get out of hand easy. And with Fastlane, you can orchestrate all the build steps and call only one command, like we will see in the ‘test’ command below.
It uses Ruby scripts to define the tasks (here known as lanes) that can be called from the command line. To start using
it, all you need to do is install it (using Brew or RubyGems), and then create a Fastfile
in the fastlane
directory.
Fastlane and KMP
When you start reading the docs, you will find out that most examples are pure native, or using other multiplatform frameworks like React Native or Flutter. So, how can we use Fastlane in a Kotlin Multiplatform project?
The answer is simple: it depends.
For Android Development, KMP is just another Android library. In other words, you will use fastlane as you would in any other Android project.
But for iOS, things are a bit different. Since KMP does manage the native apps (like React Native or Flutter), depending on how you are structuring your project, you may have a different solution.
If your iOS project is integrated through XCode Build Phases or Cocoapods, you can use Fastlane as you would in any other iOS project. But if your KMP exports a framework that is linked to the iOS project (like when you use KMMBridge), you will need to first build it using the gradle command.
Creating a Fastfile
As we previously mentioned, the Fastfile
is where you define the lanes that Fastlane will execute. Each lane is
composed by a series of actions that will be executed in order. Those tasks can be pre-defined by Fastlane, created by
Plugins, or custom scripts that you write.
- Fastlane built-in actions: https://docs.fastlane.tools/actions/
- Fastlane Plugins: https://docs.fastlane.tools/plugins/available-plugins/
So everything starts by creating the Fastfile
. If your project supports both Android and iOS, your initial
configuration, can be something like this:
platform :ios do
lane :build do
puts "Building iOS app"
end
end
platform :android do
lane :build do
puts "Building Android app"
end
end
Here we are defining two lanes, one for iOS and one for Android, that will print a message. To call it, you can
run fastlane $PLATFORM $LANE
(or bundle exec fastlane $PLATFORM $LANE
) in the terminal. Note that as we define
multiple platforms, we need to specify the platform we want to run before the lane name.
$ fastlane android build
$ fastlane ios build
Android
For Android, the lanes are pretty straightforward. You can use the built-in gradle
action to build, test, and deploy
your app.
platform :android do
lane :build do
gradle(
task: "assemble",
build_type: ENV['releaseBuild'] == 'true' ? "Release" : "Debug"
)
end
end
If you need to run tests, or build different flavors, you can simply tweak the gradle action parameters. A simple test lane could be as simple as:
platform :android do
lane :build do
gradle(
task: "testDebugUnitTest"
)
end
end
iOS
For iOS, things are a bit different, but still simple. To build the XCode project, you can use the build_app
(or its alias, gym
) action. This action uses the xcodebuild
command line to assemble the app.
For tests, you will need to follow a similar approach from the iOS build, but using the run_tests
(or its alias scan
)
action.
It’s important to note that you need to have the XCode command line tools installed. For more details, check the Fastlane iOS getting started docs.
About how to really build the app, everything depends on how your KMP is integrated with the iOS project.
Build Phases
If you created your app using the JetBrains KMP Wizard, you are probably using Build
Phases. To compile your iOS app, you should call the build_app
action.
platform :ios do
lane :build do
build_app(
project: './iosApp/iosApp.xcodeproj',
configuration: ENV['releaseBuild'] == 'true' ? 'Release' : 'Debug',
scheme: 'iosApp',
archive_path: './build/archives/iOS',
buildlog_path: './build/archives/logs/',
destination: 'generic/platform=iOS'
)
end
end
For tests, you need to run them for both the Kotlin/Gradle project, and the iOS project. So your lane will have at least two calls:
platform :ios do
lane :test do
gradle(
tasks: [
':composeApp:iosSimulatorArm64Test',
':composeApp:iosX64Test',
]
)
run_tests(
project: './iosApp/iosApp.xcodeproj',
configuration: ENV['releaseBuild'] == 'true' ? 'Release' : 'Debug',
scheme: 'iosAppUiTest',
device: 'iPhone 16 (18.2)',
ensure_devices_found: true,
prelaunch_simulator: true,
fail_build: false,
reset_simulator: true
)
end
end
KMMBridge or XCFramework
If you build the XCFramework from gradle and consume it (like when you do SPM local dev with KMM Bridge), all you need
to change, is add the gradle
action from your iOS platform lanes:
platform :ios do
lane :build do
buildMode = ENV['releaseBuild'] == 'true' ? 'Release' : 'Debug'
# Compile the Framework
gradle(
tasks: [":composeApp:assembleComposeApp#{buildMode}XCFramework"]
# tasks: [":composeApp:spmDevBuild"] # Sample using SPM Dev Build from KMMBridge
)
build_app(
project: './iosApp/iosApp.xcodeproj',
configuration: buildMode,
scheme: 'iosApp',
archive_path: './build/archives/iOS',
buildlog_path: './build/archives/logs/',
destination: 'generic/platform=iOS'
)
end
lane :test do
gradle(
tasks: [
':composeApp:iosSimulatorArm64Test',
':composeApp:iosX64Test',
]
)
# Compile the Framework
gradle(
tasks: [":composeApp:assembleComposeApp#{buildMode}XCFramework"]
# tasks: [":composeApp:spmDevBuild"] # Sample using SPM Dev Build from KMMBridge
)
run_tests(
project: './iosApp/iosApp.xcodeproj',
configuration: ENV['releaseBuild'] == 'true' ? 'Release' : 'Debug',
scheme: 'iosAppUiTest',
device: 'iPhone 16 (18.2)',
ensure_devices_found: true,
prelaunch_simulator: true,
fail_build: false,
reset_simulator: true
)
end
end
Final Thoughts
Fastlane is a powerful tool that can save you a lot of time and effort. It’s easy to use, and you can start with simple lanes and then add more complex tasks as you need.
This tool can be an essential part of your app structure, especially if you are working with a multiplatform projects, and different CI/CD environments. Usually, each CI env has its own way of doing stuff, and having it set-up in a Fastfile can make your life easier to migrate/reuse.
If you want to check a simple example, you can check the Fastlane KMP Sample.
KMP Pipeline Automation and Optimization
Navigating build systems and optimizing your CI/CD pipeline can be challenging. Clients leverage Touchlab’s experience to solve their KMP pipeline challenges and optimize other team development workflows.