Fastlane configuration in Swift still in Beta but it works! In this example, I’ll show you how to automate distribution to TestFlight with Fastlane.
Easy setup!
Steps
1. Setup. Generate config
2. Config overview
3. Auto increase version numbers. Project setup
4. Passing parameters. Final setup
5. Execution. Errors
6. Gitignore
1. Setup. Generate config
Install fastlane using Homebrew
brew install fastlane
or RubyGems
sudo gem install fastlane -NV
To generate config navigate your terminal to your project’s directory and run
fastlane init swift
I selected Automate beta distribution to TestFlight
Your app can have several schemes. Fastlane may ask you to select one of them.
If the required scheme is missing in the list you should mark it as shared, cancel current process with Ctrl+C and enter fastlane init swift
again
Then enter Apple ID developer credentials
Passing two-factor authentication:
If the account has multiple App Store Connect or Developer Portal teams select your teams
Our fastlane setup generated and ready to use but I suggest to check it and edit if needed.
2. Config overview
You can open the generated config project /fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj
in Xcode.
We will work with Appfile and Fastfile. You shouldn’t edit their counterparts from /fastlane/swift
directory because they will be overwritten or replaced during build time
FastlaneSwiftRunner project contains correct Appfile and Fastfile from /fastlane
.
Appfile.swift stores global variables and configs which can be used in Fastfile. For example, we can add appVersion
variable and change it before upload to TestFlight, but we’ll automate this task later.
Fastfile.swift contains our “lanes” — automated tasks (automated AppStore or TestFlight distribution, etc.)
Inside “beta” lane you see different actions:
incrementBuildNumber()
— increments build numberbuildApp()
— generates .ipa file in the project directoryuploadToTestflight()
— uploads build to TestFlight
All available actions are listed here https://docs.fastlane.tools/actions/ and ready to use in our project as functions. Xcode autocomplete will help you.
Function name matters. “Lane” suffix means that function describes command which can be called from terminal by the rest part of the name. So fastlane beta
command runs betaLane()
func
Any custom func without Lane
ending can be added to file and won’t be parsed as lane
Let's edit generated code. I found that teamId
parameter is missing in uploadToTestflight()
func call. It’s relevant to AppleIds with two or more dev accounts. So if teamId
isn’t specified fastlane will ask you every time you run this line.
I replaced hardcoded username
with appleID
, defined in Appfile, and added teamId
parameter. Others hardcoded values like workspace or scheme also can be moved to Appfile
Another change I did is auto-increment version number. This action is performed by the function incrementVersionNumber()
. But using incremental actions requires little preparation
3. Auto increase version numbers. Project setup
Usually, we setup build and version numbers here
In this case Xcode change Bundle version and Bundle version string (short) to $(CURRENT_PROJECT_VERSION) and $(MARKETING_VERSION). Fastlane can’t work with these variables
So we need to copy the values from General to Info tab and won’t change Version and Build number on General in future.
App version (Bundle version string) can only contain numeric characters (0–9) and periods. Each integer provides information about the release in the format [Major].[Minor].[Patch]
Examples: “2”, “41.3”, “1.31.5”
More info https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring
Incremental func incrementVersionNumber()
by default increments last number, using a default value patch
. To change another number set parameter bumpType
to minor
or major
Looks good but let's add possibility to send bumpType
from terminal!
4. Passing parameters. Final setup
class Fastfile: LaneFile {
func betaLane(withOptions options:[String: String]?) {
let appVersion = options?["appVersion"]
let bumpTypeOptional = options?["bumpType"]
let bumpType = bumpTypeOptional ?? "patch"
if appVersion != nil, bumpTypeOptional != nil {
echo(message: "Only one parameter can be used: appVersion or bumpType")
return
}
if !["major", "minor", "patch"].contains(bumpType) {
echo(message: "Unknown parameter value \(bumpType)")
return
}
desc("Push a new beta build to TestFlight")
incrementBuildNumber(xcodeproj: "Reminder.xcodeproj")
incrementVersionNumber(bumpType: bumpType, versionNumber: appVersion, xcodeproj: "Reminder.xcodeproj")
buildApp(workspace: "Reminder.xcworkspace", scheme: "Reminder")
uploadToTestflight(username: appleID, teamId: teamID)
}
All valid func signatures which can receive input params described here
https://medium.com/@doruvil/fatlane-continous-integration-swift-version-b8851f1f38b6
Our lane can process appVersion
or bumpType
params.
To setup any version use appVersion
param
fastlane beta appVersion:3.2.13
To increment first or second number pass major
or minor
as value of bumpType
, patch
is the default value
fastlane beta bumpType:major
If both params or incorrect value for bumpType
are received program prints an error message to terminal and exits.
5. Execution. Errors
To increase build, version numbers, generate a new build, and upload it to TestFlight run command with or without parameters
fastlane beta
fastlane beta appVersion:<version>
fastlane beta bumpType:<major/minor>
During execution, Fastlane may ask for an app-specific password. Follow instruction
Finally, I’ve got the error but build uploaded successfully. Just wait for an email from App Store
6. Gitignore
Add to gitignore
*.ipa
*.dSYM.*
/fastlane/report.xml
/fastlane/FastlaneRunner
Links
https://developer.apple.com/library/archive/qa/qa1827/_index.html