如何知道用户是否更新了应用程序或安装了新副本?

时间:2011-05-17 17:27:24

标签: iphone ios4 iphone-sdk-3.0

我将使用新的数据结构向我的应用发送更新,因此如果用户正在更新我的应用,我需要更新其当前数据。所以我想知道如何以编程方式判断用户是否更新了我的应用程序或安装了新副本(如果安装了新副本,我不需要更新任何内容)?

4 个答案:

答案 0 :(得分:7)

这取决于您使用的数据结构类型。

一般情况下,我会建议您不要依赖于检查应用程序版本:使用2.0的用户可能刚刚升级它可能是新用户。

我宁愿检查是否已有数据结构,并采取相应措施。假设您使用的是Sqlite支持的Core Data存储,您可以检查.sqlite文件是否存在,或者检查存储中是否有对象。

答案 1 :(得分:7)

检查数据结构是一个可靠的解决方案。在我自己的应用程序中,我开始担心没有为多个版本升级的人。我觉得这会导致无数的结构检查。我在下面显示的代码确定并存储NSUserDefaults中的版本和以前的版本。如果需要,您可以编写那些不同的版本差异方案。

NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
BOOL versionUpgraded;
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
NSString *preVersion = [prefs stringForKey:@"appVersion"];

if ([prefs stringForKey:@"appVersion"] != nil) {
    //see if version is the same as prior
    //if not it is an Upgraded
    versionUpgraded = !([preVersion isEqualToString: version]);
} else {
    //nil means new install
            //This needs to be YES for the case that
            //"appVersion" is not set anywhere else.
    versionUpgraded = YES; 
}

if (versionUpgraded) {
    [prefs setObject:version forKey:@"appVersion"];
    [prefs setObject:preVersion forKey:@"prevAppVersion"];

    [prefs synchronize];
}

答案 2 :(得分:3)

只需将捆绑版本保存在某处并检查它是否与

不同

[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]

在每个应用启动时。

答案 3 :(得分:0)

我为此创建了一个类别。只需实现标题中找到的两个新委托调用。它非常依赖obj-c运行时库,因此在使用它之前请确保您对它们充满信心。

·H

#import <UIKit/UIKit.h>

@protocol UIApplicationDelegate <UIApplicationDelegate>
@optional
- (void) application:(UIApplication *)application willUpdateToVersion: (NSString*) newVersion fromVersion: (NSString*) previousVersion;
- (void) application:(UIApplication *)application didUpdateToVersion: (NSString*) newVersion fromVersion: (NSString*) previousVersion;

@end

@interface UIApplication (Versioning)

@end

的.m

#import "UIApplication+Versioning.h"

#import <objc/message.h>
#import <objc/runtime.h>

static NSString* UIApplicationVersionFileName = @"app.ver";

@implementation UIApplication (Versioning)

+ (void) load {
    Method original, swizzled;

    original = class_getInstanceMethod(self, @selector(setDelegate:));
    swizzled = class_getInstanceMethod(self, @selector(swizzled_setDelegate:));

    method_exchangeImplementations(original, swizzled);
}

- (void) swizzled_setDelegate: (id<UIApplicationDelegate>) delegate {

    IMP implementation = class_getMethodImplementation([self class], @selector(swizzled_application:didFinishLaunchingWithOptions:));
    class_addMethod([delegate class], @selector(swizzled_application:didFinishLaunchingWithOptions:), implementation, "B@:@@");

    Method original, swizzled;

    original = class_getInstanceMethod([delegate class], @selector(application:didFinishLaunchingWithOptions:));
    swizzled = class_getInstanceMethod([delegate class], @selector(swizzled_application:didFinishLaunchingWithOptions:));

    method_exchangeImplementations(original, swizzled);

    [self swizzled_setDelegate: delegate];
}

- (BOOL)swizzled_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    //Check for a version change
    NSError* error;
    NSArray* directories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString* versionFilePath = [[directories objectAtIndex: 0] stringByAppendingPathComponent: UIApplicationVersionFileName];
    NSString* oldVersion = [NSString stringWithContentsOfFile: versionFilePath
                                                     encoding: NSUTF8StringEncoding
                                                        error: &error];
    NSString* currentVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey: @"CFBundleVersion"];

    switch (error.code) {
        case NSFileReadNoSuchFileError:
        {
            //Delegate methods will not be called first time
            oldVersion = [currentVersion copy];
            [currentVersion writeToFile: versionFilePath
                             atomically: YES
                               encoding: NSUTF8StringEncoding
                                  error: &error];
            break;
        }
        default:
        {
            NSLog(@"Warning: An error occured will loading the application version file -> Recreating file");
            [[NSFileManager defaultManager] removeItemAtPath: versionFilePath
                                                       error: nil];
            oldVersion = [currentVersion copy];
            [currentVersion writeToFile: versionFilePath
                             atomically: YES
                               encoding: NSUTF8StringEncoding
                                  error: &error];
            break;
        }
    }

    if( ![oldVersion isEqualToString: currentVersion] ) {

        if ([[application delegate] respondsToSelector: @selector(application:willUpdateToVersion:fromVersion:)]) {
            objc_msgSend([application delegate], @selector(application:willUpdateToVersion:fromVersion:), currentVersion, oldVersion);
        }

        [currentVersion writeToFile: versionFilePath
                         atomically: YES
                           encoding: NSUTF8StringEncoding
                              error: &error];

        if ([[application delegate] respondsToSelector: @selector(application:didUpdateToVersion:fromVersion:)]) {
            objc_msgSend([application delegate], @selector(application:willUpdateToVersion:fromVersion:), currentVersion, oldVersion);
        }

    }

    SEL realSelector =  @selector(swizzled_application:didFinishLaunchingWithOptions:);
    return (BOOL) objc_msgSend([application delegate], realSelector, application, launchOptions);
}

@end