feat(package_info_plus): add opt-in compile-time package info accessor#3874
feat(package_info_plus): add opt-in compile-time package info accessor#3874Ortes wants to merge 2 commits into
Conversation
Adds an opt-in library, package_info_plus_environment.dart, exposing PackageInfoEnvironment.packageInfo. It returns the *running* app's PackageInfo: on web from compile-time PACKAGE_INFO_PLUS_* dart-defines, on every other platform by delegating to PackageInfo.fromPlatform(). On web there is no reliable runtime source for the running version: version.json is fetched from the server, so it reflects the deployed version rather than the executing (possibly cached) bundle, and the fetch can fail entirely (offline, CORS, hosting rewrites). The compile-time constants are embedded in the bundle and cannot diverge from it. A web build that omits PACKAGE_INFO_PLUS_VERSION fails to compile, so a misleading version can never ship silently. Native builds are unaffected. PackageInfo.fromPlatform() is unchanged and the new library is not exported by the package barrel, so this is purely additive and opt-in. Related: fluttercommunity#2675, fluttercommunity#225, fluttercommunity#456, flutter/flutter#149031.
e31c344 to
13e02bd
Compare
|
Re: CI status — the red checks here are pre-existing infrastructure failures, not regressions from this PR. Evidence: The jobs that actually exercise this change all pass:
The failing jobs fail identically on
The last ~6 This change is purely additive: a new, non-exported |
…allbacks PackageInfoEnvironment now resolves the web version from, in order: PACKAGE_INFO_PLUS_VERSION (explicit), FLUTTER_BUILD_NAME (flutter/flutter#187935, injected by flutter_tools like FLUTTER_APP_FLAVOR), and dart.package.version (dart-lang/sdk#38855). Once either upstream proposal lands, apps need no configuration at all.
|
Forward-compatibility note. This PR now also recognizes tool-provided version defines as fallbacks, so apps will need no configuration at all once their build front-end injects the version itself:
Resolution order is: explicit |
…tter#187935) The tool already injects `FLUTTER_VERSION`, `FLUTTER_CHANNEL`, framework/engine revisions (exposed as `FlutterVersion`) and `FLUTTER_APP_FLAVOR` (exposed as `appFlavor`) as dart-defines. The application's own `version:` from `pubspec.yaml` is the one missing field, even though the tool already parses it (`FlutterManifest.buildName`/`buildNumber`) and embeds it into `version.json`, `Info.plist` and `build.gradle` on every build. Without it, the *running* version is unknowable on the web: `version.json` is fetched from the server at runtime, so a stale cached client reports the freshly deployed version instead of its own, and version gates / update prompts built on `package_info_plus` silently fail for exactly the users they exist for (fluttercommunity/plus_plugins#2675). This PR: - injects `FLUTTER_BUILD_NAME` and `FLUTTER_BUILD_NUMBER` (the app's pubspec `version`, overridable via `--build-name`/`--build-number`) in `FlutterCommand.getBuildInfo`, following the `FLUTTER_APP_FLAVOR` pattern including its reserved-name guards; - exposes them as `appBuildName` / `appBuildNumber` constants in `package:flutter/services.dart` (new `src/services/app_version.dart`, same style as `flavor.dart` / `flutter_version.dart`); - adds tool tests (injection from pubspec, no injection without a version, environment/dart-define collision guards) and framework tests. Like all `String.fromEnvironment` constants, these are tree-shaken when unreferenced, so nothing ships in the binary unless the app reads them. `package_info_plus` is ready to consume these defines (fluttercommunity/plus_plugins#3874), which would make the fix transparent for the ecosystem. A companion proposal for the pure-Dart side (`dart compile`, servers/CLIs) is dart-lang/sdk#38855 — neither subsumes the other, since Flutter does not build through `dartdev`. Fixes flutter#187934 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
|
Resolved by flutter/flutter#187934 |
Description
On the web,
PackageInfo.fromPlatform()resolves the version by fetchingversion.jsonfrom the server at runtime (with a cache buster). That file reflects whatever is currently deployed — not the bundle actually executing in the browser. The two states routinely diverge:ClientException: Invalid content-length header [-1]when readingversion.jsonon a Firefox extension #3028), leaving every field empty.This makes the reported version actively misleading rather than merely missing — and the version is the whole point of the plugin. Its two canonical uses, showing the running version and checking whether an update is needed, are both defeated when the value is the server's. An update gate built on it can never fire for the very users it targets, since stale clients self-report as up to date.
This PR
Adds a small opt-in library,
package_info_plus_environment.dart, exposingPackageInfoEnvironment.packageInfo:PackageInfobuilt from compile-timePACKAGE_INFO_PLUS_*defines (flutter build web --dart-define=PACKAGE_INFO_PLUS_VERSION=1.2.3 ...). These are embedded in the running bundle and cannot diverge from it. A web build that omitsPACKAGE_INFO_PLUS_VERSIONfails to compile (akIsWeb-conditionalconstassert), so a misleading version can never ship silently.PackageInfo.fromPlatform(), which reads the installed binary and is already reliable. The defines are not required there.Design choices that keep this safe and non-breaking:
PackageInfo.fromPlatform()is untouched. No behavior change for existing users.package_info_plus_environment.dart. Apps that don't opt in are completely unaffected — no new build requirement is imposed package-wide.flutter analyzeis clean and the existing + new tests pass. The web compile-time enforcement is verified by a compilation test (a web build without the define does not compile) rather than a runtime test.Related Issues
ClientException: Invalid content-length header [-1]when readingversion.jsonon a Firefox extension #3028Checklist
CHANGELOG.mdnor the plugin version inpubspec.yamlfiles.flutter analyze) does not report any problems on my PR.Breaking Change