diff --git a/packages/package_info_plus/package_info_plus/example/integration_test/package_info_plus_web_test.dart b/packages/package_info_plus/package_info_plus/example/integration_test/package_info_plus_web_test.dart index 1ba5fa7b48..f2d69285cc 100644 --- a/packages/package_info_plus/package_info_plus/example/integration_test/package_info_plus_web_test.dart +++ b/packages/package_info_plus/package_info_plus/example/integration_test/package_info_plus_web_test.dart @@ -48,7 +48,7 @@ void main() { group('Package Info Web', () { setUp(() { client = MockClient(); - plugin = PackageInfoPlusWebPlugin(client); + plugin = PackageInfoPlusWebPlugin(client, null, null, null); }); testWidgets('Get correct values when response status is 200', ( @@ -67,6 +67,37 @@ void main() { expect(versionMap.buildSignature, VERSION_JSON['build_signature']); }); + testWidgets('Prefer the compile-time version over version.json', ( + tester, + ) async { + when(client.get(any)).thenAnswer( + (_) => Future.value(http.Response(jsonEncode(VERSION_2_JSON), 200)), + ); + plugin = PackageInfoPlusWebPlugin(client, null, '1.0', '1'); + + final versionMap = await plugin.getAll(); + + expect(versionMap.appName, VERSION_2_JSON['app_name']); + expect(versionMap.packageName, VERSION_2_JSON['package_name']); + expect(versionMap.version, '1.0'); + expect(versionMap.buildNumber, '1'); + }); + + testWidgets('Keep the compile-time version when version.json fails', ( + tester, + ) async { + when( + client.get(any), + ).thenAnswer((_) => Future.value(http.Response('', 404))); + plugin = PackageInfoPlusWebPlugin(client, null, '1.0', '1'); + + final versionMap = await plugin.getAll(); + + expect(versionMap.appName, isEmpty); + expect(versionMap.version, '1.0'); + expect(versionMap.buildNumber, '1'); + }); + testWidgets('Get empty values when response status is not 200', ( tester, ) async { @@ -240,7 +271,7 @@ void main() { setUp(() { client = MockClient(); assetManagerMock = MockAssetManager(); - plugin = PackageInfoPlusWebPlugin(client, assetManagerMock); + plugin = PackageInfoPlusWebPlugin(client, assetManagerMock, null, null); }); testWidgets('Get correct values when using the AssetManager baseUrl', ( diff --git a/packages/package_info_plus/package_info_plus/lib/src/package_info_plus_web.dart b/packages/package_info_plus/package_info_plus/lib/src/package_info_plus_web.dart index 3e884cae36..cc3a63288c 100644 --- a/packages/package_info_plus/package_info_plus/lib/src/package_info_plus_web.dart +++ b/packages/package_info_plus/package_info_plus/lib/src/package_info_plus_web.dart @@ -8,16 +8,39 @@ import 'package:package_info_plus_platform_interface/package_info_data.dart'; import 'package:package_info_plus_platform_interface/package_info_platform_interface.dart'; import 'package:web/web.dart' as web; +/// The build name compiled into the running bundle. +/// +/// Injected by `flutter_tools` since Flutter 3.47 from the pubspec `version` +/// (or `--build-name`), and exposed by Flutter as `appBuildName`. Read through +/// the environment so older Flutter versions keep compiling. +const String? _compileTimeBuildName = bool.hasEnvironment('FLUTTER_BUILD_NAME') + ? String.fromEnvironment('FLUTTER_BUILD_NAME') + : null; + +/// The build number compiled into the running bundle, see +/// [_compileTimeBuildName]. +const String? _compileTimeBuildNumber = + bool.hasEnvironment('FLUTTER_BUILD_NUMBER') + ? String.fromEnvironment('FLUTTER_BUILD_NUMBER') + : null; + /// The web implementation of [PackageInfoPlatform]. /// /// This class implements the `package:package_info_plus` functionality for the web. class PackageInfoPlusWebPlugin extends PackageInfoPlatform { final Client? _client; final AssetManager _assetManager; - - /// Create plugin with http client and asset manager for testing purposes. - PackageInfoPlusWebPlugin([this._client, AssetManager? assetManagerMock]) - : _assetManager = assetManagerMock ?? assetManager; + final String? _buildName; + final String? _buildNumber; + + /// Create plugin with http client, asset manager and compile-time build + /// name and number for testing purposes. + PackageInfoPlusWebPlugin([ + this._client, + AssetManager? assetManagerMock, + this._buildName = _compileTimeBuildName, + this._buildNumber = _compileTimeBuildNumber, + ]) : _assetManager = assetManagerMock ?? assetManager; /// Registers this class as the default instance of [PackageInfoPlatform]. static void registerWith(Registrar registrar) { @@ -64,8 +87,13 @@ class PackageInfoPlusWebPlugin extends PackageInfoPlatform { return PackageInfoData( appName: versionMap['app_name'] ?? '', - version: versionMap['version'] ?? '', - buildNumber: versionMap['build_number'] ?? '', + // `version.json` describes the deployed bundle, which differs from the + // running one when the client is stale, so prefer the compile-time + // version embedded in the running bundle. + version: _buildName ?? versionMap['version'] ?? '', + buildNumber: _buildName != null + ? _buildNumber ?? '' + : versionMap['build_number'] ?? '', packageName: versionMap['package_name'] ?? '', // will remain empty on web buildSignature: '',