1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438 |
- //
- // iVersion.m
- //
- // Version 1.11.5
- //
- // Created by Nick Lockwood on 26/01/2011.
- // Copyright 2011 Charcoal Design
- //
- // Distributed under the permissive zlib license
- // Get the latest version from here:
- //
- // https://github.com/nicklockwood/iVersion
- //
- // This software is provided 'as-is', without any express or implied
- // warranty. In no event will the authors be held liable for any damages
- // arising from the use of this software.
- //
- // Permission is granted to anyone to use this software for any purpose,
- // including commercial applications, and to alter it and redistribute it
- // freely, subject to the following restrictions:
- //
- // 1. The origin of this software must not be misrepresented; you must not
- // claim that you wrote the original software. If you use this software
- // in a product, an acknowledgment in the product documentation would be
- // appreciated but is not required.
- //
- // 2. Altered source versions must be plainly marked as such, and must not be
- // misrepresented as being the original software.
- //
- // 3. This notice may not be removed or altered from any source distribution.
- //
- #import "iVersion.h"
- #pragma clang diagnostic ignored "-Warc-repeated-use-of-weak"
- #pragma clang diagnostic ignored "-Wobjc-missing-property-synthesis"
- #pragma clang diagnostic ignored "-Wpartial-availability"
- #pragma clang diagnostic ignored "-Wundeclared-selector"
- #pragma clang diagnostic ignored "-Wdirect-ivar-access"
- #pragma clang diagnostic ignored "-Wdouble-promotion"
- #pragma clang diagnostic ignored "-Wunused-macros"
- #pragma clang diagnostic ignored "-Wconversion"
- #pragma clang diagnostic ignored "-Wselector"
- #pragma clang diagnostic ignored "-Wshadow"
- #pragma clang diagnostic ignored "-Wgnu"
- #import <Availability.h>
- #if !__has_feature(objc_arc)
- #error This class requires automatic reference counting
- #endif
- NSString *const iVersionErrorDomain = @"iVersionErrorDomain";
- NSString *const iVersionInThisVersionTitleKey = @"iVersionInThisVersionTitle";
- NSString *const iVersionUpdateAvailableTitleKey = @"iVersionUpdateAvailableTitle";
- NSString *const iVersionVersionLabelFormatKey = @"iVersionVersionLabelFormat";
- NSString *const iVersionOKButtonKey = @"iVersionOKButton";
- NSString *const iVersionIgnoreButtonKey = @"iVersionIgnoreButton";
- NSString *const iVersionRemindButtonKey = @"iVersionRemindButton";
- NSString *const iVersionDownloadButtonKey = @"iVersionDownloadButton";
- static NSString *const iVersionAppStoreIDKey = @"iVersionAppStoreID";
- static NSString *const iVersionLastVersionKey = @"iVersionLastVersionChecked";
- static NSString *const iVersionIgnoreVersionKey = @"iVersionIgnoreVersion";
- static NSString *const iVersionLastCheckedKey = @"iVersionLastChecked";
- static NSString *const iVersionLastRemindedKey = @"iVersionLastReminded";
- static NSString *const iVersionMacAppStoreBundleID = @"com.apple.appstore";
- static NSString *const iVersionAppLookupURLFormat = @"https://itunes.apple.com/%@/lookup";
- static NSString *const iVersioniOSAppStoreURLFormat = @"itms-apps://itunes.apple.com/app/id%@";
- static NSString *const iVersionMacAppStoreURLFormat = @"macappstore://itunes.apple.com/app/id%@";
- #define SECONDS_IN_A_DAY 86400.0
- #define MAC_APP_STORE_REFRESH_DELAY 5.0
- #define REQUEST_TIMEOUT 60.0
- @implementation NSString(iVersion)
- - (NSComparisonResult)compareVersion:(NSString *)version
- {
- return [self compare:version options:NSNumericSearch];
- }
- - (NSComparisonResult)compareVersionDescending:(NSString *)version
- {
- return (NSComparisonResult)(0 - [self compareVersion:version]);
- }
- @end
- @interface iVersion ()
- @property (nonatomic, copy) NSDictionary *remoteVersionsDict;
- @property (nonatomic, strong) NSError *downloadError;
- @property (nonatomic, copy) NSString *versionDetails;
- @property (nonatomic, strong) id visibleLocalAlert;
- @property (nonatomic, strong) id visibleRemoteAlert;
- @property (nonatomic, assign) BOOL checkingForNewVersion;
- @end
- @implementation iVersion
- + (void)load
- {
- // [self performSelectorOnMainThread:@selector(sharedInstance) withObject:nil waitUntilDone:NO];
- }
- + (iVersion *)sharedInstance
- {
- static iVersion *sharedInstance = nil;
- if (sharedInstance == nil)
- {
- sharedInstance = [[iVersion alloc] init];
- }
- return sharedInstance;
- }
- - (NSString *)localizedStringForKey:(NSString *)key withDefault:(NSString *)defaultString
- {
- static NSBundle *bundle = nil;
- if (bundle == nil)
- {
- NSString *bundlePath = [[NSBundle bundleForClass:[iVersion class]] pathForResource:@"iVersion" ofType:@"bundle"];
- if (self.useAllAvailableLanguages)
- {
- bundle = [NSBundle bundleWithPath:bundlePath];
- NSString *language = [[NSLocale preferredLanguages] count]? [NSLocale preferredLanguages][0]: @"en";
- if (![[bundle localizations] containsObject:language])
- {
- language = [language componentsSeparatedByString:@"-"][0];
- }
- if ([[bundle localizations] containsObject:language])
- {
- bundlePath = [bundle pathForResource:language ofType:@"lproj"];
- }
- }
- bundle = [NSBundle bundleWithPath:bundlePath] ?: [NSBundle mainBundle];
- }
- defaultString = [bundle localizedStringForKey:key value:defaultString table:nil];
- return [[NSBundle mainBundle] localizedStringForKey:key value:defaultString table:nil];
- }
- - (iVersion *)init
- {
- if ((self = [super init]))
- {
-
- #if TARGET_OS_IPHONE
-
- //register for iphone application events
- if (&UIApplicationWillEnterForegroundNotification)
- {
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(applicationWillEnterForeground)
- name:UIApplicationWillEnterForegroundNotification
- object:nil];
- }
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(didRotate)
- name:UIDeviceOrientationDidChangeNotification
- object:nil];
-
- #endif
-
- //get country
- self.appStoreCountry = [(NSLocale *)[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
- if ([self.appStoreCountry isEqualToString:@"150"])
- {
- self.appStoreCountry = @"eu";
- }
- else if ([[self.appStoreCountry stringByReplacingOccurrencesOfString:@"[A-Za-z]{2}" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, 2)] length])
- {
- self.appStoreCountry = @"us";
- }
- else if ([self.appStoreCountry isEqualToString:@"GI"])
- {
- self.appStoreCountry = @"GB";
- }
-
- //application version (use short version preferentially)
- self.applicationVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
- if ([self.applicationVersion length] == 0)
- {
- self.applicationVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:(__bridge NSString *)kCFBundleVersionKey];
- }
-
- //bundle id
- self.applicationBundleID = [[NSBundle mainBundle] bundleIdentifier];
-
- //default settings
- self.updatePriority = iVersionUpdatePriorityDefault;
- self.useAllAvailableLanguages = YES;
- self.onlyPromptIfMainWindowIsAvailable = YES;
- self.checkAtLaunch = YES;
- self.checkPeriod = 0.0f;
- self.remindPeriod = 1.0f;
-
- #ifdef DEBUG
-
- //enable verbose logging in debug mode
- self.verboseLogging = YES;
-
- #endif
-
- //app launched
- [self performSelectorOnMainThread:@selector(applicationLaunched) withObject:nil waitUntilDone:NO];
- }
- return self;
- }
- - (id<iVersionDelegate>)delegate
- {
- if (_delegate == nil)
- {
-
- #if TARGET_OS_IPHONE
- #define APP_CLASS UIApplication
- #else
- #define APP_CLASS NSApplication
- #endif
-
- _delegate = (id<iVersionDelegate>)[[APP_CLASS sharedApplication] delegate];
- }
- return _delegate;
- }
- - (NSString *)inThisVersionTitle
- {
- return _inThisVersionTitle ?: [self localizedStringForKey:iVersionInThisVersionTitleKey withDefault:@"New in this version"];
- }
- - (NSString *)updateAvailableTitle
- {
- return _updateAvailableTitle ?: [self localizedStringForKey:iVersionUpdateAvailableTitleKey withDefault:@"New version available"];
- }
- - (NSString *)versionLabelFormat
- {
- return _versionLabelFormat ?: [self localizedStringForKey:iVersionVersionLabelFormatKey withDefault:@"Version %@"];
- }
- - (NSString *)okButtonLabel
- {
- return _okButtonLabel ?: [self localizedStringForKey:iVersionOKButtonKey withDefault:@"OK"];
- }
- - (NSString *)ignoreButtonLabel
- {
- return _ignoreButtonLabel ?: [self localizedStringForKey:iVersionIgnoreButtonKey withDefault:@"Ignore"];
- }
- - (NSString *)downloadButtonLabel
- {
- return _downloadButtonLabel ?: [self localizedStringForKey:iVersionDownloadButtonKey withDefault:@"Download"];
- }
- - (NSString *)remindButtonLabel
- {
- return _remindButtonLabel ?: [self localizedStringForKey:iVersionRemindButtonKey withDefault:@"Remind Me Later"];
- }
- - (NSURL *)updateURL
- {
- if (_updateURL)
- {
- return _updateURL;
- }
-
- if (!self.appStoreID)
- {
- NSLog(@"iVersion error: No App Store ID was found for this application. If the application is not intended for App Store release then you must specify a custom updateURL.");
- }
-
- #if TARGET_OS_IPHONE
-
- return [NSURL URLWithString:[NSString stringWithFormat:iVersioniOSAppStoreURLFormat, @(self.appStoreID)]];
-
- #else
-
- return [NSURL URLWithString:[NSString stringWithFormat:iVersionMacAppStoreURLFormat, @(self.appStoreID)]];
-
- #endif
-
- }
- - (NSUInteger)appStoreID
- {
- return [[[NSUserDefaults standardUserDefaults] objectForKey:iVersionAppStoreIDKey] unsignedIntegerValue];
- }
- - (void)setAppStoreID:(NSUInteger)appStoreID
- {
- [[NSUserDefaults standardUserDefaults] setInteger:(NSInteger)appStoreID forKey:iVersionAppStoreIDKey];
- [[NSUserDefaults standardUserDefaults] synchronize];
- }
- - (NSDate *)lastChecked
- {
- return [[NSUserDefaults standardUserDefaults] objectForKey:iVersionLastCheckedKey];
- }
- - (void)setLastChecked:(NSDate *)date
- {
- [[NSUserDefaults standardUserDefaults] setObject:date forKey:iVersionLastCheckedKey];
- [[NSUserDefaults standardUserDefaults] synchronize];
- }
- - (NSDate *)lastReminded
- {
- return [[NSUserDefaults standardUserDefaults] objectForKey:iVersionLastRemindedKey];
- }
- - (void)setLastReminded:(NSDate *)date
- {
- [[NSUserDefaults standardUserDefaults] setObject:date forKey:iVersionLastRemindedKey];
- [[NSUserDefaults standardUserDefaults] synchronize];
- }
- - (NSString *)ignoredVersion
- {
- return [[NSUserDefaults standardUserDefaults] objectForKey:iVersionIgnoreVersionKey];
- }
- - (void)setIgnoredVersion:(NSString *)version
- {
- [[NSUserDefaults standardUserDefaults] setObject:version forKey:iVersionIgnoreVersionKey];
- [[NSUserDefaults standardUserDefaults] synchronize];
- }
- - (BOOL)viewedVersionDetails
- {
- return [[[NSUserDefaults standardUserDefaults] objectForKey:iVersionLastVersionKey] isEqualToString:self.applicationVersion];
- }
- - (void)setViewedVersionDetails:(BOOL)viewed
- {
- [[NSUserDefaults standardUserDefaults] setObject:(viewed? self.applicationVersion: nil) forKey:iVersionLastVersionKey];
- }
- - (void)dealloc
- {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- - (NSString *)lastVersion
- {
- return [[NSUserDefaults standardUserDefaults] objectForKey:iVersionLastVersionKey];
- }
- - (void)setLastVersion:(NSString *)version
- {
- [[NSUserDefaults standardUserDefaults] setObject:version forKey:iVersionLastVersionKey];
- [[NSUserDefaults standardUserDefaults] synchronize];
- }
- - (NSDictionary *)localVersionsDict
- {
- static NSDictionary *versionsDict = nil;
- if (versionsDict == nil)
- {
- if (self.localVersionsPlistPath == nil)
- {
- versionsDict = [[NSDictionary alloc] init]; //empty dictionary
- }
- else
- {
- NSString *versionsFile = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.localVersionsPlistPath];
- versionsDict = [[NSDictionary alloc] initWithContentsOfFile:versionsFile];
- if (!versionsDict)
- {
- // Get the path to versions plist in localized directory
- NSArray *pathComponents = [self.localVersionsPlistPath componentsSeparatedByString:@"."];
- versionsFile = ([pathComponents count] == 2) ? [[NSBundle mainBundle] pathForResource:pathComponents[0] ofType:pathComponents[1]] : nil;
- versionsDict = [[NSDictionary alloc] initWithContentsOfFile:versionsFile];
- }
- }
- }
- return versionsDict;
- }
- - (NSString *)mostRecentVersionInDict:(NSDictionary *)dict
- {
- return [[[dict allKeys] sortedArrayUsingSelector:@selector(compareVersion:)] lastObject];
- }
- - (NSString *)versionDetails:(NSString *)version inDict:(NSDictionary *)dict
- {
- if (self.versionDetailsDefault && ([self.versionDetailsDefault length] > 0)) {
- return self.versionDetailsDefault;
- }
- id versionData = dict[version];
- if ([versionData isKindOfClass:[NSString class]])
- {
- return versionData;
- }
- else if ([versionData isKindOfClass:[NSArray class]])
- {
- return [versionData componentsJoinedByString:@"\n"];
- }
- return nil;
- }
- - (NSString *)versionDetailsSince:(NSString *)lastVersion inDict:(NSDictionary *)dict
- {
- if (self.versionDetailsDefault && ([self.versionDetailsDefault length] > 0)) {
- return self.versionDetailsDefault;
- }
-
- if (self.previewMode)
- {
- lastVersion = @"0";
- }
- BOOL newVersionFound = NO;
- NSMutableString *details = [NSMutableString string];
- NSArray *versions = [[dict allKeys] sortedArrayUsingSelector:@selector(compareVersionDescending:)];
- for (NSString *version in versions)
- {
- if ([version compareVersion:lastVersion] == NSOrderedDescending)
- {
- newVersionFound = YES;
- if (self.groupNotesByVersion)
- {
- [details appendString:[self.versionLabelFormat stringByReplacingOccurrencesOfString:@"%@" withString:version]];
- [details appendString:@"\n\n"];
- }
- [details appendString:[self versionDetails:version inDict:dict] ?: @""];
- [details appendString:@"\n"];
- if (self.groupNotesByVersion)
- {
- [details appendString:@"\n"];
- }
- }
- }
- return newVersionFound? [details stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]: nil;
- }
- - (NSString *)versionDetails
- {
- if (!_versionDetails)
- {
- if (self.viewedVersionDetails)
- {
- self.versionDetails = [self versionDetails:self.applicationVersion inDict:[self localVersionsDict]];
- }
- else
- {
- self.versionDetails = [self versionDetailsSince:self.lastVersion inDict:[self localVersionsDict]];
- }
- }
- return _versionDetails;
- }
- - (NSString *)URLEncodedString:(NSString *)string
- {
- CFStringRef stringRef = CFBridgingRetain(string);
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- CFStringRef encoded = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
- stringRef,
- NULL,
- CFSTR("!*'\"();:@&=+$,/?%#[]% "),
- kCFStringEncodingUTF8);
- #pragma clang diagnostic pop
- CFRelease(stringRef);
- return CFBridgingRelease(encoded);
- }
- - (void)downloadedVersionsData
- {
-
- #if !TARGET_OS_IPHONE
-
- //only show when main window is available
- if (self.onlyPromptIfMainWindowIsAvailable && ![[NSApplication sharedApplication] mainWindow])
- {
- [self performSelector:@selector(downloadedVersionsData) withObject:nil afterDelay:0.5];
- return;
- }
-
- #endif
-
- if (self.checkingForNewVersion)
- {
- //no longer checking
- self.checkingForNewVersion = NO;
-
- //check if data downloaded
- if (!self.remoteVersionsDict)
- {
- //log the error
- if (self.downloadError)
- {
- NSLog(@"iVersion update check failed because: %@", [self.downloadError localizedDescription]);
- }
- else
- {
- NSLog(@"iVersion update check failed because an unknown error occured");
- }
-
- if ([self.delegate respondsToSelector:@selector(iVersionVersionCheckDidFailWithError:)])
- {
- [self.delegate iVersionVersionCheckDidFailWithError:self.downloadError];
- }
-
- //deprecated code path
- else if ([self.delegate respondsToSelector:@selector(iVersionVersionCheckFailed:)])
- {
- NSLog(@"iVersionVersionCheckFailed: delegate method is deprecated, use iVersionVersionCheckDidFailWithError: instead");
- [self.delegate performSelector:@selector(iVersionVersionCheckFailed:) withObject:self.downloadError];
- }
- return;
- }
-
- //get version details
- NSString *details = [self versionDetailsSince:self.applicationVersion inDict:self.remoteVersionsDict];
- NSString *mostRecentVersion = [self mostRecentVersionInDict:self.remoteVersionsDict];
- if (details)
- {
- //inform delegate of new version
- if ([self.delegate respondsToSelector:@selector(iVersionDidDetectNewVersion:details:)])
- {
- [self.delegate iVersionDidDetectNewVersion:mostRecentVersion details:details];
- }
-
- //deprecated code path
- else if ([self.delegate respondsToSelector:@selector(iVersionDetectedNewVersion:details:)])
- {
- NSLog(@"iVersionDetectedNewVersion:details: delegate method is deprecated, use iVersionDidDetectNewVersion:details: instead");
- [self.delegate performSelector:@selector(iVersionDetectedNewVersion:details:) withObject:mostRecentVersion withObject:details];
- }
-
- //check if ignored
- BOOL showDetails = ![self.ignoredVersion isEqualToString:mostRecentVersion] || self.previewMode;
- if (showDetails)
- {
- if ([self.delegate respondsToSelector:@selector(iVersionShouldDisplayNewVersion:details:)])
- {
- showDetails = [self.delegate iVersionShouldDisplayNewVersion:mostRecentVersion details:details];
- if (!showDetails && self.verboseLogging)
- {
- NSLog(@"iVersion did not display the new version because the iVersionShouldDisplayNewVersion:details: delegate method returned NO");
- }
- }
- }
- else if (self.verboseLogging)
- {
- NSLog(@"iVersion did not display the new version because it was marked as ignored");
- }
-
- //show details
- if (showDetails && !self.visibleRemoteAlert)
- {
- NSString *title = self.updateAvailableTitle;
- if (!self.groupNotesByVersion)
- {
- title = [title stringByAppendingFormat:@" (%@)", mostRecentVersion];
- }
-
- self.visibleRemoteAlert = [self showAlertWithTitle:title
- details:details
- defaultButton:self.downloadButtonLabel
- ignoreButton:[self showIgnoreButton]? self.ignoreButtonLabel: nil
- remindButton:[self showRemindButton]? self.remindButtonLabel: nil];
- }
- }
- else if ([self.delegate respondsToSelector:@selector(iVersionDidNotDetectNewVersion)])
- {
- [self.delegate iVersionDidNotDetectNewVersion];
- }
- }
- }
- - (BOOL)shouldCheckForNewVersion
- {
- //debug mode?
- if (!self.previewMode)
- {
- //check if within the reminder period
- if (self.lastReminded != nil)
- {
- //reminder takes priority over check period
- if ([[NSDate date] timeIntervalSinceDate:self.lastReminded] < self.remindPeriod * SECONDS_IN_A_DAY)
- {
- if (self.verboseLogging)
- {
- NSLog(@"iVersion did not check for a new version because the user last asked to be reminded less than %g days ago", self.remindPeriod);
- }
- return NO;
- }
- }
-
- //check if within the check period
- else if (self.lastChecked != nil && [[NSDate date] timeIntervalSinceDate:self.lastChecked] < self.checkPeriod * SECONDS_IN_A_DAY)
- {
- if (self.verboseLogging)
- {
- NSLog(@"iVersion did not check for a new version because the last check was less than %g days ago", self.checkPeriod);
- }
- return NO;
- }
- }
- else if (self.verboseLogging)
- {
- NSLog(@"iVersion debug mode is enabled - make sure you disable this for release");
- }
-
- //confirm with delegate
- if ([self.delegate respondsToSelector:@selector(iVersionShouldCheckForNewVersion)])
- {
- BOOL shouldCheck = [self.delegate iVersionShouldCheckForNewVersion];
- if (!shouldCheck && self.verboseLogging)
- {
- NSLog(@"iVersion did not check for a new version because the iVersionShouldCheckForNewVersion delegate method returned NO");
- }
- return shouldCheck;
- }
-
- //perform the check
- return YES;
- }
- - (NSString *)valueForKey:(NSString *)key inJSON:(id)json
- {
- if ([json isKindOfClass:[NSString class]])
- {
- //use legacy parser
- NSRange keyRange = [json rangeOfString:[NSString stringWithFormat:@"\"%@\"", key]];
- if (keyRange.location != NSNotFound)
- {
- NSInteger start = keyRange.location + keyRange.length;
- NSRange valueStart = [json rangeOfString:@":" options:(NSStringCompareOptions)0 range:NSMakeRange(start, [(NSString *)json length] - start)];
- if (valueStart.location != NSNotFound)
- {
- start = valueStart.location + 1;
- NSRange valueEnd = [json rangeOfString:@"," options:(NSStringCompareOptions)0 range:NSMakeRange(start, [(NSString *)json length] - start)];
- if (valueEnd.location != NSNotFound)
- {
- NSString *value = [json substringWithRange:NSMakeRange(start, valueEnd.location - start)];
- value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
- while ([value hasPrefix:@"\""] && ![value hasSuffix:@"\""])
- {
- if (valueEnd.location == NSNotFound)
- {
- break;
- }
- NSInteger newStart = valueEnd.location + 1;
- valueEnd = [json rangeOfString:@"," options:(NSStringCompareOptions)0 range:NSMakeRange(newStart, [(NSString *)json length] - newStart)];
- value = [json substringWithRange:NSMakeRange(start, valueEnd.location - start)];
- value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
- }
-
- value = [value stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\""]];
- value = [value stringByReplacingOccurrencesOfString:@"\\\\" withString:@"\\"];
- value = [value stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"];
- value = [value stringByReplacingOccurrencesOfString:@"\\\"" withString:@"\""];
- value = [value stringByReplacingOccurrencesOfString:@"\\n" withString:@"\n"];
- value = [value stringByReplacingOccurrencesOfString:@"\\r" withString:@"\r"];
- value = [value stringByReplacingOccurrencesOfString:@"\\t" withString:@"\t"];
- value = [value stringByReplacingOccurrencesOfString:@"\\f" withString:@"\f"];
- value = [value stringByReplacingOccurrencesOfString:@"\\b" withString:@"\f"];
-
- while (YES)
- {
- NSRange unicode = [value rangeOfString:@"\\u"];
- if (unicode.location == NSNotFound || unicode.location + unicode.length == 0)
- {
- break;
- }
-
- uint32_t c = 0;
- NSString *hex = [value substringWithRange:NSMakeRange(unicode.location + 2, 4)];
- NSScanner *scanner = [NSScanner scannerWithString:hex];
- [scanner scanHexInt:&c];
-
- if (c <= 0xffff)
- {
- value = [value stringByReplacingCharactersInRange:NSMakeRange(unicode.location, 6) withString:[NSString stringWithFormat:@"%C", (unichar)c]];
- }
- else
- {
- //convert character to surrogate pair
- uint16_t x = (uint16_t)c;
- uint16_t u = (c >> 16) & ((1 << 5) - 1);
- uint16_t w = (uint16_t)u - 1;
- unichar high = 0xd800 | (w << 6) | x >> 10;
- unichar low = (uint16_t)(0xdc00 | (x & ((1 << 10) - 1)));
-
- value = [value stringByReplacingCharactersInRange:NSMakeRange(unicode.location, 6) withString:[NSString stringWithFormat:@"%C%C", high, low]];
- }
- }
- return value;
- }
- }
- }
- }
- else
- {
- return json[key];
- }
- return nil;
- }
- - (void)setAppStoreIDOnMainThread:(NSString *)appStoreIDString
- {
- self.appStoreID = [appStoreIDString longLongValue];
- }
- - (void)checkForNewVersionInBackground
- {
- @synchronized (self)
- {
- @autoreleasepool
- {
- BOOL newerVersionAvailable = NO;
- BOOL osVersionSupported = NO;
- NSString *latestVersion = nil;
- NSDictionary *versions = nil;
-
- //first check iTunes
- NSString *iTunesServiceURL = [NSString stringWithFormat:iVersionAppLookupURLFormat, self.appStoreCountry];
- if (self.appStoreID)
- {
- iTunesServiceURL = [iTunesServiceURL stringByAppendingFormat:@"?id=%@", @(self.appStoreID)];
- }
- else
- {
- iTunesServiceURL = [iTunesServiceURL stringByAppendingFormat:@"?bundleId=%@", self.applicationBundleID];
- }
-
- if (self.verboseLogging)
- {
- NSLog(@"iVersion is checking %@ for a new app version...", iTunesServiceURL);
- }
-
- NSError *error = nil;
- NSURLResponse *response = nil;
- NSURL *url = [NSURL URLWithString:iTunesServiceURL];
- NSURLRequest *request = [NSURLRequest requestWithURL:url
- cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
- timeoutInterval:REQUEST_TIMEOUT];
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
- #pragma clang diagnostic pop
- NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
- if (data && statusCode == 200)
- {
- //in case error is garbage...
- error = nil;
-
- id json = nil;
- if ([NSJSONSerialization class])
- {
- json = [[NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingOptions)0 error:&error][@"results"] lastObject];
- }
- else
- {
- //convert to string
- json = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- }
-
- if (!error)
- {
- //check bundle ID matches
- NSString *bundleID = [self valueForKey:@"bundleId" inJSON:json];
- if (bundleID)
- {
- if ([bundleID isEqualToString:self.applicationBundleID])
- {
- //get supported OS version
- NSString *minimumSupportedOSVersion = [self valueForKey:@"minimumOsVersion" inJSON:json];
-
- #if TARGET_OS_IPHONE
-
- NSString *systemVersion = [UIDevice currentDevice].systemVersion;
-
- #else
- NSString *systemVersion = nil;
-
- #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1100
-
- if ([[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)])
- {
- NSOperatingSystemVersion version = [NSProcessInfo processInfo].operatingSystemVersion;
- systemVersion = [NSString stringWithFormat:@"%zd.%zd.%zd", version.majorVersion, version.minorVersion, version.patchVersion];
- }
- else
- #endif
- {
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
- SInt32 majorVersion = 0, minorVersion = 0, patchVersion = 0;
- Gestalt(gestaltSystemVersionMajor, &majorVersion);
- Gestalt(gestaltSystemVersionMinor, &minorVersion);
- Gestalt(gestaltSystemVersionBugFix, &patchVersion);
- systemVersion = [NSString stringWithFormat:@"%d.%d.%d", majorVersion, minorVersion, patchVersion];
-
- #pragma clang diagnostic pop
-
- }
- #endif
- osVersionSupported = ([systemVersion compare:minimumSupportedOSVersion options:NSNumericSearch] != NSOrderedAscending);
- if (!osVersionSupported)
- {
- error = [NSError errorWithDomain:iVersionErrorDomain
- code:iVersionErrorOSVersionNotSupported
- userInfo:@{NSLocalizedDescriptionKey: @"Current OS version is not supported."}];
- }
- //get version details
- NSString *releaseNotes = [self valueForKey:@"releaseNotes" inJSON:json];
- latestVersion = [self valueForKey:@"version" inJSON:json];
- if (latestVersion && osVersionSupported)
- {
- versions = @{latestVersion: releaseNotes ?: @""};
- }
-
- //get app id
- if (!self.appStoreID)
- {
- NSString *appStoreIDString = [self valueForKey:@"trackId" inJSON:json];
- [self performSelectorOnMainThread:@selector(setAppStoreIDOnMainThread:) withObject:appStoreIDString waitUntilDone:YES];
-
- if (self.verboseLogging)
- {
- NSLog(@"iVersion found the app on iTunes. The App Store ID is %@", appStoreIDString);
- }
- }
- //check for new version
- newerVersionAvailable = ([latestVersion compareVersion:self.applicationVersion] == NSOrderedDescending);
- if (self.verboseLogging)
- {
- if (newerVersionAvailable)
- {
- NSLog(@"iVersion found a new version (%@) of the app on iTunes. Current version is %@", latestVersion, self.applicationVersion);
- }
- else
- {
- NSLog(@"iVersion did not find a new version of the app on iTunes. Current version is %@, latest version is %@", self.applicationVersion, latestVersion);
- }
- }
- }
- else
- {
- if (self.verboseLogging)
- {
- NSLog(@"iVersion found that the application bundle ID (%@) does not match the bundle ID of the app found on iTunes (%@) with the specified App Store ID (%@)", self.applicationBundleID, bundleID, @(self.appStoreID));
- }
-
- error = [NSError errorWithDomain:iVersionErrorDomain
- code:iVersionErrorBundleIdDoesNotMatchAppStore
- userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Application bundle ID does not match expected value of %@", bundleID]}];
- }
- }
- else if (self.appStoreID || !self.remoteVersionsPlistURL)
- {
- if (self.verboseLogging)
- {
- NSLog(@"iVersion could not find this application on iTunes. If your app is not intended for App Store release then you must specify a remoteVersionsPlistURL. If this is the first release of your application then it's not a problem that it cannot be found on the store yet");
- }
-
- error = [NSError errorWithDomain:iVersionErrorDomain
- code:iVersionErrorApplicationNotFoundOnAppStore
- userInfo:@{NSLocalizedDescriptionKey: @"The application could not be found on the App Store."}];
- }
- else if (!self.appStoreID && self.verboseLogging)
- {
- NSLog(@"iVersion could not find your app on iTunes. If your app is not yet on the store or is not intended for App Store release then don't worry about this");
- }
- //now check plist for alternative release notes
- if (((self.appStoreID && newerVersionAvailable && osVersionSupported) || !self.appStoreID || self.previewMode) && self.remoteVersionsPlistURL)
- {
- if (self.verboseLogging)
- {
- NSLog(@"iVersion will check %@ for %@", self.remoteVersionsPlistURL, self.appStoreID? @"release notes": @"a new app version");
- }
- NSURL *url = [NSURL URLWithString:self.remoteVersionsPlistURL];
- NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:REQUEST_TIMEOUT];
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
- #pragma clang diagnostic pop
- if (data)
- {
- NSPropertyListFormat format;
- NSDictionary *plistVersions = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:&format error:&error];
-
- if (latestVersion)
- {
- //remove versions that are greater than latest in app store
- NSMutableDictionary *versions = [NSMutableDictionary dictionary];
- for (NSString *version in plistVersions)
- {
- if ([version compareVersion:latestVersion] != NSOrderedDescending)
- {
- versions[version] = plistVersions[version];
- }
- }
- plistVersions = versions;
- }
- if (!latestVersion || plistVersions[latestVersion] || !_useAppStoreDetailsIfNoPlistEntryFound)
- {
- versions = [plistVersions copy];
- }
- }
- else if (self.verboseLogging)
- {
- NSLog(@"iVersion was unable to download the user-specified release notes");
- }
- }
- }
- else if (statusCode >= 400)
- {
- //http error
- NSString *message = [NSString stringWithFormat:@"The server returned a %@ error", @(statusCode)];
- error = [NSError errorWithDomain:@"HTTPResponseErrorDomain" code:statusCode userInfo:@{NSLocalizedDescriptionKey: message}];
- }
- }
- [self performSelectorOnMainThread:@selector(setDownloadError:) withObject:error waitUntilDone:YES];
- [self performSelectorOnMainThread:@selector(setRemoteVersionsDict:) withObject:versions waitUntilDone:YES];
- [self performSelectorOnMainThread:@selector(setLastChecked:) withObject:[NSDate date] waitUntilDone:YES];
- [self performSelectorOnMainThread:@selector(downloadedVersionsData) withObject:nil waitUntilDone:YES];
- }
- }
- }
- - (void)checkForNewVersion
- {
- if (!self.checkingForNewVersion)
- {
- self.checkingForNewVersion = YES;
- [self performSelectorInBackground:@selector(checkForNewVersionInBackground) withObject:nil];
- }
- }
- - (void)checkIfNewVersion
- {
-
- #if !TARGET_OS_IPHONE
-
- //only show when main window is available
- if (self.onlyPromptIfMainWindowIsAvailable && ![[NSApplication sharedApplication] mainWindow])
- {
- [self performSelector:@selector(checkIfNewVersion) withObject:nil afterDelay:0.5];
- return;
- }
-
- #endif
-
- if (self.lastVersion != nil || self.showOnFirstLaunch || self.previewMode)
- {
- if ([self.applicationVersion compareVersion:self.lastVersion] == NSOrderedDescending || self.previewMode)
- {
- //clear reminder
- self.lastReminded = nil;
-
- //get version details
- BOOL showDetails = !!self.versionDetails;
- if (showDetails && [self.delegate respondsToSelector:@selector(iVersionShouldDisplayCurrentVersionDetails:)])
- {
- showDetails = [self.delegate iVersionShouldDisplayCurrentVersionDetails:self.versionDetails];
- }
-
- //show details
- if (showDetails && !self.visibleLocalAlert && !self.visibleRemoteAlert)
- {
- self.visibleLocalAlert = [self showAlertWithTitle:self.inThisVersionTitle
- details:self.versionDetails
- defaultButton:self.okButtonLabel
- ignoreButton:nil
- remindButton:nil];
- }
- }
- }
- else
- {
- //record this as last viewed release
- self.viewedVersionDetails = YES;
- }
- }
- - (BOOL)showIgnoreButton
- {
- return [self.ignoreButtonLabel length] && self.updatePriority < iVersionUpdatePriorityMedium;
- }
- - (BOOL)showRemindButton
- {
- return [self.remindButtonLabel length] && self.updatePriority < iVersionUpdatePriorityHigh;
- }
- - (id)showAlertWithTitle:(NSString *)title
- details:(NSString *)details
- defaultButton:(NSString *)defaultButton
- ignoreButton:(NSString *)ignoreButton
- remindButton:(NSString *)remindButton
- {
-
- #if TARGET_OS_IPHONE
-
- UIViewController *topController = [UIApplication sharedApplication].delegate.window.rootViewController;
- while (topController.presentedViewController)
- {
- topController = topController.presentedViewController;
- }
-
- if ([UIAlertController class] && topController && self.useUIAlertControllerIfAvailable)
- {
- UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:details preferredStyle:UIAlertControllerStyleAlert];
-
- //download/ok action
- [alert addAction:[UIAlertAction actionWithTitle:self.downloadButtonLabel style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) {
- [self didDismissAlert:alert withButtonAtIndex:0];
- }]];
-
- //ignore action
- if ([self showIgnoreButton])
- {
- [alert addAction:[UIAlertAction actionWithTitle:self.ignoreButtonLabel style:UIAlertActionStyleCancel handler:^(__unused UIAlertAction *action) {
- [self didDismissAlert:alert withButtonAtIndex:1];
- }]];
- }
-
- //remind action
- if ([self showRemindButton])
- {
- [alert addAction:[UIAlertAction actionWithTitle:self.remindButtonLabel style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) {
- [self didDismissAlert:alert withButtonAtIndex:[self showIgnoreButton]? 2: 1];
- }]];
- }
-
- //get current view controller and present alert
- [topController presentViewController:alert animated:YES completion:NULL];
-
- return alert;
- }
- else
- {
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
- message:details
- delegate:(id<UIAlertViewDelegate>)self
- cancelButtonTitle:nil
- otherButtonTitles:defaultButton, nil];
- if (ignoreButton)
- {
- [alert addButtonWithTitle:ignoreButton];
- alert.cancelButtonIndex = 1;
- }
-
- if (remindButton)
- {
- [alert addButtonWithTitle:remindButton];
- }
-
- [alert show];
-
- return alert;
- }
-
- #else
-
- NSAlert *alert = [[NSAlert alloc] init];
- alert.messageText = title;
- alert.informativeText = self.inThisVersionTitle;
- [alert addButtonWithTitle:defaultButton];
-
- NSScrollView *scrollview = [[NSScrollView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 380.0, 15.0)];
- NSSize contentSize = [scrollview contentSize];
- scrollview.borderType = NSBezelBorder;
- scrollview.hasVerticalScroller = YES;
- scrollview.hasHorizontalScroller = NO;
- scrollview.autoresizingMask = (NSAutoresizingMaskOptions)(NSViewWidthSizable|NSViewHeightSizable);
-
- NSTextView *textView = [[NSTextView alloc] initWithFrame:NSMakeRect(0.0, 0.0, contentSize.width, contentSize.height)];
- textView.minSize = NSMakeSize(0.0, contentSize.height);
- textView.maxSize = NSMakeSize(FLT_MAX, FLT_MAX);
- textView.verticallyResizable = YES;
- textView.horizontallyResizable = NO;
- textView.autoresizingMask = NSViewWidthSizable;
- textView.textContainer.containerSize = NSMakeSize(contentSize.width, FLT_MAX);
- textView.textContainer.widthTracksTextView = YES;
- textView.string = details;
- textView.editable = NO;
- scrollview.documentView = textView;
- [textView sizeToFit];
-
- CGFloat height = MIN(200.0, [[scrollview documentView] frame].size.height) + 3.0;
- scrollview.frame = NSMakeRect(0.0, 0.0, scrollview.frame.size.width, height);
- alert.accessoryView = scrollview;
-
- if (ignoreButton)
- {
- [alert addButtonWithTitle:ignoreButton];
- }
-
- if (remindButton)
- {
- [alert addButtonWithTitle:remindButton];
- }
-
- #if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9
-
- if (![alert respondsToSelector:@selector(beginSheetModalForWindow:completionHandler:)])
- {
- [alert beginSheetModalForWindow:(id __nonnull)[NSApplication sharedApplication].mainWindow
- modalDelegate:self
- didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
- contextInfo:nil];
- }
- else
-
- #endif
-
- {
- [alert beginSheetModalForWindow:(id __nonnull)[NSApplication sharedApplication].mainWindow completionHandler:^(NSModalResponse returnCode) {
- [self didDismissAlert:alert withButtonAtIndex:returnCode - NSAlertFirstButtonReturn];
- }];
- }
-
- return alert;
-
- #endif
-
- }
- - (void)didDismissAlert:(id)alertView withButtonAtIndex:(NSInteger)buttonIndex
- {
- //get button indices
- NSInteger downloadButtonIndex = 0;
- NSInteger ignoreButtonIndex = [self showIgnoreButton]? 1: 0;
- NSInteger remindButtonIndex = [self showRemindButton]? ignoreButtonIndex + 1: 0;
-
- //latest version
- NSString *latestVersion = [self mostRecentVersionInDict:self.remoteVersionsDict];
-
- if (alertView == self.visibleLocalAlert)
- {
- //record that details have been viewed
- self.viewedVersionDetails = YES;
-
- //release alert
- self.visibleLocalAlert = nil;
- return;
- }
-
- if (buttonIndex == downloadButtonIndex)
- {
- //clear reminder
- self.lastReminded = nil;
-
- //log event
- if ([self.delegate respondsToSelector:@selector(iVersionUserDidAttemptToDownloadUpdate:)])
- {
- [self.delegate iVersionUserDidAttemptToDownloadUpdate:latestVersion];
- }
-
- if (![self.delegate respondsToSelector:@selector(iVersionShouldOpenAppStore)] ||
- [self.delegate iVersionShouldOpenAppStore])
- {
- //go to download page
- [self openAppPageInAppStore];
- }
- }
- else if (buttonIndex == ignoreButtonIndex)
- {
- //ignore this version
- self.ignoredVersion = latestVersion;
- self.lastReminded = nil;
-
- //log event
- if ([self.delegate respondsToSelector:@selector(iVersionUserDidIgnoreUpdate:)])
- {
- [self.delegate iVersionUserDidIgnoreUpdate:latestVersion];
- }
- }
- else if (buttonIndex == remindButtonIndex)
- {
- //remind later
- self.lastReminded = [NSDate date];
-
- //log event
- if ([self.delegate respondsToSelector:@selector(iVersionUserDidRequestReminderForUpdate:)])
- {
- [self.delegate iVersionUserDidRequestReminderForUpdate:latestVersion];
- }
- }
- //release alert
- self.visibleRemoteAlert = nil;
- }
- #if TARGET_OS_IPHONE
- - (BOOL)openAppPageInAppStore
- {
- if (!_updateURL && !self.appStoreID)
- {
- if (self.verboseLogging)
- {
- NSLog(@"iVersion was unable to open the App Store because the app store ID is not set.");
- }
- return NO;
- }
-
- #if defined(IVERSION_USE_STOREKIT) && IVERSION_USE_STOREKIT
-
- if (!_updateURL && [SKStoreProductViewController class])
- {
- if (self.verboseLogging)
- {
- NSLog(@"iVersion will attempt to open the StoreKit in-app product page using the following app store ID: %@", @(self.appStoreID));
- }
-
- //create store view controller
- SKStoreProductViewController *productController = [[SKStoreProductViewController alloc] init];
- productController.delegate = (id<SKStoreProductViewControllerDelegate>)self;
-
- //load product details
- NSDictionary *productParameters = @{SKStoreProductParameterITunesItemIdentifier: [@(self.appStoreID) description]};
- [productController loadProductWithParameters:productParameters completionBlock:NULL];
-
-
- //get root view controller
- UIWindow *window = [[UIApplication sharedApplication] delegate].window;
- UIViewController *rootViewController = window.rootViewController;
- if (!rootViewController)
- {
- if (self.verboseLogging)
- {
- NSLog(@"iVersion couldn't find a root view controller from which to display StoreKit product page");
- }
- }
- else
- {
- while (rootViewController.presentedViewController)
- {
- rootViewController = rootViewController.presentedViewController;
- }
-
- //present product view controller
- [rootViewController presentViewController:productController animated:YES completion:nil];
- if ([self.delegate respondsToSelector:@selector(iVersionDidPresentStoreKitModal)])
- {
- [self.delegate iVersionDidPresentStoreKitModal];
- }
- return YES;
- }
- }
-
- #endif
-
- if (self.verboseLogging)
- {
- NSLog(@"iVersion will open the App Store using the following URL: %@", self.updateURL);
- }
-
- [[UIApplication sharedApplication] openURL:self.updateURL];
- return YES;
- }
- - (void)productViewControllerDidFinish:(UIViewController *)controller
- {
- [controller.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
- if ([self.delegate respondsToSelector:@selector(iVersionDidDismissStoreKitModal)])
- {
- [self.delegate iVersionDidDismissStoreKitModal];
- }
- }
- - (void)resizeAlertView:(UIAlertView *)alertView
- {
- if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone &&
- UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) &&
- [[UIDevice currentDevice].systemVersion floatValue] < 7.0f)
- {
- CGFloat max = alertView.window.bounds.size.height - alertView.frame.size.height - 10.0f;
- CGFloat offset = 0.0f;
- for (UIView *view in alertView.subviews)
- {
- CGRect frame = view.frame;
- if ([view isKindOfClass:[UILabel class]])
- {
- UILabel *label = (UILabel *)view;
- if ([label.text isEqual:alertView.message])
- {
- label.lineBreakMode = NSLineBreakByWordWrapping;
- label.numberOfLines = 0;
- label.alpha = 1.0f;
- [label sizeToFit];
- offset = label.frame.size.height - frame.size.height;
- frame.size.height = label.frame.size.height;
- if (offset > max)
- {
- frame.size.height -= (offset - max);
- offset = max;
- }
- if (offset > max - 10.0f)
- {
- frame.size.height -= (offset - max - 10);
- frame.origin.y += (offset - max - 10) / 2.0f;
- }
- }
- }
- else if ([view isKindOfClass:[UITextView class]])
- {
- view.alpha = 0.0f;
- }
- else if ([view isKindOfClass:[UIControl class]])
- {
- frame.origin.y += offset;
- }
- view.frame = frame;
- }
- CGRect frame = alertView.frame;
- frame.origin.y -= roundf(offset/2.0f);
- frame.size.height += offset;
- alertView.frame = frame;
- }
- }
- - (void)didRotate
- {
- [self performSelectorOnMainThread:@selector(resizeAlertView:) withObject:self.visibleLocalAlert waitUntilDone:NO];
- [self performSelectorOnMainThread:@selector(resizeAlertView:) withObject:self.visibleRemoteAlert waitUntilDone:NO];
- }
- - (void)willPresentAlertView:(UIAlertView *)alertView
- {
- [self resizeAlertView:alertView];
- }
- - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
- {
- [self didDismissAlert:alertView withButtonAtIndex:buttonIndex];
- }
- #else
- - (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(__unused void *)contextInfo
- {
- [self didDismissAlert:alert withButtonAtIndex:returnCode - NSAlertFirstButtonReturn];
- }
- - (void)openAppPageWhenAppStoreLaunched
- {
- //check if app store is running
- for (NSRunningApplication *app in [[NSWorkspace sharedWorkspace] runningApplications])
- {
- if ([app.bundleIdentifier isEqualToString:iVersionMacAppStoreBundleID])
- {
- //open app page
- [[NSWorkspace sharedWorkspace] performSelector:@selector(openURL:) withObject:self.updateURL afterDelay:MAC_APP_STORE_REFRESH_DELAY];
- return;
- }
- }
-
- //try again
- [self performSelector:@selector(openAppPageWhenAppStoreLaunched) withObject:nil afterDelay:0.0];
- }
- - (BOOL)openAppPageInAppStore
- {
- if (!_updateURL && !self.appStoreID)
- {
- if (self.verboseLogging)
- {
- NSLog(@"iVersion was unable to open the App Store because the app store ID is not set.");
- }
- return NO;
- }
-
- if (self.verboseLogging)
- {
- NSLog(@"iVersion will open the App Store using the following URL: %@", self.updateURL);
- }
-
- [[NSWorkspace sharedWorkspace] openURL:self.updateURL];
- if (!_updateURL) [self openAppPageWhenAppStoreLaunched];
- return YES;
- }
- #endif
- - (void)applicationLaunched
- {
- #if VERSION_DMG
- return;
- #endif
-
- if (self.checkAtLaunch)
- {
- [self checkIfNewVersion];
- if ([self shouldCheckForNewVersion]) {
- [self checkForNewVersion];
- }
- }
- else if (self.verboseLogging)
- {
- NSLog(@"iVersion will not check for updates because the checkAtLaunch option is disabled");
- }
- }
- #if TARGET_OS_IPHONE
- - (void)applicationWillEnterForeground
- {
- if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
- {
- if (self.checkAtLaunch)
- {
- if ([self shouldCheckForNewVersion]) [self checkForNewVersion];
- }
- else if (self.verboseLogging)
- {
- NSLog(@"iVersion will not check for updates because the checkAtLaunch option is disabled");
- }
- }
- }
- #endif
- @end
|