Fastlane
Fastlane is a popular tool for automating the build and release process for iOS, Android and macOS apps. Shorebird can be integrated with fastlane to automate releasing and patching.
Installation
Section titled “Installation”Follow the setup instructions on the fastlane website to install fastlane
(ios,
android). For
macOS, follow the iOS instructions from your app’s macos directory.
Using Fastlane on CI
Section titled “Using Fastlane on CI”This section assumes that you are using fastlane on CI to release your app. If you are running fastlane locally (on your development machine), you can skip to the Using fastlane locally section.
A working example of this setup can be found in the fastlane_demo sample.
On the CI machine, install Shorebird and add it to the PATH as the
generic CI guide shows, and set
SHOREBIRD_TOKEN as described in Authentication. Fastlane
runs shorebird as a child process, so the CLI reads SHOREBIRD_TOKEN from the
CI job’s environment.
For code signing and uploading to the stores on CI, follow fastlane’s own
continuous integration guide.
For iOS, match keeps your
certificates and provisioning profiles in a store your whole team and CI share;
call setup_ci before match
so it has a keychain to install into.
Notice that the demo app’s
Fastfile
has a release_shorebird lane. It uses the shorebird_release action in
place of fastlane’s
build_app action to build an
ipa and create a Shorebird release, then uploads it to TestFlight with
upload_to_testflight.
Note that this change from build_app to shorebird_release is the only change
needed to add Shorebird to your fastlane workflow.
Patching
Section titled “Patching”To patch your app, you can use the shorebird_patch action. You can see an
example of this in the patch_shorebird lane in the
Fastfile.
For iOS, build each patch with the same Xcode as the release it patches; see Build patches with the same toolchain as the release.
Authentication
Section titled “Authentication”Creating releases and patches needs a signed-in Shorebird CLI. In CI, the CLI
reads an API key from the SHOREBIRD_TOKEN environment variable, so nobody has
to run shorebird login on the builder.
Use a key that belongs to a service account. A service account belongs to your organization rather than to a person, so its key keeps working when whoever set up CI leaves or changes roles, and the audit log shows the job’s actions under the service account’s name. Service accounts are available on every plan. To create one, you need the Admin or Owner role in the organization:
- In the Shorebird Console, open your organization’s Settings and select Service accounts.
- Click Create service account, name it after the CI system that will use
it (such as
GitHub Actions), and click Create. - Keep the Developer role, which can create releases and patches. Choose
App Manager instead if the job also creates apps, for example by running
shorebird init. - Under API keys, click Create key, enter a name, and choose an expiration.
- Copy the key. It is shown only once.
Store the key as SHOREBIRD_TOKEN in your CI platform’s secrets manager, as the
steps below show.
If you can’t create a service account, a personal API key from Account → API
Keys goes in SHOREBIRD_TOKEN the same way. It acts as you, can do at most
what your own role allows, and stops working if your account is deleted. See
API Keys.
Add the key to your CI system’s secrets as SHOREBIRD_TOKEN, and pass it to the
job that runs fastlane as an environment variable.
Using Fastlane locally
Section titled “Using Fastlane locally”This section assumes that you have Shorebird installed on the machine that will be running fastlane. If you have not already installed Shorebird, you can do so by following the Getting Started instructions.
If you are not already using fastlane with your project, navigate to your app’s
ios directory in your project and run fastlane init. You will be prompted to
answer several questions. For this guide, choose to manually add lanes to the
Fastfile.
Use the Shorebird plugin
Section titled “Use the Shorebird plugin”Run the following command to install the shorebird fastlane plugin, which
exposes the shorebird_release and shorebird_patch actions.
Update Fastfile to release
Section titled “Update Fastfile to release”Open the Fastfile in the fastlane directory and add the following lane:
To run this, execute the following command:
If you would like to provide additional arguments to the release command, you
can do so using the args parameter. For example:
Update Fastfile to patch
Section titled “Update Fastfile to patch”Open the Fastfile in the fastlane directory and add the following lane:
Run it with the version of the release to patch, normally the one in the App Store:
Naming the release keeps a patch from landing on a build that hasn’t shipped,
such as one still in TestFlight. See Patching for why to
always pass --release-version.
As with shorebird_release, you can provide additional arguments to the patch
command using the args parameter.
Android
Section titled “Android”The same actions release and patch Android apps. Run fastlane init in your
app’s android directory, which sets up the Play Console credentials that
upload_to_play_store
uses, and add the Shorebird plugin there as above. Then add these lanes to
android/fastlane/Fastfile:
shorebird release android signs the app bundle with your Gradle release
signing config, as flutter build appbundle does, so the machine running the
lane needs your upload keystore and key.properties. Ruby code in a lane runs
from the fastlane directory, so File.expand_path("../..") is your Flutter
project’s root, where the app bundle is built.
With a flavor, pass it in args to both actions, for example
shorebird_release(platform: "android", args: "--flavor production"), and
change the app bundle path to
build/app/outputs/bundle/productionRelease/app-production-release.aab.
The shorebird_release and shorebird_patch actions are written for iOS and
Android, so these lanes call the Shorebird CLI with sh instead. They assume
the Fastfile is in your app’s macos/fastlane directory. Fastlane runs sh
and other Ruby code in a lane from the fastlane directory, so
File.expand_path("../..") is your Flutter project’s root.
shorebird release macos runs flutter build macos, which builds and signs the
app with the signing settings of your Xcode project’s Release configuration,
then creates the release. It doesn’t archive or export the app, so Xcode never
re-signs it for distribution the way it does when exporting an archive. Set up
the Release configuration for how you distribute the app, as described below,
before releasing. The signed .app is in build/macos/Build/Products/Release.
To pass arguments to shorebird release or shorebird patch, add them to the
sh call, for example
sh("shorebird", "release", "macos", "--flavor", "production"). With a flavor,
the app is in build/macos/Build/Products/Release-production, so change the
Release/*.app glob in the release lanes to match.
The lanes are in a platform :mac block. fastlane init writes a Fastfile
for iOS (default_platform(:ios) and a platform :ios block), so either change
it to default_platform(:mac) or name the platform when you run a lane:
The lanes expect your signing certificates in the keychain. If you manage them
with match, as the iOS setup above
does, each section names the match call to add to the lane before the release
step. On CI, call setup_ci before match so it has a keychain to install
into.
Release outside the Mac App Store
Section titled “Release outside the Mac App Store”For an app you distribute yourself, set the Release configuration to sign
manually with your Developer ID Application certificate. With match, add
match(type: "developer_id", platform: "macos").
Apple’s notary service requires the app to be signed with the hardened runtime
and every executable in it to carry a secure timestamp. Xcode adds the timestamp
only when it exports an archive, and Flutter signs App.framework and
FlutterMacOS.framework without one. So this lane re-signs the app’s frameworks
and then the app with both, and notarizes the result with fastlane’s
notarize action:
Replace the signing identity with your own; security find-identity -v lists
the identities in your keychain. notarize uploads the app to Apple’s notary
service and staples the ticket to it. It takes an App Store Connect API key
(api_key_path or api_key; this example reads api_key.json from the
fastlane directory) or an Apple ID (username). Package the stapled app
however you ship it, for example in a disk image.
Release to the Mac App Store
Section titled “Release to the Mac App Store”A build you can upload to the Mac App Store needs:
- The Release configuration set to sign manually with an Apple Distribution certificate.
- A Mac App Store provisioning profile for your app’s bundle ID, selected in the Release configuration. The build embeds it in the app, and App Store Connect rejects a Mac build without one (ITMS-90889).
- A Mac Installer Distribution certificate, which
productbuilduses to sign the package. It shows in your keychain as “3rd Party Mac Developer Installer”.
Automatic signing doesn’t produce this build. With it, the build signs with an Apple Development certificate, because Xcode applies the distribution certificate and profile only when it exports an archive.
With match, add
match(type: "appstore", platform: "macos", additional_cert_types: ["mac_installer_distribution"]),
which installs both certificates and a profile named
match AppStore <bundle ID> macos to select in the Release configuration.
This lane packages the app with productbuild and uploads the package to
TestFlight with
upload_to_testflight,
which leaves your App Store version alone:
Replace the installer identity with your own.
Pass the release to patch as release_version, as shown above.
shorebird patch macos builds and signs the app with the Release
configuration’s signing settings, as the release did, so the machine running
this lane needs the same certificate and provisioning profile. With match, add
the same match call the release lane uses, with readonly: true, before
shorebird patch (after setup_ci on CI). Build the patch the way you built
the release: passing --no-codesign to a patch of a signed release makes
Shorebird report native code changes that aren’t in your code. A patch needs no
re-signing, notarization or upload; Shorebird delivers it to apps already
installed from the release.