`
ydbc
  • 浏览: 716163 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

ios开发 升级App

 
阅读更多
//
// CWLSynthesizeSingleton.h
// CocoaWithLove
//
// Created by Matt Gallagher on 2011/08/23.
// Copyright (c) 2011 Matt Gallagher. All rights reserved.
//
// Permission is given to use this source code file, free of charge, in any
// project, commercial or otherwise, entirely at your risk, with the condition
// that any redistribution (in part or whole) of source code must retain
// this copyright and permission notice. Attribution in compiled projects is
// appreciated but not required.
//

#import <objc/runtime.h>

#define CWL_DECLARE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(classname, accessorMethodName) \
+ (classname *)accessorMethodName;

#if __has_feature(objc_arc)
#define CWL_SYNTHESIZE_SINGLETON_RETAIN_METHODS
#else
#define CWL_SYNTHESIZE_SINGLETON_RETAIN_METHODS \
- (id)retain \
{ \
return self; \
} \
\
- (NSUInteger)retainCount \
{ \
return NSUIntegerMax; \
} \
\
- (oneway void)release \
{ \
} \
\
- (id)autorelease \
{ \
return self; \
}
#endif

#define CWL_SYNTHESIZE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(classname, accessorMethodName) \
\
static classname *accessorMethodName##Instance = nil; \
\
+ (classname *)accessorMethodName \
{ \
@synchronized(self) \
{ \
if (accessorMethodName##Instance == nil) \
{ \
accessorMethodName##Instance = [super allocWithZone:NULL]; \
accessorMethodName##Instance = [accessorMethodName##Instance init]; \
method_exchangeImplementations(\
class_getClassMethod([accessorMethodName##Instance class], @selector(accessorMethodName)),\
class_getClassMethod([accessorMethodName##Instance class], @selector(cwl_lockless_##accessorMethodName)));\
method_exchangeImplementations(\
class_getInstanceMethod([accessorMethodName##Instance class], @selector(init)),\
class_getInstanceMethod([accessorMethodName##Instance class], @selector(cwl_onlyInitOnce)));\
} \
} \
\
return accessorMethodName##Instance; \
} \
\
+ (classname *)cwl_lockless_##accessorMethodName \
{ \
return accessorMethodName##Instance; \
} \
\
+ (id)allocWithZone:(NSZone *)zone \
{ \
return [self accessorMethodName]; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
} \
- (id)cwl_onlyInitOnce \
{ \
return self;\
} \
\
CWL_SYNTHESIZE_SINGLETON_RETAIN_METHODS

#define CWL_DECLARE_SINGLETON_FOR_CLASS(classname) CWL_DECLARE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(classname, shared##classname)

#define CWL_SYNTHESIZE_SINGLETON_FOR_CLASS(classname) CWL_SYNTHESIZE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(classname, shared##classname)










//
// PSUpdateApp.h
// PSUpdateApp
//
// Created by iBo on 18/02/13.
// Copyright (c) 2013 D-Still. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "CWLSynthesizeSingleton.h"

typedef void(^PSUpdateAppCompletionBLock)(NSError *error, BOOL success, id JSON);

typedef enum {
DefaultStrategy = 0,
ForceStrategy,
RemindStrategy
} UpdateStrategy;

@interface PSUpdateApp : NSObject

CWL_DECLARE_SINGLETON_FOR_CLASS(PSUpdateApp)

@property (nonatomic) NSString *appID, *appStoreLocation, *appName, *route, *updatePageUrl;
@property (nonatomic) UpdateStrategy strategy;
@property (nonatomic) int daysUntilPrompt;
@property (nonatomic) NSDate *remindDate;

+ (id) startWithRoute:(NSString *)route;
+ (id) startWithAppID:(NSString *)appId;
+ (id) startWithAppID:(NSString *)appId store:(NSString *)store;

- (void) detectAppVersion:(PSUpdateAppCompletionBLock)completionBlock;
- (void) setURLAdHoc:(NSString *)url;

@end






//
// PSUpdateApp.m
// PSUpdateApp
//
// Created by iBo on 18/02/13.
// Copyright (c) 2013 D-Still. All rights reserved.
//

#ifndef PSUdateAppLocalizedStrings
#define PSUdateAppLocalizedStrings(key) \
NSLocalizedStringFromTable(key, @"PSUdateApp", nil)
#endif

#import "PSUpdateApp.h"
#import <AFNetworking/AFNetworking.h>

#define APPLE_URL @"http://itunes.apple.com/lookup?"

#define kCurrentAppVersion [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]

@interface PSUpdateApp () <UIAlertViewDelegate> {
NSString *_newVersion;
}
@end

@implementation PSUpdateApp

CWL_SYNTHESIZE_SINGLETON_FOR_CLASS(PSUpdateApp)

+ (id) startWithRoute:(NSString *)route
{
return [[self alloc] initWithAppID:nil store:nil route:route];
}

+ (id) startWithAppID:(NSString *)appId store:(NSString *)store
{
return [[self alloc] initWithAppID:appId store:store route:nil];
}

+ (id) startWithAppID:(NSString *)appId
{
return [[self alloc] initWithAppID:appId store:nil route:nil];
}

- (id) initWithAppID:(NSString *)appId store:(NSString *)store route:(NSString *)route
{
self = [super init];

if ( self ) {
[self setAppName:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]];
[self setStrategy:DefaultStrategy];
[self setAppID:appId];
[self setAppStoreLocation: store ? store : [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode]];
[self setDaysUntilPrompt:2];
[self setRoute:route];
}

return self;
}

- (void) detectAppVersion:(PSUpdateAppCompletionBLock)completionBlock
{
if ( _strategy == RemindStrategy && [self remindDate] != nil && ![self checkConsecutiveDays] )
return;

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[self setJsonURL]]];
[request setHTTPMethod:@"GET"];

AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
if ( [self isNewVersion:JSON] ) {
if ( completionBlock && ![self isSkipVersion] ) {
completionBlock(nil, YES, JSON);
} else if ( ![self isSkipVersion] ) {
[self showAlert];
} else {
if ( completionBlock )
completionBlock(nil, NO, JSON);
}
} else {
if ( completionBlock )
completionBlock(nil, NO, JSON);
}
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
if ( completionBlock && ![self isSkipVersion] )
completionBlock(error, NO, nil);
}];
[operation start];
}

- (NSString *) setJsonURL
{
return self.route ? self.route : [NSString stringWithFormat:@"%@id=%@&country=%@", APPLE_URL, self.appID, self.appStoreLocation];
}

- (void) setURLAdHoc:(NSString *)url
{
[self setRoute:[NSString stringWithFormat:url, self.appStoreLocation]];
}

#pragma mark - Check version

- (BOOL) isNewVersion:(NSDictionary *)dictionary
{
if ( [[dictionary objectForKey:@"results"] count] > 0 ) {
_newVersion = [[[dictionary objectForKey:@"results"] objectAtIndex:0] objectForKey:@"version"];
[self setUpdatePageUrl:[[[dictionary objectForKey:@"results"] objectAtIndex:0] objectForKey:@"trackViewUrl"]];

if ([[[dictionary objectForKey:@"results"] objectAtIndex:0] objectForKey:@"type"]) {
[self setStrategy: [[[[dictionary objectForKey:@"results"] objectAtIndex:0] objectForKey:@"type"] isEqualToString:@"mandatory"] ? ForceStrategy : DefaultStrategy];
}

return [kCurrentAppVersion compare:_newVersion options:NSNumericSearch] == NSOrderedAscending;
}

return NO;
}

- (BOOL) isSkipVersion
{
return [[[NSUserDefaults standardUserDefaults] objectForKey:@"skipVersion"] isEqualToString:_newVersion];
}

#pragma mark - remindDate getter / setter

- (NSDate *) remindDate
{
return [[NSUserDefaults standardUserDefaults] objectForKey:@"remindDate"];
}

- (void) setRemindDate:(NSDate *)remindDate
{
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"remindDate"];
[[NSUserDefaults standardUserDefaults] synchronize];
}

#pragma mark - Show alert

- (void) showAlert
{
switch ( self.strategy ) {
case DefaultStrategy:
default:
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:PSUdateAppLocalizedStrings(@"alert.success.title")
message:[NSString stringWithFormat:PSUdateAppLocalizedStrings(@"alert.success.default.text"), self.appName, _newVersion]
delegate:self
cancelButtonTitle:PSUdateAppLocalizedStrings(@"alert.button.skip")
otherButtonTitles:PSUdateAppLocalizedStrings(@"alert.button.update"), nil];
[alertView show];
}
break;

case ForceStrategy:
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:PSUdateAppLocalizedStrings(@"alert.success.title")
message:[NSString stringWithFormat:PSUdateAppLocalizedStrings(@"alert.success.force.text"), self.appName, _newVersion]
delegate:self
cancelButtonTitle:PSUdateAppLocalizedStrings(@"alert.button.update")
otherButtonTitles:nil, nil];
[alertView show];
}
break;

case RemindStrategy:
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:PSUdateAppLocalizedStrings(@"alert.success.title")
message:[NSString stringWithFormat:PSUdateAppLocalizedStrings(@"alert.success.remindme.text"), _appName, _newVersion]
delegate:self
cancelButtonTitle:PSUdateAppLocalizedStrings(@"alert.button.skip")
otherButtonTitles:PSUdateAppLocalizedStrings(@"alert.button.update"), PSUdateAppLocalizedStrings(@"alert.button.remindme"), nil];
[alertView show];
}
break;
}
}


#pragma mark - UIAlertViewDelegate Methods

- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch ( self.strategy ) {
case DefaultStrategy:
default:
{
if ( buttonIndex == 0 ) {
[[NSUserDefaults standardUserDefaults] setObject:_newVersion forKey:@"skipVersion"];
[[NSUserDefaults standardUserDefaults] synchronize];
} else {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:self.updatePageUrl]];
}
}

break;

case ForceStrategy:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:self.updatePageUrl]];
break;

case RemindStrategy:
{
if ( buttonIndex == 0 ) {
[[NSUserDefaults standardUserDefaults] setObject:_newVersion forKey:@"skipVersion"];
[[NSUserDefaults standardUserDefaults] synchronize];
} else if ( buttonIndex == 1 ) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:self.updatePageUrl]];
} else {
[self setRemindDate:[NSDate date]];
}
}

break;
}
}

#pragma mark - Check if have passed

- (BOOL) checkConsecutiveDays
{
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDate *today = [NSDate date];

NSDate *dateToRound = [[self remindDate] earlierDate:today];
NSDateComponents * dateComponents = [gregorian components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:dateToRound];

NSDate *roundedDate = [gregorian dateFromComponents:dateComponents];
NSDate *otherDate = (dateToRound == [self remindDate]) ? today : [self remindDate] ;
NSInteger diff = abs([roundedDate timeIntervalSinceDate:otherDate]);
NSInteger daysDifference = floor(diff/(24 * 60 * 60));

return daysDifference >= _daysUntilPrompt;
}

@end


分享到:
评论

相关推荐

    苹果iOS app开发之更新升级app的办法.zip

    苹果iOS app开发之更新升级app的办法.zip

    swift-SwiftWeather采用Swift2开发的iOS天气App

    SwiftWeather:采用Swift 2开发的iOS天气App。应用程序一直积极升级到采用最新的iOS和Swift语言特性。

    IOS开发官方教程(中文)

    开发 iOS 应用程序,您需要: Mac 电脑,运行 OS X 10.8 (Mountain Lion) 或更高版本 Xcode iOS SDK Xcode 是 Apple 的集成开发环境 (IDE)。Xcode 包括源代码编辑器、图形用户界面编辑器和许多其他功 能。iOS SDK 扩展...

    iOS 16 真机开发包 正式版

    iOS 16 真机开发包 正式版. 使用方法: 将下载好的调试包解压,快捷键command+shift+g前往文件夹: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport 把解压后的文件放入到该...

    iOS 16.1 真机开发包 正式版

    注意:升级到iOS 16后需打开开发者模式否则Xcode会报错“Failed to prepare device for development”,一直转圈不能调试。入口为:设置-隐私与安全性 安全性-开发者模式打开,打开后会重启手机,之后再调试就可以了...

    iOS 16 beta 真机开发包

    iOS 16 真机开发包 beta版. 使用方法: 将下载好的调试包解压,快捷键command+shift+g前往文件夹: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport 把解压后的文件放入到该...

    iOS 16.4真机开发包

    注意:升级到iOS 16后需打开开发者模式否则Xcode会报错“Failed to prepare device for development”,一直转圈不能调试。入口为:设置-隐私与安全性 安全性-开发者模式打开,打开后会重启手机,之后再调试就可以了...

    iOS开发-解决Xcode15无法创建category问题

    Xcode升级到iOS15以后发现无法创建category了,现已找到解决方案供大家参考。 这是由于Xcode15缺少了"CategoryNSObject"和"ExtensionNSObject"两个文件夹导致的,解决办法就是将这两个加进去就好了。 如果你有旧的...

    VirtualBox安装Mac+OS+X虚拟机全教程以及iOS开发必备软件

    首先为什么要使用vBox虚拟机?很简单, 1、我不想买Mac本本 2、黑苹果安装苦难,危险。正常按照网络上的教程,不折腾个7、8天是不行的,还不一定能... -xcode_4.2_and_ios_5_sdk使用的iOS开发软件 来吧,还等什么。

    xcode配置iOS11.0开发包

    xcode配置iOS11.0开发包 解决iOS 11.0升级后无法真机测试 Could not find Developer Disk Image 使用方法: 在“/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport”里添加...

    谈谈AndroidApp混合开发

    混合开发的App(HybridApp)就是在一个App中内嵌一个轻量级的浏览器,一部分原生的功能改为Html5来开发,这部分功能不仅能够在不升级App的情况下动态更新,而且可以在Android或iOS的App上同时运行,让用户的体验更好...

    iOS 10即将来袭!升级你的iOS开发装备

    WWDC(苹果开发者大会)刚刚过去不久,iOS 10将不久来袭,是时候升级你的iOS开发装备了!小编整理了10款必备开发工具,让你的开发过程事半功倍。 SourceTree SourceTree是一个免费的Mac软件,主要用于Git和...

    [总结帖]关于升级xcode8,谈谈你的新发现!!! | iOS开发 - CocoaChina CocoaChina_让移动开发

    ain 16-bit or P3 assets if the app is targeting iOS releases earlier than iOS 9.

    H5混合开发app如何升级的方法

    当我们的app开发完成之后,无可避免的以后会进行产品升级,那么我们希望在客户的手机上让app进行自动升级,可以分为自动升级和手动升级。 自动升级:一般在客户app第一次打开首页的时候。 手动升级:在app界面提供一...

    iOS16真机包 Xcode14 真机包

    下载解压放到/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport即可,重启Xcode即可,无需升级系统和Xcode

    TipsForIOS:IOS开发常见问题及常用技巧

    IOS开发常见问题及常用技巧 1.升级到iOS 8.0 SDK以后,创建的新项目会带有LaunchScreen.xib文件作为App的启动界面,此时若不作任何设置就把基于8.0 SDK的App运行在7.0等版本的设备上,可能会出现应用不能全屏,为了解决...

    uni-app-master:uni-app是使用Vue语法开发小程序,H5,App的统一框架

    官网地址: : Vue.js开发者使用Vue语法编写代码, uni-app框架将其编译到小程序(微信/支付宝/百度/字节跳动/ QQ /钉钉),App(iOS / Android),H5等多个平台,保证其正确运行并达到优秀体验。uni-app的特点开发者...

    xcode8 支持iOS10.2系统的开发资源包

    iOS升级到10.2,Xocde不能真机调试。这个是真机调试资源包,下载以后,加入到下面的目录下就可以支持了。 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

Global site tag (gtag.js) - Google Analytics