feat: support module_version for add-to-app AAR releases#3674
feat: support module_version for add-to-app AAR releases#3674
Conversation
Make --release-version optional for AAR releases. When omitted, defaults to the current git commit short hash. The release version is temporarily injected into shorebird.yaml before building so it gets baked into the AAR's flutter_assets/shorebird.yaml. The engine reads this field and uses it instead of the host app's version when checking for patches. This enables add-to-app (AAR) use cases where the same module is embedded in multiple host apps with different version numbers. Closes #793
…tion Replace the hacky _injectReleaseVersion/_restoreYaml approach with a clean environment variable passed to `flutter build aar`. The Flutter tool's compileShorebirdYaml() reads SHOREBIRD_RELEASE_VERSION and writes it into the build output's shorebird.yaml — no source file mutation needed.
The SHOREBIRD_RELEASE_VERSION env var is silently ignored by older Flutter versions, so we need to enforce a minimum version to ensure the release version actually gets baked into the AAR.
The version gate should only apply when using the new env var flow (no explicit --release-version). Passing --release-version explicitly works with any Flutter version since it doesn't depend on the SHOREBIRD_RELEASE_VERSION env var.
The concept applies to both AAR and iOS framework releases — module_version is the platform-agnostic name for the version of an embeddable Flutter module.
moduleVersion is the git hash baked into the AAR via env var (new flow only). releaseVersion is the server-side release name — either from --release-version (old flow) or the module version (new flow). They are resolved independently and stored separately.
Optional field for add-to-app (module) releases. When present, the server uses it instead of releaseVersion for patch lookup. The releaseVersion always contains the host app's version for analytics. Part of #793
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
packages/shorebird_cli/lib/src/commands/release/aar_releaser.dart
Outdated
Show resolved
Hide resolved
packages/shorebird_cli/lib/src/commands/release/aar_releaser.dart
Outdated
Show resolved
Hide resolved
Resolve both _releaseVersion and _moduleVersion once during assertArgsAreValid instead of lazily re-parsing argResults in multiple methods. Also check Flutter version when null (not just when too old).
packages/shorebird_cli/lib/src/commands/release/aar_releaser.dart
Outdated
Show resolved
Hide resolved
packages/shorebird_cli/lib/src/commands/release/aar_releaser.dart
Outdated
Show resolved
Hide resolved
In the module-version flow, _releaseVersion is null and getReleaseVersion returns _moduleVersion instead. This correctly separates the two concepts — _releaseVersion is only the explicit --release-version value.
packages/shorebird_cli/lib/src/commands/release/aar_releaser.dart
Outdated
Show resolved
Hide resolved
packages/shorebird_cli/lib/src/commands/release/aar_releaser.dart
Outdated
Show resolved
Hide resolved
Three ways to create an AAR release: 1. --release-version=1.0.0: Explicit version, no module version baked in (existing behavior). 2. --module-version=git: Uses git hash as module version. Recommended for CI. 3. --module-version=v2.0: Explicit module version string. 4. Neither flag (interactive): Prompts for module version with git hash as default. Includes warning about module versions not being store-enforced. Errors if both --release-version and --module-version are provided. Errors in non-interactive mode if neither flag is provided.
Extract shared module version resolution logic into Releaser base class (resolveModuleReleaseVersionArgs, getGitHash, assertFlutterSupportsModuleVersion). Both AarReleaser and IosFrameworkReleaser now use the same code paths for: - --module-version flag handling - --release-version flag handling - Interactive prompt with git hash default - Module version info message - Flutter version gating Also adds moduleVersion parameter to buildIosFramework().
Can you describe the full workflow you're intending a customer to follow so I can wrap my mind around how this solution fully addresses the problem? If customer CoolCustomer has two apps NeatApp and AwesomeApp which both embed a shorebird-enabled AAR Flutter module SocialModule, and CoolCustomer wants to release a bugfix in SocialModule across their two apps at the same time... how do they set up the releases ahead of time and what does patch creation look like? Is the intent to have the user generate separate Shorebird releases for NeatApp and AwesomeApp, but with a shared module version for SocialModule & hopefully identical code (for the purposes of making stuff like MAU maximally useful), thereby allowing the user to create one patch that will distribute to all releases attributed to the SocialModule module version? |
|
My expectation would be that if customer has apps A and B and module M, they would build module M once, and then embed it into A and B as though it were a 3p dependency (already comes prebuilt). Thus M would end up with the same module_version in our system, and when they send a patch to M, it would appear in both A and B? |
|
So When you want to patch, you just then run I think I need to get a full setup working locally (although I'm not entirely sure I can do that before landing at least the server bits) to verify. |
Summary
--release-versionis omitted for AAR releases, default to git commit short hash as both the server-side release version and the module version baked into the AARflutter build aarviaSHOREBIRD_MODULE_VERSIONenv var; the Flutter tool writes it asmodule_versioninto the compiledshorebird.yamlmoduleVersionfield toShorebirdYamlschema (so the CLI accepts the field)moduleVersionfield toPatchCheckRequestprotocol--release-versionis omitted (older Flutter ignores the env var)moduleVersionparameter tobuildAar()in artifact builderContext
Addresses #793 — enables add-to-app (AAR) use cases where the same Flutter module is embedded in multiple host apps with different version numbers.
release_versionalways stays the host app's version (for clean analytics).module_versionis a separate optional field used only for patch lookup.Companion PRs:
Test plan
assertArgsAreValidtests for Flutter version gating and git hash resolutiongetReleaseVersiontests for explicit and git-hash pathsshorebird_yaml_testformodule_versiondeserialization