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

Posted

技术标签:

【中文标题】如何知道用户是不是更新了应用程序或安装了新副本?【英文标题】:How to know if user has updated app or installed a fresh copy?如何知道用户是否更新了应用程序或安装了新副本? 【发布时间】:2011-05-17 17:27:24 【问题描述】:

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

【问题讨论】:

您使用的是什么“数据结构”?核心数据? 【参考方案1】:

检查数据结构是一个可靠的解决方案。我开始在我自己的应用程序中担心那些不升级多个版本的人。我觉得这会导致无数的结构检查。我在下面显示的代码确定版本和以前的版本并将其存储在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】:

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

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

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

【讨论】:

我的回答几乎一样! 我实际上正在使用属性列表,但我想我可以检查丢失的数据或其他东西,谢谢。 忽略我的回答。我误解了你的问题。对此答案 +1。【参考方案3】:

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

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

在每次应用启动时。

【讨论】:

【参考方案4】:

我为此创建了一个类别。只需实现在标头中找到的两个新委托调用。它非常依赖 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

【讨论】:

以上是关于如何知道用户是不是更新了应用程序或安装了新副本?的主要内容,如果未能解决你的问题,请参考以下文章

如何知道是不是选择了 UITableView 的单元格?

如何创建表的回滚副本以防我插入或更新错误

iOS - 用户禁用通知的应用程序如何更新其徽章?

当用户更新或重新安装应用程序时,注册 ID 是不是会更改

更新部署(滚动更新)是不是会使新旧共存副本同时接收流量?

如何告诉应用程序在地址簿中添加或删除或修改了新联系人及其在android中的详细信息