Skip to content

feat: support module_version for add-to-app AAR releases#3674

Open
eseidel wants to merge 29 commits intomainfrom
feat/aar-release-version
Open

feat: support module_version for add-to-app AAR releases#3674
eseidel wants to merge 29 commits intomainfrom
feat/aar-release-version

Conversation

@eseidel
Copy link
Copy Markdown
Contributor

@eseidel eseidel commented Apr 2, 2026

Summary

  • When --release-version is omitted for AAR releases, default to git commit short hash as both the server-side release version and the module version baked into the AAR
  • Pass module version to flutter build aar via SHOREBIRD_MODULE_VERSION env var; the Flutter tool writes it as module_version into the compiled shorebird.yaml
  • Add moduleVersion field to ShorebirdYaml schema (so the CLI accepts the field)
  • Add moduleVersion field to PatchCheckRequest protocol
  • Require Flutter >= 3.41.4 when --release-version is omitted (older Flutter ignores the env var)
  • Add moduleVersion parameter to buildAar() in artifact builder

Context

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_version always stays the host app's version (for clean analytics). module_version is a separate optional field used only for patch lookup.

Companion PRs:

Test plan

  • assertArgsAreValid tests for Flutter version gating and git hash resolution
  • getReleaseVersion tests for explicit and git-hash paths
  • shorebird_yaml_test for module_version deserialization
  • Verify non-AAR releases are unaffected

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
eseidel added 8 commits April 2, 2026 11:03
…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
Copy link
Copy Markdown

codecov bot commented Apr 2, 2026

Codecov Report

❌ Patch coverage is 0% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../src/messages/patch_check/patch_check_request.dart 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

eseidel added 3 commits April 2, 2026 13:30
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).
@eseidel eseidel marked this pull request as ready for review April 2, 2026 22:25
@eseidel eseidel requested a review from bdero April 2, 2026 22:25
@eseidel eseidel changed the title feat: decouple AAR release version from host app version feat: support module_version for add-to-app AAR releases Apr 2, 2026
eseidel added 3 commits April 2, 2026 15:38
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.
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.
eseidel added 10 commits April 2, 2026 16:30
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().
@bdero
Copy link
Copy Markdown
Member

bdero commented Apr 3, 2026

release_version always stays the host app's version (for clean analytics). module_version is a separate optional field used only for patch lookup.

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?

@eseidel
Copy link
Copy Markdown
Contributor Author

eseidel commented Apr 3, 2026

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?

@eseidel
Copy link
Copy Markdown
Contributor Author

eseidel commented Apr 3, 2026

So shorebird release aar --module-version=git take the output, and put it wherever it goes for your other two apps to consume and then they just get each built with gradel (or XCode) as before.

When you want to patch, you just then run shorebird patch aar --module-version=latest (I think I have to add that component).

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants