diff --git a/Classes/BITHockeyBaseManager.h b/Classes/BITHockeyBaseManager.h index 47950b90d5..ba530cc718 100644 --- a/Classes/BITHockeyBaseManager.h +++ b/Classes/BITHockeyBaseManager.h @@ -1,10 +1,30 @@ -// -// CNSHockeyBaseManager.h -// HockeySDK -// -// Created by Andreas Linde on 04.06.12. -// Copyright (c) 2012 __MyCompanyName__. All rights reserved. -// +/* + * Author: Andreas Linde + * + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ #import #import diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index 775f405f68..d0aca0a722 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -1,10 +1,30 @@ -// -// CNSHockeyBaseManager.m -// HockeySDK -// -// Created by Andreas Linde on 04.06.12. -// Copyright (c) 2012 __MyCompanyName__. All rights reserved. -// +/* + * Author: Andreas Linde + * + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ #import "HockeySDK.h" #import "HockeySDKPrivate.h" diff --git a/Classes/BITHockeyManager.h b/Classes/BITHockeyManager.h index c29653e4c8..813de922e0 100644 --- a/Classes/BITHockeyManager.h +++ b/Classes/BITHockeyManager.h @@ -36,6 +36,7 @@ @class BITHockeyBaseManager; @class BITCrashManager; @class BITUpdateManager; +@class BITStoreUpdateManager; @class BITFeedbackManager; /** @@ -238,6 +239,32 @@ @property (nonatomic, getter = isUpdateManagerDisabled) BOOL disableUpdateManager; +/** + Reference to the initialized BITStoreUpdateManager module + + Returns the BITStoreUpdateManager instance initialized by BITHockeyManager + + @see configureWithIdentifier:delegate: + @see configureWithBetaIdentifier:liveIdentifier:delegate: + @see startManager + @see disableStoreUpdateManager + */ +@property (nonatomic, strong, readonly) BITStoreUpdateManager *storeUpdateManager; + + +/** + Flag the determines whether the App Store Update Manager should be enabled + + If this flag is enabled, then checking for updates when the app runs from the + app store will be turned on! + + Please note that the Store Update Manager will be initialized anyway! + + *Default*: _NO_ + @see storeUpdateManager + */ +@property (nonatomic, getter = isStoreUpdateManagerEnabled) BOOL enableStoreUpdateManager; + /** Reference to the initialized BITFeedbackManager module diff --git a/Classes/BITHockeyManager.m b/Classes/BITHockeyManager.m index 3e430e0ca8..4facfd64f4 100644 --- a/Classes/BITHockeyManager.m +++ b/Classes/BITHockeyManager.m @@ -34,6 +34,7 @@ #import "BITHockeyBaseManagerPrivate.h" #import "BITCrashManagerPrivate.h" #import "BITUpdateManagerPrivate.h" +#import "BITStoreUpdateManagerPrivate.h" #import "BITFeedbackManagerPrivate.h" @interface BITHockeyManager () @@ -101,6 +102,7 @@ _disableCrashManager = NO; _disableUpdateManager = NO; + _enableStoreUpdateManager = NO; _disableFeedbackManager = NO; _appStoreEnvironment = NO; @@ -174,6 +176,15 @@ } [_updateManager performSelector:@selector(startManager) withObject:nil afterDelay:0.5f]; } + + // start StoreUpdateManager + if ([self isStoreUpdateManagerEnabled]) { + BITHockeyLog(@"INFO: Start StoreUpdateManager"); + if (_serverURL) { + [_storeUpdateManager setServerURL:_serverURL]; + } + [_storeUpdateManager performSelector:@selector(startManager) withObject:nil afterDelay:0.5f]; + } // start FeedbackManager if (![self isFeedbackManagerDisabled]) { @@ -203,6 +214,14 @@ } +- (void)setEnableStoreUpdateManager:(BOOL)enableStoreUpdateManager { + if (_storeUpdateManager) { + [_storeUpdateManager setEnableStoreUpdateManager:enableStoreUpdateManager]; + } + _enableStoreUpdateManager = enableStoreUpdateManager; +} + + - (void)setDisableFeedbackManager:(BOOL)disableFeedbackManager { if (_feedbackManager) { [_feedbackManager setDisableFeedbackManager:disableFeedbackManager]; @@ -247,6 +266,9 @@ BITHockeyLog(@"INFO: Setup UpdateManager"); _updateManager = [[BITUpdateManager alloc] initWithAppIdentifier:_appIdentifier isAppStoreEnvironemt:_appStoreEnvironment]; _updateManager.delegate = _delegate; + + BITHockeyLog(@"INFO: Setup StoreUpdateManager"); + _storeUpdateManager = [[BITStoreUpdateManager alloc] initWithAppIdentifier:_appIdentifier isAppStoreEnvironemt:_appStoreEnvironment]; BITHockeyLog(@"INFO: Setup FeedbackManager"); _feedbackManager = [[BITFeedbackManager alloc] initWithAppIdentifier:_appIdentifier isAppStoreEnvironemt:_appStoreEnvironment]; diff --git a/Classes/BITStoreUpdateManager.h b/Classes/BITStoreUpdateManager.h new file mode 100644 index 0000000000..37ab34fd39 --- /dev/null +++ b/Classes/BITStoreUpdateManager.h @@ -0,0 +1,133 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2013 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import +#import "BITHockeyBaseManager.h" + + +typedef enum { + BITStoreUpdateCheckDaily = 0, + BITStoreUpdateCheckWeekly = 1, + BITStoreUpdateCheckManually = 2 +} BITStoreUpdateSetting; + +/** + The store update manager module. + + This is the HockeySDK module for handling app updates when having your app released in the App Store. + + This module automatically disables itself when **NOT** running in an App Store build by default! + + When an update is detected, it will open the apps store page. + + */ + +@interface BITStoreUpdateManager : BITHockeyBaseManager + + +///----------------------------------------------------------------------------- +/// @name Update Checking +///----------------------------------------------------------------------------- + +// see BITHockeyStoreUpdateSetting-enum. Will be saved in user defaults. +// default value: BITStoreUpdateCheckDaily +/** + When to check for new updates. + + Defines when a the SDK should check if there is a new update available on the + server. This must be assigned one of the following: + + - `BITStoreUpdateCheckDaily`: Once a day + - `BITStoreUpdateCheckWeekly`: Once a week + - `BITStoreUpdateCheckManually`: Manually + + **Default**: BITStoreUpdateCheckDaily + + @warning When setting this to `BITStoreUpdateCheckManually` you need to either + invoke the update checking process yourself with `checkForUpdate` somehow, e.g. by + proving an update check button for the user or integrating the Update View into your + user interface. + @see countryCode + @see checkForUpdateOnLaunch + @see checkForUpdate + */ +@property (nonatomic, assign) BITStoreUpdateSetting updateSetting; + + +/** + Defines the store country the app is always available in, otherwise uses the users locale + + If this value is not defined, then it uses the device country if the current locale. + + If you are pre-defining a country and are releasing a new version on a specific date, + it can happen that users get an alert but the update is not yet available in their country! + + But if a user downloaded the app from another appstore than the locale is set and the app is not + available in the locales app store, then the user will never receive an update notification! + + More information about possible country codes is available here: http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 + + @see updateSetting + @see checkForUpdateOnLaunch + @see checkForUpdate + */ +@property (nonatomic, strong) NSString *countryCode; + + +/** + Flag that determines whether the automatic update checks should be done. + + If this is enabled the update checks will be performed automatically depending on the + `updateSetting` property. If this is disabled the `updateSetting` property will have + no effect, and checking for updates is totally up to be done by yourself. + + *Default*: _YES_ + + @warning When setting this to `NO` you need to invoke update checks yourself! + @see updateSetting + @see countryCode + @see checkForUpdate + */ +@property (nonatomic, assign, getter=isCheckingForUpdateOnLaunch) BOOL checkForUpdateOnLaunch; + + +// manually start an update check +/** + Check for an update + + Call this to trigger a check if there is a new update available on the HockeyApp servers. + + @see updateSetting + @see countryCode + @see checkForUpdateOnLaunch + */ +- (void)checkForUpdate; + + +@end diff --git a/Classes/BITStoreUpdateManager.m b/Classes/BITStoreUpdateManager.m new file mode 100644 index 0000000000..d67eb45175 --- /dev/null +++ b/Classes/BITStoreUpdateManager.m @@ -0,0 +1,338 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2013 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import +#import +#import "HockeySDK.h" +#import "HockeySDKPrivate.h" +#import "BITHockeyHelper.h" + +#import "BITHockeyBaseManagerPrivate.h" +#import "BITStoreUpdateManagerPrivate.h" + + +@implementation BITStoreUpdateManager { + NSString *_lastStoreVersion; + NSString *_newStoreVersion; + NSString *_appStoreURL; + NSString *_currentUUID; + + BOOL _updateAlertShowing; + BOOL _lastCheckFailed; + + BOOL _didSetupDidBecomeActiveNotifications; +} + + +#pragma mark - private + +- (void)reportError:(NSError *)error { + BITHockeyLog(@"ERROR: %@", [error localizedDescription]); + _lastCheckFailed = YES; +} + + +- (void)didBecomeActiveActions { + if ([self isStoreUpdateManagerEnabled] && [self isCheckingForUpdateOnLaunch]) { + [self checkForUpdate]; + } +} + +- (void)setupDidBecomeActiveNotifications { + if (!_didSetupDidBecomeActiveNotifications) { + NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter]; + [dnc addObserver:self selector:@selector(didBecomeActiveActions) name:UIApplicationDidBecomeActiveNotification object:nil]; + [dnc addObserver:self selector:@selector(didBecomeActiveActions) name:BITHockeyNetworkDidBecomeReachableNotification object:nil]; + _didSetupDidBecomeActiveNotifications = YES; + } +} + +- (void)cleanupDidBecomeActiveNotifications { + [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyNetworkDidBecomeReachableNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; +} + + +#pragma mark - Init + +- (id)init { + if ((self = [super init])) { + _checkInProgress = NO; + _updateAvailable = NO; + _lastCheckFailed = NO; + _enableStoreUpdateManager = NO; + _didSetupDidBecomeActiveNotifications = NO; + _updateAlertShowing = NO; + _lastStoreVersion = nil; + _newStoreVersion = nil; + _appStoreURL = nil; + _currentUUID = [[self executableUUID] copy]; + _countryCode = nil; + + // set defaults + self.checkForUpdateOnLaunch = YES; + self.updateSetting = BITStoreUpdateCheckDaily; + + if ([[NSUserDefaults standardUserDefaults] objectForKey:kBITStoreUpdateLastStoreVersion]) { + _lastStoreVersion = [[NSUserDefaults standardUserDefaults] objectForKey:kBITStoreUpdateLastStoreVersion]; + } + + if ([[NSUserDefaults standardUserDefaults] objectForKey:kBITStoreUpdateDateOfLastCheck]) { + self.lastCheck = [[NSUserDefaults standardUserDefaults] objectForKey:kBITStoreUpdateDateOfLastCheck]; + } + + if (!_lastCheck) { + self.lastCheck = [NSDate distantPast]; + } + + if (!BITHockeyBundle()) { + NSLog(@"[HockeySDK] WARNING: %@ is missing, make sure it is added!", BITHOCKEYSDK_BUNDLE); + } + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyNetworkDidBecomeReachableNotification object:nil]; + + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; +} + + +#pragma mark - Version + +- (BOOL)hasNewVersion:(NSDictionary *)dictionary { + _lastCheckFailed = YES; + + if ( [(NSDictionary *)[dictionary objectForKey:@"results"] count] > 0 ) { + _lastCheckFailed = NO; + + _newStoreVersion = [(NSDictionary *)[[dictionary objectForKey:@"results"] objectAtIndex:0] objectForKey:@"version"]; + _appStoreURL = [(NSDictionary *)[[dictionary objectForKey:@"results"] objectAtIndex:0] objectForKey:@"trackViewUrl"]; + + if (!_newStoreVersion || !_appStoreURL) { + return NO; + } else if (!_lastStoreVersion) { + [[NSUserDefaults standardUserDefaults] setObject:_currentUUID forKey:kBITStoreUpdateLastUUID]; + [[NSUserDefaults standardUserDefaults] setObject:_newStoreVersion forKey:kBITStoreUpdateLastStoreVersion]; + [[NSUserDefaults standardUserDefaults] synchronize]; + return NO; + } else { + NSComparisonResult comparissonResult = bit_versionCompare(_newStoreVersion, _lastStoreVersion); + + if (comparissonResult == NSOrderedDescending) { + return YES; + } else { + return NO; + } + + } + } + + return NO; +} + +- (BOOL)shouldCheckForUpdates { + BOOL checkForUpdate = NO; + + switch (self.updateSetting) { + case BITStoreUpdateCheckDaily: { + NSTimeInterval dateDiff = fabs([self.lastCheck timeIntervalSinceNow]); + if (dateDiff != 0) + dateDiff = dateDiff / (60*60*24); + + checkForUpdate = (dateDiff >= 1); + break; + } + case BITStoreUpdateCheckWeekly: { + NSTimeInterval dateDiff = fabs([self.lastCheck timeIntervalSinceNow]); + if (dateDiff != 0) + dateDiff = dateDiff / (60*60*24); + + checkForUpdate = (dateDiff >= 7); + break; + } + case BITStoreUpdateCheckManually: + checkForUpdate = NO; + break; + default: + break; + } + + return checkForUpdate; +} + + +#pragma mark - Update Check + +- (void)checkForUpdate { + if (![self isAppStoreEnvironment]) return; + if (![self isStoreUpdateManagerEnabled]) return; + if (self.isCheckInProgress) return; + + self.checkInProgress = YES; + + // do we need to update? + if (![self shouldCheckForUpdates]) { + BITHockeyLog(@"INFO: Update check not needed right now"); + self.checkInProgress = NO; + return; + } + + NSString *country = @""; + if (self.countryCode) { + country = [NSString stringWithFormat:@"&country=%@", self.countryCode]; + } else { + country = [NSString stringWithFormat:@"&country=%@", [(NSDictionary *)[NSLocale currentLocale] objectForKey: NSLocaleCountryCode]]; + } + // TODO: problem with worldwide is timed releases! + + NSString *appBundleIdentifier = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; + appBundleIdentifier = @"de.buzzworks.worldviewlive"; + + NSString *url = [NSString stringWithFormat:@"http://itunes.apple.com/lookup?bundleId=%@%@", + bit_URLEncodedString(appBundleIdentifier), + country]; + + BITHockeyLog(@"INFO: Sending request to %@", url); + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:1 timeoutInterval:10.0]; + [request setHTTPMethod:@"GET"]; + [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; + + [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *responseData, NSError *error){ + self.checkInProgress = NO; + + if (error) { + [self reportError:error]; + } else if ([responseData length]) { + NSString *responseString = [[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding]; + BITHockeyLog(@"INFO: Received API response: %@", responseString); + + if (!responseString || ![responseString dataUsingEncoding:NSUTF8StringEncoding]) { + return; + } + + NSError *error = nil; + NSDictionary *json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; + + // remember that we just checked the server + self.lastCheck = [NSDate date]; + + self.updateAvailable = [self hasNewVersion:json]; + if (_lastCheckFailed) return; + + if ([self isUpdateAvailable]) { + [self showUpdateAlert]; + } + } + }]; +} + + +// begin the startup process +- (void)startManager { + if (![self isAppStoreEnvironment]) return; + if (![self isStoreUpdateManagerEnabled]) return; + + BITHockeyLog(@"INFO: Start UpdateManager"); + + // did the user just update the version? + NSString *lastStoredUUID = nil; + if ([[NSUserDefaults standardUserDefaults] objectForKey:kBITStoreUpdateLastUUID]) { + lastStoredUUID = [[NSUserDefaults standardUserDefaults] objectForKey:kBITStoreUpdateLastUUID]; + if (_lastStoreVersion && lastStoredUUID && ![lastStoredUUID isEqualToString:_currentUUID]) { + // a new version has been installed, reset everything + [[NSUserDefaults standardUserDefaults] removeObjectForKey:kBITStoreUpdateLastStoreVersion]; + _lastStoreVersion = nil; + } + } + + if (lastStoredUUID && ![lastStoredUUID isEqualToString:_currentUUID]) { + [[NSUserDefaults standardUserDefaults] setObject:_currentUUID forKey:kBITStoreUpdateLastUUID]; + [[NSUserDefaults standardUserDefaults] synchronize]; + } + + if ([self isCheckingForUpdateOnLaunch] && [self shouldCheckForUpdates]) { + [self performSelector:@selector(checkForUpdate) withObject:nil afterDelay:1.0f]; + } + + [self setupDidBecomeActiveNotifications]; +} + + +#pragma mark - Alert + +- (void)showUpdateAlert { + if (!_updateAlertShowing) { + NSString *versionString = [NSString stringWithFormat:@"%@ %@", BITHockeyLocalizedString(@"UpdateVersion"), _newStoreVersion]; + + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"UpdateAvailable") + message:[NSString stringWithFormat:BITHockeyLocalizedString(@"UpdateAlertTextWithAppVersion"), versionString] + delegate:self + cancelButtonTitle:BITHockeyLocalizedString(@"UpdateIgnore") + otherButtonTitles:BITHockeyLocalizedString(@"UpdateRemindMe"), BITHockeyLocalizedString(@"UpdateShow"), nil + ]; + [alertView setTag:0]; + [alertView show]; + _updateAlertShowing = YES; + } +} + + +#pragma mark - Properties + +- (void)setLastCheck:(NSDate *)aLastCheck { + if (_lastCheck != aLastCheck) { + _lastCheck = [aLastCheck copy]; + + [[NSUserDefaults standardUserDefaults] setObject:self.lastCheck forKey:kBITStoreUpdateDateOfLastCheck]; + [[NSUserDefaults standardUserDefaults] synchronize]; + } +} + + +#pragma mark - UIAlertViewDelegate + +// invoke the selected action from the action sheet for a location element +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { + _updateAlertShowing = NO; + if (buttonIndex == [alertView cancelButtonIndex]) { + [[NSUserDefaults standardUserDefaults] setObject:self.lastCheck forKey:kBITStoreUpdateDateOfLastCheck]; + [[NSUserDefaults standardUserDefaults] synchronize]; + } else if (buttonIndex == [alertView firstOtherButtonIndex]) { + // Remind button + } else if (buttonIndex == [alertView firstOtherButtonIndex] + 1) { + // Show button + if (_appStoreURL) { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:_appStoreURL]]; + } + } +} + +@end diff --git a/Classes/BITStoreUpdateManagerPrivate.h b/Classes/BITStoreUpdateManagerPrivate.h new file mode 100644 index 0000000000..a4288d2ec2 --- /dev/null +++ b/Classes/BITStoreUpdateManagerPrivate.h @@ -0,0 +1,49 @@ +/* + * Author: Andreas Linde + * Peter Steinberger + * + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2011 Andreas Linde. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import + + +@interface BITStoreUpdateManager () { +} + +// is an update available? +@property (nonatomic, assign, getter=isUpdateAvailable) BOOL updateAvailable; + +// are we currently checking for updates? +@property (nonatomic, assign, getter=isCheckInProgress) BOOL checkInProgress; + +@property (nonatomic, copy) NSDate *lastCheck; + +// used by BITHockeyManager if disable status is changed +@property (nonatomic, getter = isStoreUpdateManagerEnabled) BOOL enableStoreUpdateManager; + +@end diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index 7480fa9515..8c7a152afb 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -40,6 +40,8 @@ #import "BITUpdateManagerDelegate.h" #import "BITUpdateViewController.h" +#import "BITStoreUpdateManager.h" + #import "BITFeedbackManager.h" #import "BITFeedbackActivity.h" #import "BITFeedbackComposeViewController.h" diff --git a/Classes/HockeySDKPrivate.h b/Classes/HockeySDKPrivate.h index b95bfbd0b2..95fd0d662f 100644 --- a/Classes/HockeySDKPrivate.h +++ b/Classes/HockeySDKPrivate.h @@ -52,6 +52,10 @@ #define kBITUpdateAuthorizedVersion @"BITUpdateAuthorizedVersion" #define kBITUpdateAuthorizedToken @"BITUpdateAuthorizedToken" +#define kBITStoreUpdateDateOfLastCheck @"BITStoreUpdateDateOfLastCheck" +#define kBITStoreUpdateLastStoreVersion @"BITStoreUpdateLastStoreVersion" +#define kBITStoreUpdateLastUUID @"BITStoreUpdateLastUUID" + #define BITHOCKEYSDK_BUNDLE @"HockeySDKResources.bundle" #define BITHOCKEYSDK_URL @"https://sdk.hockeyapp.net/" diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 5e93f406bf..673534ebd7 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -101,6 +101,9 @@ 1E754E5F1621FBB70070AB92 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */; }; 1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */; }; 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */; }; + 1E94F9E116E91330006570AD /* BITStoreUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E94F9DF16E91330006570AD /* BITStoreUpdateManager.h */; }; + 1E94F9E216E91330006570AD /* BITStoreUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E94F9E016E91330006570AD /* BITStoreUpdateManager.m */; }; + 1E94F9E416E9136B006570AD /* BITStoreUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E94F9E316E9136B006570AD /* BITStoreUpdateManagerPrivate.h */; }; 1EACC97B162F041E007578C5 /* BITAttributedLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EACC979162F041E007578C5 /* BITAttributedLabel.h */; }; 1EACC97C162F041E007578C5 /* BITAttributedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EACC97A162F041E007578C5 /* BITAttributedLabel.m */; }; 1EAF20A8162DC0F600957B1D /* feedbackActivity@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A4162DC0F600957B1D /* feedbackActivity@2x~ipad.png */; }; @@ -211,6 +214,9 @@ 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerPrivate.h; sourceTree = ""; }; 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashReportTextFormatter.h; sourceTree = ""; }; 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashReportTextFormatter.m; sourceTree = ""; }; + 1E94F9DF16E91330006570AD /* BITStoreUpdateManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITStoreUpdateManager.h; sourceTree = ""; }; + 1E94F9E016E91330006570AD /* BITStoreUpdateManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITStoreUpdateManager.m; sourceTree = ""; }; + 1E94F9E316E9136B006570AD /* BITStoreUpdateManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITStoreUpdateManagerPrivate.h; sourceTree = ""; }; 1EA512DF167F7EF000FC9FBA /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/HockeySDK.strings"; sourceTree = ""; }; 1EACC979162F041E007578C5 /* BITAttributedLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITAttributedLabel.h; sourceTree = ""; }; 1EACC97A162F041E007578C5 /* BITAttributedLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = BITAttributedLabel.m; sourceTree = ""; }; @@ -366,6 +372,16 @@ name = CrashReports; sourceTree = ""; }; + 1E94F9DE16E912DD006570AD /* StoreUpdate */ = { + isa = PBXGroup; + children = ( + 1E94F9DF16E91330006570AD /* BITStoreUpdateManager.h */, + 1E94F9E016E91330006570AD /* BITStoreUpdateManager.m */, + 1E94F9E316E9136B006570AD /* BITStoreUpdateManagerPrivate.h */, + ); + name = StoreUpdate; + sourceTree = ""; + }; E400560F148D79B500EB22B9 = { isa = PBXGroup; children = ( @@ -413,6 +429,7 @@ 1E754E551621FBAF0070AB92 /* CrashReports */, 1E754E461621FA9A0070AB92 /* Feedback */, 1E754E471621FAD00070AB92 /* Update */, + 1E94F9DE16E912DD006570AD /* StoreUpdate */, E41EB465148D7BF50015DEDC /* BITHockeyManager.h */, E41EB466148D7BF50015DEDC /* BITHockeyManager.m */, 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */, @@ -471,6 +488,8 @@ 1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */, 1EACC97B162F041E007578C5 /* BITAttributedLabel.h in Headers */, 1E0FEE28173BDB260061331F /* BITKeychainUtils.h in Headers */, + 1E94F9E116E91330006570AD /* BITStoreUpdateManager.h in Headers */, + 1E94F9E416E9136B006570AD /* BITStoreUpdateManagerPrivate.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -645,6 +664,7 @@ 1EF95CA7162CB037000AE3AD /* BITFeedbackActivity.m in Sources */, 1EACC97C162F041E007578C5 /* BITAttributedLabel.m in Sources */, 1E0FEE29173BDB260061331F /* BITKeychainUtils.m in Sources */, + 1E94F9E216E91330006570AD /* BITStoreUpdateManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };