本篇文章完美的阐述了应用启动和手动版本的检测原理!
#import "HYBVersionManager.h"
#import "UIAlertView+Blocks.h"
#define kRequestTimeOut 60.0
@interface HYBVersionManager () {
int _type;
UIAlertView *_alertView;
}
@end
@implementation HYBVersionManager
/*!
* @brief 单例方法
*/
+ (HYBVersionManager *)sharedVersionManager {
static HYBVersionManager *sharedObject = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (!sharedObject) {
sharedObject = [[self alloc] init];
}
});
return sharedObject;
}
- (instancetype)init {
if (self = [super init]) {
_type = 0; // 自动检测
}
return self;
}
- (void)checkVersion:(int)type {
_type = type;
[self checkAppStoreVersion];
}
- (void)checkAppStoreVersion {
if ([NSThread isMainThread]) {
[self performSelectorInBackground:@selector(checkAppStoreVersion) withObject:nil];
return;
}
@autoreleasepool {
//prevent concurrent checks
static BOOL checking = NO;
if (checking) return;
checking = YES;
NSError *error = nil;
NSURLResponse *response = nil;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:kItunsLink]
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:kRequestTimeOut];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
if (data && statusCode == 200) {
error = nil;
id json = nil;
if ([NSJSONSerialization class]) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
json = [dict[@"results"] lastObject];
} else {
json = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
if (!error) {
// 获取到appstore上最新的版本号
NSString *latestVersion = [self valueForKey:@"version" inJSON:json];
NSString *localVersion = [self appLocalVersion];
[self check:latestVersion localVersion:localVersion];
}
}
// finished
checking = NO;
}
}
- (void)check:(NSString *)latestVersion localVersion:(NSString *)localVersion {
if ([latestVersion compare:localVersion] == NSOrderedDescending) { // 有新版本
[self showPromptForUpdate];
} else if ([latestVersion compare:localVersion options:NSNumericSearch] == NSOrderedSame) {// 已经是最新版本
if (_type == 1) { // 手动
[self showMessage];
}
}
}
- (void)showMessage {
if (_alertView) {
_alertView.hidden = YES;
[_alertView removeFromSuperview];
_alertView = nil;
}
UIAlertView *alert = [UIAlertView showWithTitle:@""
message:@"当前版本已经是最新版本!"
okButton:@"确定"
cancelButton:nil];
_alertView = alert;
}
- (void)showPromptForUpdate {
[UIAlertView showWithTitle:nil
message:@"美容总监有新版本发布了,亲,快去更新吧!"
cancelButtonTitle:@"暂不更新"
otherButtonTitles:@[@"立即更新"] tapBlock:^(UIAlertView *alertView, NSInteger buttonIndex) {
if (buttonIndex == 0) {
} else {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:kAppStoreLink]];
}
}];
}
/*!
* @brief 获取app本地的版本号
*/
- (NSString *)appLocalVersion {
NSDictionary *info = [[NSBundle mainBundle] infoDictionary];
NSString *version = [info objectForKey:@"CFBundleVersion"];
return [version stringByTrimmingCharactersInSet:[NSCharacterSet letterCharacterSet]];
}
- (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)];
if (hex != nil) {
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;
}
@end
</span>