import 'package:flutter/foundation.dart'; import 'package:package_info_plus/package_info_plus.dart'; /// Single source of truth for the app's identity shown inside the running app. /// /// **Source of truth** for the version numbers is the `version:` field in /// `pubspec.yaml` (e.g. `1.0.0+1`). At runtime we read that value via /// `package_info_plus`, which Flutter populates from `pubspec.yaml` *unless* /// overridden at build time with `--build-name` / `--build-number`. /// /// If `package_info_plus` cannot resolve the values (e.g. running in a unit /// test that hasn't initialised the plugin platform), we fall back to the /// [fallbackVersion] constant. Keep that constant in sync with `pubspec.yaml` /// when you bump versions; the release process described in /// `docs/RELEASING.md` owns that update. class AppInfo { AppInfo._(); /// Hard-coded fallback. Must mirror the `version:` field in `pubspec.yaml`. /// Format: `MAJOR.MINOR.PATCH+BUILD`. static const String fallbackVersion = '1.0.0+1'; /// Cached result so we only hit the platform once. static PackageInfo? _cached; /// Asynchronously loads the package info, caching the result. static Future _load() async { return _cached ??= await PackageInfo.fromPlatform(); } /// Resolves the build version in the form `MAJOR.MINOR.PATCH+BUILD` /// (e.g. `1.0.0+1`). Falls back to [fallbackVersion] on error. static Future versionString() async { try { final info = await _load(); final name = info.version.isEmpty ? '0.0.0' : info.version; final build = info.buildNumber.isEmpty ? '0' : info.buildNumber; return '$name+$build'; } catch (e, st) { debugPrint('AppInfo.versionString() fell back to constant: $e\n$st'); return fallbackVersion; } } /// The user-facing `MAJOR.MINOR.PATCH` portion (e.g. `1.0.0`). static Future versionName() async { try { final info = await _load(); return info.version.isEmpty ? '0.0.0' : info.version; } catch (_) { // Extract the part before the '+' from the fallback. return fallbackVersion.split('+').first; } } /// The monotonically increasing `+BUILD` portion (e.g. `1`). static Future buildNumber() async { try { final info = await _load(); return info.buildNumber.isEmpty ? '0' : info.buildNumber; } catch (_) { return fallbackVersion.split('+').last; } } }