diff --git a/Classes/BITAppVersionMetaInfo.h b/Classes/BITAppVersionMetaInfo.h index f47897a890..7c1db67f5a 100644 --- a/Classes/BITAppVersionMetaInfo.h +++ b/Classes/BITAppVersionMetaInfo.h @@ -38,6 +38,8 @@ @property (nonatomic, copy) NSDate *date; @property (nonatomic, copy) NSNumber *size; @property (nonatomic, copy) NSNumber *mandatory; +@property (nonatomic, copy) NSNumber *versionID; +@property (nonatomic, copy) NSDictionary *uuids; - (NSString *)nameAndVersionString; - (NSString *)versionString; @@ -46,6 +48,7 @@ - (NSString *)notesOrEmptyString; - (void)setDateWithTimestamp:(NSTimeInterval)timestamp; - (BOOL)isValid; +- (BOOL)hasUUID:(NSString *)uuid; - (BOOL)isEqualToAppVersionMetaInfo:(BITAppVersionMetaInfo *)anAppVersionMetaInfo; + (BITAppVersionMetaInfo *)appVersionMetaInfoFromDict:(NSDictionary *)dict; diff --git a/Classes/BITAppVersionMetaInfo.m b/Classes/BITAppVersionMetaInfo.m index 22e4645d7d..7b1394fd84 100644 --- a/Classes/BITAppVersionMetaInfo.m +++ b/Classes/BITAppVersionMetaInfo.m @@ -33,14 +33,6 @@ @implementation BITAppVersionMetaInfo -@synthesize name = _name; -@synthesize version = _version; -@synthesize shortVersion = _shortVersion; -@synthesize notes = _notes; -@synthesize date = _date; -@synthesize size = _size; -@synthesize mandatory = _mandatory; - #pragma mark - Static @@ -55,6 +47,8 @@ appVersionMetaInfo.size = [dict objectForKey:@"appsize"]; appVersionMetaInfo.notes = [dict objectForKey:@"notes"]; appVersionMetaInfo.mandatory = [dict objectForKey:@"mandatory"]; + appVersionMetaInfo.versionID = [dict objectForKey:@"id"]; + appVersionMetaInfo.uuids = [dict objectForKey:@"uuids"]; } return appVersionMetaInfo; @@ -89,6 +83,8 @@ return NO; if (self.mandatory != anAppVersionMetaInfo.mandatory && ![self.mandatory isEqualToNumber:anAppVersionMetaInfo.mandatory]) return NO; + if (![self.uuids isEqualToDictionary:anAppVersionMetaInfo.uuids]) + return NO; return YES; } @@ -103,6 +99,8 @@ [encoder encodeObject:self.date forKey:@"date"]; [encoder encodeObject:self.size forKey:@"size"]; [encoder encodeObject:self.mandatory forKey:@"mandatory"]; + [encoder encodeObject:self.versionID forKey:@"versionID"]; + [encoder encodeObject:self.uuids forKey:@"uuids"]; } - (id)initWithCoder:(NSCoder *)decoder { @@ -114,6 +112,8 @@ self.date = [decoder decodeObjectForKey:@"date"]; self.size = [decoder decodeObjectForKey:@"size"]; self.mandatory = [decoder decodeObjectForKey:@"mandatory"]; + self.versionID = [decoder decodeObjectForKey:@"versionID"]; + self.uuids = [decoder decodeObjectForKey:@"uuids"]; } return self; } @@ -172,4 +172,19 @@ return valid; } +- (BOOL)hasUUID:(NSString *)uuid { + if (!uuid) return NO; + if (!self.uuids) return NO; + + __block BOOL hasUUID = NO; + + [self.uuids enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){ + if (obj && [uuid compare:obj] == NSOrderedSame) { + hasUUID = YES; + *stop = YES; + } + }]; + + return hasUUID; +} @end diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 2efad54974..0926b51016 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -52,7 +52,11 @@ BOOL _sendUsageData; BOOL _didSetupDidBecomeActiveNotifications; + + BOOL _firstStartAfterInstall; + NSNumber *_versionID; + NSString *_versionUUID; NSString *_uuid; } @@ -146,17 +150,17 @@ BOOL newVersion = NO; - if (![[NSUserDefaults standardUserDefaults] valueForKey:kBITUpdateUsageTimeForVersionString]) { + if (![[NSUserDefaults standardUserDefaults] valueForKey:kBITUpdateUsageTimeForUUID]) { newVersion = YES; } else { - if ([(NSString *)[[NSUserDefaults standardUserDefaults] valueForKey:kBITUpdateUsageTimeForVersionString] compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] != NSOrderedSame) { + if ([(NSString *)[[NSUserDefaults standardUserDefaults] valueForKey:kBITUpdateUsageTimeForUUID] compare:_uuid] != NSOrderedSame) { newVersion = YES; } } if (newVersion) { [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithDouble:[[NSDate date] timeIntervalSinceReferenceDate]] forKey:kBITUpdateDateOfVersionInstallation]; - [[NSUserDefaults standardUserDefaults] setObject:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:kBITUpdateUsageTimeForVersionString]; + [[NSUserDefaults standardUserDefaults] setObject:_uuid forKey:kBITUpdateUsageTimeForUUID]; [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithDouble:0] forKey:kBITUpdateUsageTimeOfCurrentVersion]; [[NSUserDefaults standardUserDefaults] synchronize]; } @@ -240,10 +244,55 @@ - (void)checkUpdateAvailable { // check if there is an update available - self.updateAvailable = (bit_versionCompare(self.newestAppVersion.version, self.currentAppVersion) == NSOrderedDescending); + NSComparisonResult comparissonResult = bit_versionCompare(self.newestAppVersion.version, self.currentAppVersion); + + if (comparissonResult == NSOrderedDescending) { + self.updateAvailable = YES; + } else if (comparissonResult == NSOrderedSame) { + // compare using the binary UUID and stored version id + self.updateAvailable = NO; + if (_firstStartAfterInstall) { + if ([self.newestAppVersion hasUUID:_uuid]) { + _versionUUID = [_uuid copy]; + _versionID = [self.newestAppVersion.versionID copy]; + [self saveAppCache]; + } else { + [self.appVersions enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if (idx > 0 && [obj isKindOfClass:[BITAppVersionMetaInfo class]]) { + NSComparisonResult compareVersions = bit_versionCompare([(BITAppVersionMetaInfo *)obj version], self.currentAppVersion); + BOOL uuidFound = [(BITAppVersionMetaInfo *)obj hasUUID:_uuid]; + + if (uuidFound) { + _versionUUID = [_uuid copy]; + _versionID = [[(BITAppVersionMetaInfo *)obj versionID] copy]; + [self saveAppCache]; + + self.updateAvailable = YES; + } + + if (compareVersions != NSOrderedSame || uuidFound) { + *stop = YES; + } + } + }]; + } + } else { + if ([self.newestAppVersion.versionID compare:_versionID] == NSOrderedDescending) + self.updateAvailable = YES; + } + } } - (void)loadAppCache { + _firstStartAfterInstall = NO; + _versionUUID = [[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateInstalledUUID]; + if (!_versionUUID) { + _firstStartAfterInstall = YES; + } else { + if ([_uuid compare:_versionUUID] != NSOrderedSame) + _firstStartAfterInstall = YES; + } + _versionID = [[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateInstalledVersionID]; _companyName = [[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateCurrentCompanyName]; NSData *savedHockeyData = [[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateArrayOfLastCheck]; @@ -262,6 +311,10 @@ - (void)saveAppCache { if (_companyName) [[NSUserDefaults standardUserDefaults] setObject:_companyName forKey:kBITUpdateCurrentCompanyName]; + if (_versionUUID) + [[NSUserDefaults standardUserDefaults] setObject:_versionUUID forKey:kBITUpdateInstalledUUID]; + if (_versionID) + [[NSUserDefaults standardUserDefaults] setObject:_versionID forKey:kBITUpdateInstalledVersionID]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.appVersions]; [[NSUserDefaults standardUserDefaults] setObject:data forKey:kBITUpdateArrayOfLastCheck]; [[NSUserDefaults standardUserDefaults] synchronize]; @@ -307,10 +360,13 @@ _authenticationSecret = nil; _lastCheck = nil; _uuid = [[self executableUUID] copy]; + _versionUUID = nil; + _versionID = nil; _sendUsageData = YES; _disableUpdateManager = NO; _checkForTracker = NO; _didSetupDidBecomeActiveNotifications = NO; + _firstStartAfterInstall = NO; _companyName = nil; // set defaults @@ -791,7 +847,7 @@ self.companyName = (([[json valueForKey:@"company"] isKindOfClass:[NSString class]]) ? [json valueForKey:@"company"] : nil); if (![self isAppStoreEnvironment]) { - NSArray *feedArray = (NSArray *)([self checkForTracker] ? [json valueForKey:@"versions"] : json); + NSArray *feedArray = (NSArray *)[json valueForKey:@"versions"]; self.receivedData = nil; self.urlConnection = nil; diff --git a/Classes/HockeySDKPrivate.h b/Classes/HockeySDKPrivate.h index f17574c80b..346482d74c 100644 --- a/Classes/HockeySDKPrivate.h +++ b/Classes/HockeySDKPrivate.h @@ -41,12 +41,14 @@ #define BITHOCKEY_FEEDBACK_SETTINGS @"BITFeedbackManager.plist" +#define kBITUpdateInstalledUUID @"BITUpdateInstalledUUID" +#define kBITUpdateInstalledVersionID @"BITUpdateInstalledVersionID" #define kBITUpdateCurrentCompanyName @"BITUpdateCurrentCompanyName" #define kBITUpdateArrayOfLastCheck @"BITUpdateArrayOfLastCheck" #define kBITUpdateDateOfLastCheck @"BITUpdateDateOfLastCheck" #define kBITUpdateDateOfVersionInstallation @"BITUpdateDateOfVersionInstallation" #define kBITUpdateUsageTimeOfCurrentVersion @"BITUpdateUsageTimeOfCurrentVersion" -#define kBITUpdateUsageTimeForVersionString @"BITUpdateUsageTimeForVersionString" +#define kBITUpdateUsageTimeForUUID @"BITUpdateUsageTimeForUUID" #define kBITUpdateAuthorizedVersion @"BITUpdateAuthorizedVersion" #define kBITUpdateAuthorizedToken @"BITUpdateAuthorizedToken"