Give QA an add-to-app build, then promote it
If your host app (Android or iOS) has a QA build that goes to a group of testers
before your users get anything, Shorebird fits into it with a
track. The QA build checks the qa track and the build you
ship checks stable. You publish each patch to qa, and when QA signs off you
promote that same patch to stable, without rebuilding it.
This page assumes you have already followed the Android or iOS add-to-app guide.
How releases and patches reach QA
Section titled “How releases and patches reach QA”- A release is the module build that
shorebird release aarorshorebird release ios-frameworkproduced. It reaches devices only inside a host app build, so QA sees a new release as soon as you give them a host build that contains it, and your users see it when you ship that host app to the store. Shorebird doesn’t need to hold the release back. - A patch reaches every device running its release that checks the patch’s
track. Publish it to
qaand only QA builds get it. Promote it tostableand your users get it too.
For a patch to work in both builds, the QA build and the build you ship must
contain the same module release: the same aar or .xcframeworks from the
same release directory. The QA build differs only in the host app: it tells
the module which track to check.
Set up the module once, before you release
Section titled “Set up the module once, before you release”The module has to read its track from the host app, and that code has to be in
the release. Follow
Set up the module once, before you release:
add shorebird_code_push, set auto_update: false, and check for updates on
the track the host app passes as --shorebird-track=<name>. With no track, the
module checks the default track (stable, or the channel: set in
shorebird.yaml), so the build you ship needs no change.
Add a QA build to your host app
Section titled “Add a QA build to your host app”Give the host app a QA build that passes --shorebird-track=qa to the module,
and keep the build you ship passing nothing. The code that starts the Flutter
engine is the same as in
Build the host app locally with your track:
it reads SHOREBIRD_TRACK from the build and passes it to the module only when
it’s set. Here the QA build sets it to qa.
The QA build must be a release build, because Shorebird only patches release
builds. It must also keep the host app’s version: the version and build number
have to match the --release-version you released the module with.
Android
Section titled “Android”Add a qa build type that starts from release, sets the track, and uses the
module’s release aar:
Build the QA build with ./gradlew assembleQa (or bundleQa), and hand it to
QA the way you do today, for example with Firebase App Distribution. The release
build still has an empty SHOREBIRD_TRACK, so it checks the default track.
The .qa suffix gives the QA build its own package name. Shorebird doesn’t
mind: the module’s app_id comes from the aar, and the release version from
the version name and code. But anything else keyed on the package name needs the
QA one registered too, for example a Firebase app in google-services.json,
OAuth clients, and API keys. Without the suffix, the QA build replaces the store
app on testers’ devices, and you can’t upload it to Google Play under the same
version code as the build you ship.
If your app uses build.gradle.kts, the build type is:
- In your project’s Info tab, duplicate the Release configuration and
name the copy QA. The copy keeps Release’s build settings, including the
Framework Search Paths to your module’s
.xcframeworks. If your app uses CocoaPods for other dependencies, map the new configuration to release in yourPodfile(project 'MyApp', 'QA' => :release) and runpod installagain. - In your app target’s Build Settings, add a user-defined setting
SHOREBIRD_TRACK. Leave it empty for Release and set it toqafor QA. - Still in the target’s Build Settings, give the QA configuration its own
Product Bundle Identifier, such as
com.example.myapp.qa. The QA build has to keep the version and build number of the build you ship, and App Store Connect accepts each build number only once per app, so the QA build needs an app of its own there (or distribute it ad hoc). - In your app’s Info.plist, add an entry
ShorebirdTrackwith the value$(SHOREBIRD_TRACK). - Duplicate your scheme, name it for QA, and set its Archive build configuration to QA.
Archive the QA scheme and hand the build to QA the way you do today, for example
with TestFlight under the QA app. Archives of your normal scheme still have an
empty ShorebirdTrack, so they check the default track.
Ship a new release
Section titled “Ship a new release”-
Release the module, with the version of the host app that will contain it:
-
Build the host app’s QA build from that
releasedirectory and give it to QA. -
When QA signs off, build the host app you ship from the same
releasedirectory and submit it to the store. Don’t rebuild the module in between.
Ship a patch
Section titled “Ship a patch”-
Make your change in the module and publish the patch to
qa: -
QA launches their build so the module downloads the patch (if the app starts Flutter only when a Flutter screen opens, they open one), then fully quits it and launches it again to run it. Builds from the store never see it.
-
When QA signs off, promote the patch to
stable, with the patch number thatshorebird patchprinted (or find it withshorebird patches list --release-version <version>):Your users get the exact patch QA tested.
To patch again, publish the next patch to qa and repeat. A patch QA rejects
stays on qa; publish a fixed one to qa and promote that instead.
If QA and your users get the same store build
Section titled “If QA and your users get the same store build”Some teams don’t have a separate QA build: QA installs from a Google Play test
track or TestFlight, and the same binary is later promoted to your users. That
binary can’t have qa built in. Choose the track at runtime instead, for
example from how the app was installed or who is signed in, and pass it to the
module the same way. See
Testing patches with a subset of users for
ways to choose it.