27

I am developing an application and i need to know whether user installed the app for the first time or upgraded it from the App Store.

How can i detect whether app is installed for the first time or upgraded or re-installed?

Thanks for your answers in advance.

hamzaozturk
  • 453
  • 1
  • 5
  • 12

5 Answers5

39

You can differentiate between the first start after installing the App, the first start after an update and other starts quite easily via saving the latest known version to standardUserDefaults. But as far as I know it is not possible do detect a re-install of the App as all App-related data are also removed when the App is deleted from the device.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSString* currentVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
    NSString* versionOfLastRun = [[NSUserDefaults standardUserDefaults] objectForKey:@"VersionOfLastRun"];

    if (versionOfLastRun == nil) {
        // First start after installing the app
    } else if (![versionOfLastRun isEqual:currentVersion]) {
        // App was updated since last run
    } else {
        // nothing changed 
    }

    [[NSUserDefaults standardUserDefaults] setObject:currentVersion forKey:@"VersionOfLastRun"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}
Nero
  • 1,295
  • 1
  • 16
  • 23
  • Maybe storing the version number to keychain will work? I think the data in the keychain is not deleted after the app is uninstalled. – Sweeper Jul 06 '16 at 07:48
  • when do you update the previous version? – Gerald Sep 29 '16 at 19:30
  • @Nero This is working when I change the Build number, but not the version number. Any Ideas? – Sethmr Dec 13 '16 at 22:42
  • 1
    @Sethmr Oh yes, you're right. Thanks for noting this. `CFBundleVersion` actually returns what Xcode calls the Build number, but there's another key `CFBundleShortVersionString` which returns the Version number you enter in the Project Editor. – Nero Dec 14 '16 at 20:23
  • The standardized format for Version/Build numbers needs to be actually documented instead of allowing complete and total freedom of use! It was only after seeing those two variables that I realized the Build is basically meant to be an extension onto the Version. I was previously treating it as just an Int with no "." to identify which version. – Sethmr Dec 15 '16 at 19:58
  • Do not use `objectForInfoDictionaryKey` to compare versions! See http://stackoverflow.com/a/42552076/1033581 – Cœur Mar 02 '17 at 10:01
20

Checkout Swift 3.0 version of code.
Note: Use CFBundleShortVersionString, for checking actual App version checking.

func checkAppUpgrade() {
    let currentVersion = Bundle.main.object(forInfoDictionaryKey:     "CFBundleShortVersionString") as? String
    let versionOfLastRun = UserDefaults.standard.object(forKey: "VersionOfLastRun") as? String

    if versionOfLastRun == nil {
        // First start after installing the app

    } else if versionOfLastRun != currentVersion {
        // App was updated since last run

    } else {
        // nothing changed

    }

    UserDefaults.standard.set(currentVersion, forKey: "VersionOfLastRun")
    UserDefaults.standard.synchronize()
}
Saggy
  • 465
  • 5
  • 18
4

For Swift 3

 let currentVersion : String = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String

let versionOfLastRun: String? = UserDefaults.standard.object(forKey: "VersionOfLastRun") as? String

if versionOfLastRun == nil {
     // First start after installing the app
} else if  !(versionOfLastRun?.isEqual(currentVersion))! {
      // App is updated
}

UserDefaults.standard.set(currentVersion, forKey: "VersionOfLastRun")
UserDefaults.standard.synchronize()
sohail059
  • 830
  • 1
  • 6
  • 14
0

Just for note:

To obtain localized value of any key you should use CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), "CFBundleShortVersionString" as CFString)

akaDuality
  • 384
  • 5
  • 6
0

Please store a version in NSUserDefaults (per @Nero's answer) for checking (possible) fresh installs and subsequent updates.

For checking reinstalls (in the case where stored version == nil), exploit iOS 11's introduction of DeviceCheck API which exposes two bits of device specific data which can be set and retrieved by the app, but maintained by Apple and persisted across an uninstall/reinstalls.

Tom Howard
  • 4,672
  • 2
  • 43
  • 48