diff --git a/lib/src/appcast.dart b/lib/src/appcast.dart index cfa1b747..8a4823e7 100644 --- a/lib/src/appcast.dart +++ b/lib/src/appcast.dart @@ -62,8 +62,10 @@ class Appcast { bestItem = item; } else { try { - final itemVersion = Version.parse(item.versionString!); - final bestItemVersion = Version.parse(bestItem!.versionString!); + final itemVersion = + Version.parse(item.versionString!.split('+').first); + final bestItemVersion = + Version.parse(bestItem!.versionString!.split('+').first); if (itemVersion > bestItemVersion) { bestItem = item; } @@ -93,8 +95,10 @@ class Appcast { bestItem = item; } else { try { - final itemVersion = Version.parse(item.versionString!); - final bestItemVersion = Version.parse(bestItem!.versionString!); + final itemVersion = + Version.parse(item.versionString!.split('+').first); + final bestItemVersion = + Version.parse(bestItem!.versionString!.split('+').first); if (itemVersion > bestItemVersion) { bestItem = item; } @@ -301,7 +305,8 @@ class AppcastItem { if (supported) { if (maximumSystemVersion != null) { try { - final maxVersion = Version.parse(maximumSystemVersion!); + final maxVersion = + Version.parse(maximumSystemVersion!.split('+').first); if (osVersion > maxVersion) { supported = false; } @@ -311,7 +316,8 @@ class AppcastItem { } if (supported && minimumSystemVersion != null) { try { - final minVersion = Version.parse(minimumSystemVersion!); + final minVersion = + Version.parse(minimumSystemVersion!.split('+').first); if (osVersion < minVersion) { supported = false; } @@ -323,7 +329,8 @@ class AppcastItem { minimumUpdateVersion != null && currentAppVersion != null) { try { - final minUpdateVersion = Version.parse(minimumUpdateVersion!); + final minUpdateVersion = + Version.parse(minimumUpdateVersion!.split('+').first); if (currentAppVersion < minUpdateVersion) { supported = false; } diff --git a/lib/src/upgrade_store_controller.dart b/lib/src/upgrade_store_controller.dart index 87808d34..952abaf5 100644 --- a/lib/src/upgrade_store_controller.dart +++ b/lib/src/upgrade_store_controller.dart @@ -47,7 +47,12 @@ class UpgraderAppStore extends UpgraderStore { final version = iTunes.version(response); if (version != null) { try { - appStoreVersion = Version.parse(version); + final normalized = version.split('+').first; + if (normalized != version && state.debugLogging) { + print( + "upgrader: version normalized: '$version' → '$normalized'"); + } + appStoreVersion = Version.parse(normalized); } catch (e) { if (state.debugLogging) { print( @@ -105,7 +110,12 @@ class UpgraderPlayStore extends UpgraderStore { final version = playStore.version(response); if (version != null) { try { - appStoreVersion = Version.parse(version); + final normalized = version.split('+').first; + if (normalized != version && state.debugLogging) { + print( + "upgrader: version normalized: '$version' → '$normalized'"); + } + appStoreVersion = Version.parse(normalized); } catch (e) { if (state.debugLogging) { print( @@ -120,7 +130,7 @@ class UpgraderPlayStore extends UpgraderStore { final mav = playStore.minAppVersion(response); if (mav != null) { try { - final minVersion = mav.toString(); + final minVersion = mav.toString().split('+').first; minAppVersion = Version.parse(minVersion); if (state.debugLogging) { @@ -227,7 +237,8 @@ class UpgraderAppcastStore extends UpgraderStore { try { if (criticalVersion.isNotEmpty && - installedVersion < Version.parse(criticalVersion)) { + installedVersion < + Version.parse(criticalVersion.split('+').first)) { isCriticalUpdate = true; } } catch (e) { @@ -239,7 +250,12 @@ class UpgraderAppcastStore extends UpgraderStore { if (bestItem.versionString != null) { try { - appStoreVersion = Version.parse(bestItem.versionString!); + final normalized = bestItem.versionString!.split('+').first; + if (normalized != bestItem.versionString && state.debugLogging) { + print( + "upgrader: version normalized: '${bestItem.versionString}' → '$normalized'"); + } + appStoreVersion = Version.parse(normalized); } catch (e) { if (state.debugLogging) { print( diff --git a/lib/src/upgrader.dart b/lib/src/upgrader.dart index 8b2cd757..1e62e644 100644 --- a/lib/src/upgrader.dart +++ b/lib/src/upgrader.dart @@ -262,13 +262,9 @@ class Upgrader with WidgetsBindingObserver { } // Determine the installed version of this app. - late Version installedVersion; - try { - installedVersion = Version.parse(state.packageInfo!.version); - } catch (e) { - if (state.debugLogging) { - print('upgrader: installedVersion exception: $e'); - } + final installedVersion = parseVersion( + state.packageInfo!.version, 'installedVersion', state.debugLogging); + if (installedVersion == null) { updateState(state.copyWithNull(versionInfo: null)); return null; } @@ -370,13 +366,10 @@ class Upgrader with WidgetsBindingObserver { var rv = false; final minVersion = state.minAppVersion ?? versionInfo?.minAppVersion; if (minVersion != null && state.packageInfo != null) { - try { - final installedVersion = Version.parse(state.packageInfo!.version); + final installedVersion = parseVersion( + state.packageInfo!.version, 'installedVersion', state.debugLogging); + if (installedVersion != null) { rv = installedVersion < minVersion; - } catch (e) { - if (state.debugLogging) { - print(e); - } } } return rv; @@ -424,10 +417,12 @@ class Upgrader with WidgetsBindingObserver { } try { - final installedVersion = Version.parse(state.packageInfo!.version); - - final available = versionInfo!.appStoreVersion! > installedVersion; - _updateAvailable = available ? versionInfo?.appStoreVersion : null; + final installedVersion = parseVersion( + state.packageInfo!.version, 'installedVersion', state.debugLogging); + if (installedVersion != null) { + final available = versionInfo!.appStoreVersion! > installedVersion; + _updateAvailable = available ? versionInfo?.appStoreVersion : null; + } } on Exception catch (e) { if (state.debugLogging) { print('upgrader: isUpdateAvailable: $e'); @@ -527,23 +522,13 @@ class Upgrader with WidgetsBindingObserver { } final versionAlerted = prefs.getString('lastVersionAlerted'); if (versionAlerted != null) { - try { - _lastVersionAlerted = Version.parse(versionAlerted); - } catch (e) { - if (state.debugLogging) { - print('upgrader: lastVersionAlerted exception: $e'); - } - } + _lastVersionAlerted = parseVersion( + versionAlerted, 'lastVersionAlerted', state.debugLogging); } final ignoredVersion = prefs.getString('userIgnoredVersion'); if (ignoredVersion != null) { - try { - _userIgnoredVersion = Version.parse(ignoredVersion); - } catch (e) { - if (state.debugLogging) { - print('upgrader: userIgnoredVersion exception: $e'); - } - } + _userIgnoredVersion = + parseVersion(ignoredVersion, 'userIgnoredVersion', state.debugLogging); } return true; @@ -581,11 +566,13 @@ class Upgrader with WidgetsBindingObserver { String? version, String name, bool debugLogging) { if (version == null) return null; try { - return Version.parse(version); + final normalized = version.split('+').first; + if (normalized != version && debugLogging) { + print("upgrader: version normalized: '$version' → '$normalized'"); + } + return Version.parse(normalized); } catch (e) { - // if (state.debugLogging) { print('upgrader: _parseVersion $name exception: $e'); - // } return null; } } diff --git a/test/upgrader_test.dart b/test/upgrader_test.dart index 6b94ee40..74d70d26 100644 --- a/test/upgrader_test.dart +++ b/test/upgrader_test.dart @@ -1375,6 +1375,75 @@ void main() { verifyMessages(UpgraderMessages(code: 'vi'), 'vi'); verifyMessages(UpgraderMessages(code: 'zh'), 'zh'); }, skip: false); + + test('parseVersion strips build metadata from version string', () { + final result = Upgrader.parseVersion('1.2.3+45', 'test', false); + expect(result, isNotNull); + expect(result, equals(Version.parse('1.2.3'))); + expect(result! > Version.parse('1.2.3'), isFalse); + }); + + test('parseVersion leaves clean version string unchanged', () { + final result = Upgrader.parseVersion('1.2.3', 'test', false); + expect(result, isNotNull); + expect(result, equals(Version.parse('1.2.3'))); + }); + + testWidgets( + 'isUpdateAvailable returns false when installed version has build metadata matching store version', + (WidgetTester tester) async { + await tester.runAsync(() async { + final client = MockITunesSearchClient.setupMockClient(); + final upgrader = Upgrader( + upgraderOS: MockUpgraderOS(ios: true), + client: client, + debugLogging: true, + ); + + upgrader.installPackageInfo( + packageInfo: PackageInfo( + appName: 'Upgrader', + packageName: 'com.larryaasen.upgrader', + version: '1.2.3+45', + buildNumber: '45')); + + expect(await upgrader.initialize(), isTrue); + + upgrader.updateState(upgrader.state.copyWith( + versionInfo: UpgraderVersionInfo( + appStoreVersion: Version.parse('1.2.3')))); + + expect(upgrader.isUpdateAvailable(), isFalse); + }); + }); + + testWidgets( + 'isUpdateAvailable returns true when installed version with build metadata is genuinely older', + (WidgetTester tester) async { + await tester.runAsync(() async { + final client = MockITunesSearchClient.setupMockClient(); + final upgrader = Upgrader( + upgraderOS: MockUpgraderOS(ios: true), + client: client, + debugLogging: true, + ); + + upgrader.installPackageInfo( + packageInfo: PackageInfo( + appName: 'Upgrader', + packageName: 'com.larryaasen.upgrader', + version: '1.2.2+99', + buildNumber: '99')); + + expect(await upgrader.initialize(), isTrue); + + upgrader.updateState(upgrader.state.copyWith( + versionInfo: UpgraderVersionInfo( + appStoreVersion: Version.parse('1.2.3')))); + + expect(upgrader.isUpdateAvailable(), isTrue); + }); + }); } void verifyMessages(UpgraderMessages messages, String code) {