From ecf9370db10ebdc001c24ae17835bcf2c05e5c78 Mon Sep 17 00:00:00 2001 From: EdisonJwa Date: Sun, 17 May 2026 01:18:06 +0800 Subject: [PATCH] fix(ui): preserve '-rc.8' in About dialog despite iOS version sanitisation (rc.8+65) Two related fixes for the version-display work landed at 97a6ba6: PROBLEM 1: build counter stuck at +59 on the device. The user reported the About dialog showed v1.0.0-rc.8+59 even though pubspec.yaml has been bumping (60 -> 61 -> 62 -> 63 -> 64). Root cause: Xcode caches ios/Flutter/Generated.xcconfig (which holds FLUTTER_BUILD_NUMBER) and doesn't regenerate it on Cmd+R unless inputs change. 'flutter pub get' also doesn't rewrite it. Only 'flutter build ios' or deleting the file forces regen. Fix (operational, not code-side): the Generated.xcconfig file on the Mac was deleted + regenerated and is now at FLUTTER_BUILD_NUMBER=64, so the next Xcode Run picks up the correct value. Going forward, if the build counter ever lags again the workaround is: rm ios/Flutter/Generated.xcconfig && flutter pub get before running from Xcode. We may add this to a build-doc note or a Makefile target during the rc.8 wrap-up. PROBLEM 2: 'v1.0.0-rc.8' was being displayed as 'v1.0.0.8'. CFBundleShortVersionString on iOS rejects non-numeric characters, so Flutter strips the '-rc.8' suffix to '.8' when populating Info.plist. package_info_plus.version reflects that mangled value. CFBundleVersion (the build counter) is passed through intact, so the issue affects only the semver half. Fix: split _kAppVersion resolution. Hardcode the semver baseline as _kSemverBaseline = 'v1.0.0-rc.8' (kept in sync with the git tag + pubspec semver portion; bumped once per release-candidate cycle, not per test build). Use package_info_plus for the '+' suffix only, where CFBundleVersion survives the sanitiser unchanged. Final display becomes 'v1.0.0-rc.8+' (e.g. 'v1.0.0-rc.8+65'). flutter analyze: clean. Build counter 64 -> 65. After Xcode Clean Build Folder + Run the About dialog should now read 'v1.0.0-rc.8+65' on the iPhone. --- apps/chanora_flutter/lib/main.dart | 56 ++++++++++++++++++------------ apps/chanora_flutter/pubspec.yaml | 2 +- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/apps/chanora_flutter/lib/main.dart b/apps/chanora_flutter/lib/main.dart index 7fa5867..e5fd2ea 100644 --- a/apps/chanora_flutter/lib/main.dart +++ b/apps/chanora_flutter/lib/main.dart @@ -37,21 +37,29 @@ bool get _isTouchOnlyPttHost { } /// Public version string shown in the About dialog. Resolved at -/// app init from `package_info_plus`, which reads the platform- -/// canonical version (iOS `CFBundleShortVersionString` + `CFBundleVersion`, -/// Android `versionName` + `versionCode`). Flutter populates both -/// from the SAME `pubspec.yaml` `version:` field, so whatever the -/// user sees in the About dialog is guaranteed to match the -/// commit that produced the build they're running. The "+build" -/// suffix is the post-`+` portion of the pubspec version and -/// distinguishes successive test builds during the iOS audio -/// rollout (every test commit bumps the build number). +/// app init by combining a hardcoded semver baseline (kept in sync +/// with the git tag and pubspec.yaml's `version:` field) with the +/// platform-canonical build counter from `package_info_plus`. /// -/// Initialised before `runApp` in `main()`. Falls back to the -/// hardcoded baseline if `PackageInfo.fromPlatform()` fails -/// (extremely unlikely — the platform channel call is a simple -/// constant lookup). -String _kAppVersion = 'v1.0.0-rc.8'; +/// Why hardcode the semver instead of reading the whole string +/// from `package_info_plus`: iOS rejects non-numeric characters +/// in `CFBundleShortVersionString` and Flutter therefore strips +/// `-rc.8` to `.8` when populating the Info.plist field. The +/// resulting `1.0.0.8` is technically valid on the App Store but +/// useless to humans tracking pre-release builds. +/// `package_info_plus.version` reflects that mangled value. The +/// build counter (`CFBundleVersion` / Android `versionCode`) does +/// pass through unmodified, so we use platform info for the +/// `+` suffix only and pair it with the human-readable +/// semver baseline that this codebase already maintains as the +/// canonical release identity. +/// +/// Bump `_kSemverBaseline` whenever the semver portion of +/// pubspec.yaml advances (e.g. rc.8 -> rc.9 -> 1.0.0). The +/// build-counter suffix changes automatically on every pubspec +/// `+` bump because Flutter writes it into Info.plist. +const String _kSemverBaseline = 'v1.0.0-rc.8'; +String _kAppVersion = _kSemverBaseline; Future main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -62,20 +70,22 @@ Future main() async { runApp(const ChanoraApp()); } -/// Populate `_kAppVersion` from the platform manifest. Format is -/// `v+` (e.g. `v1.0.0-rc.8+60`). The `+` is -/// the iOS `CFBundleVersion` / Android `versionCode`, kept in -/// sync with `pubspec.yaml`'s `version: +`. +/// Populate `_kAppVersion` by suffixing the platform-canonical +/// build number to `_kSemverBaseline`. Format: +/// `v1.0.0-rc.8+` (e.g. `v1.0.0-rc.8+64`). The build +/// number is iOS `CFBundleVersion` / Android `versionCode`, +/// kept in sync with pubspec.yaml's `version: +`. Future _resolveAppVersion() async { try { final info = await PackageInfo.fromPlatform(); - // info.version = "1.0.0-rc.8" (CFBundleShortVersionString) - // info.buildNumber = "60" (CFBundleVersion) + // info.buildNumber = "64" (CFBundleVersion on iOS; survives + // the iOS version-string sanitiser that mangles + // CFBundleShortVersionString). final build = info.buildNumber.isEmpty ? '' : '+${info.buildNumber}'; - _kAppVersion = 'v${info.version}$build'; + _kAppVersion = '$_kSemverBaseline$build'; } catch (_) { - // Keep the hardcoded fallback. Already-correct for the - // semver portion; only the build counter is lost. + // Keep the hardcoded baseline. The build counter is lost + // but the semver stays correct. } } diff --git a/apps/chanora_flutter/pubspec.yaml b/apps/chanora_flutter/pubspec.yaml index d14ad2f..924086f 100644 --- a/apps/chanora_flutter/pubspec.yaml +++ b/apps/chanora_flutter/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.0-rc.8+64 +version: 1.0.0-rc.8+65 environment: sdk: ^3.11.5