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.
To get started, follow this guide to set up fastlane with certificate management, code signing, and submitting to the App Store/TestFlight.
Notice that the demo app’s
Fastfile
has a release_shorebird lane. It uses the shorebird_release action in
place of the guide’s build_app 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.
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:
This will patch the iOS release whose version matches the one detected in the compiled app.
As with shorebird_release, you can provide additional arguments to the patch
command using the args parameter.
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.
This patches the macOS release whose version matches the one in the compiled
app. 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.