I need to check when my app launches if it was being updated, because i need to make a view that only appears when the app is firstly installed to appear again after being updated.
-
2you need to elaborate on this question: what is being updated? the app itself or files within the app or files to be downloaded from a remote server? – Michael Dautermann Jun 03 '13 at 14:47
-
the app itself is being updated – user2412870 Jun 04 '13 at 07:24
8 Answers
You could save a value (e.g. the current app version number) to NSUserDefaults
and check it every time the user starts the app.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *currentAppVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSString *previousVersion = [defaults objectForKey:@"appVersion"];
if (!previousVersion) {
// first launch
// ...
[defaults setObject:currentAppVersion forKey:@"appVersion"];
[defaults synchronize];
} else if ([previousVersion isEqualToString:currentAppVersion]) {
// same version
} else {
// other version
// ...
[defaults setObject:currentAppVersion forKey:@"appVersion"];
[defaults synchronize];
}
return YES;
}
The swift-2 version looks like this:
let defaults = NSUserDefaults.standardUserDefaults()
let currentAppVersion = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") as! String
let previousVersion = defaults.stringForKey("appVersion")
if previousVersion == nil {
// first launch
defaults.setObject(currentAppVersion, forKey: "appVersion")
defaults.synchronize()
} else if previousVersion == currentAppVersion {
// same version
} else {
// other version
defaults.setObject(currentAppVersion, forKey: "appVersion")
defaults.synchronize()
}
The swift-3 version looks like this:
let defaults = UserDefaults.standard
let currentAppVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
let previousVersion = defaults.string(forKey: "appVersion")
if previousVersion == nil {
// first launch
defaults.set(currentAppVersion, forKey: "appVersion")
defaults.synchronize()
} else if previousVersion == currentAppVersion {
// same version
} else {
// other version
defaults.set(currentAppVersion, forKey: "appVersion")
defaults.synchronize()
}
-
9how we check if already shipped app not supporting the above mechanism ? – damithH Mar 04 '14 at 12:38
-
3@damithH if your shipped app was using NSUserDefaults, then simply check for the existence of whatever key you were using. – Cœur Apr 04 '17 at 02:50
-
2Apple docs says **synchronize()** *Waits for any pending asynchronous updates to the defaults database and returns; this method is unnecessary and shouldn't be used.* [Synchronize](https://developer.apple.com/documentation/foundation/userdefaults/1414005-synchronize) – Viennarz Valdevieso Curtiz Dec 11 '19 at 02:59
you can store a app version number in NSUserDefaults and check it every time your app is launched. If the number is not available, its a fresh installation. If it is changed , it is an upgrade.

- 10,205
- 2
- 35
- 73
-
I read that after an update the NSUserDefaults doesn't get deleted, so that wouldn't not help me, that would work if a user deletes the application first and the reinstall it – user2412870 Jun 03 '13 at 14:53
-
1@user2412870 Store your version number in NSUserDefaults and check, if updated you can check if the version number is similar to the number saved in NSUserDefaults – pre Jun 03 '13 at 14:56
Just initialise AppVersionUpdateNotifier in app launch and conform AppUpdateNotifier protocol, enjoy.
Use: Swift 3.x
extension AppDelegate: AppUpdateNotifier {
func onVersionUpdate(newVersion: Int, oldVersion: Int) {
// do something
}
func onFirstLaunch() {
//do something
}
}
class AppVersionUpdateNotifier {
static let KEY_APP_VERSION = "key_app_version"
static let shared = AppVersionUpdateNotifier()
private let userDefault:UserDefaults
private var delegate:AppUpdateNotifier?
private init() {
self.userDefault = UserDefaults.standard
}
func initNotifier(_ delegate:AppUpdateNotifier) {
self.delegate = delegate
checkVersionAndNotify()
}
private func checkVersionAndNotify() {
let versionOfLastRun = userDefault.object(forKey: AppVersionUpdateNotifier.KEY_APP_VERSION) as? Int
let currentVersion = Int(Bundle.main.buildVersion)!
if versionOfLastRun == nil {
// First start after installing the app
delegate?.onFirstLaunch()
} else if versionOfLastRun != currentVersion {
// App was updated since last run
delegate?.onVersionUpdate(newVersion: currentVersion, oldVersion: versionOfLastRun!)
} else {
// nothing changed
}
userDefault.set(currentVersion, forKey: AppVersionUpdateNotifier.KEY_APP_VERSION)
}
}
protocol AppUpdateNotifier {
func onFirstLaunch()
func onVersionUpdate(newVersion:Int, oldVersion:Int)
}
extension Bundle {
var shortVersion: String {
return infoDictionary!["CFBundleShortVersionString"] as! String
}
var buildVersion: String {
return infoDictionary!["CFBundleVersion"] as! String
}
}

- 4,768
- 4
- 32
- 51
swift version with an important improvement over the accepted answer:
- using
infoDictionary
instead ofobjectForInfoDictionaryKey
guaranties that the result is independent from device language, otherwise you may end up in some rare cases believing that there is an upgrade when in reality it is just a device language change - using a UserDefaults key identical to the main Bundle infoDictionary for clarity on what is exactly stored
- factoring setting currentVersion code
- Swift 3 syntax
Code:
let standardUserDefaults = UserDefaults.standard
let shortVersionKey = "CFBundleShortVersionString"
let currentVersion = Bundle.main.infoDictionary![shortVersionKey] as! String
let previousVersion = standardUserDefaults.object(forKey: shortVersionKey) as? String
if previousVersion == currentVersion {
// same version
} else {
// replace with `if let previousVersion = previousVersion {` if you need the exact value
if previousVersion != nil {
// new version
} else {
// first launch
}
standardUserDefaults.set(currentVersion, forKey: shortVersionKey)
standardUserDefaults.synchronize()
}

- 37,241
- 25
- 195
- 267
I think, given answers are good when you've a small scale application but when you working on a large-scale iOS apps with a long roadmap you definitely need a strong futuristic solution with benefits like.
- Better compare logic that works fine with all possibilities (2.0/2.0.0 etc).
- Take specific action during migration, assume when user migrating from version 1.0 to 2.0 verses 1.1 to 2.0.
- Reset the cached version when the user reset the app (Logout).
Below is the code snippet that I used in one of my iOS App.
public enum VersionConfigResponse {
case freshInstalled
case versionGreater
case versionEqualOrLesser
case currentVersionEmpty
}
/*
Config manager responsible to handle the change needs to be done when user migrate from one Version to another Version.
*/
public class VersionConfig {
public static let shared = VersionConfig()
private init() { }
private let versionKey = "SAVED_SHORT_VERSION_STRING"
/*
Cache the existing version for compare during next app launch.
*/
private var storedVersion : String? {
get {
return UserDefaults.standard.object(forKey: versionKey) as? String
} set {
UserDefaults.standard.set(newValue, forKey: versionKey)
UserDefaults.standard.synchronize()
}
}
/*
Validate the current version with saved version, if greater do clean.
*/
public func validate(currentVersion: String?) -> VersionConfigResponse {
guard let currentVersion = currentVersion else {
return .currentVersionEmpty
}
guard let sVersion = storedVersion else {
self.storedVersion = currentVersion
self.freshInstalled()
return .freshInstalled
}
if currentVersion.compare(sVersion, options: .numeric, range: nil, locale: nil) == .orderedDescending {
self.storedVersion = currentVersion
self.userMigrated(fromVersion: sVersion, toVersion:currentVersion)
return .versionGreater
} else {
return .versionEqualOrLesser
}
}
private func userMigrated(fromVersion: String, toVersion: String) {
//take your action here...
}
private func freshInstalled() {
//take your action here...
}
/*
Remove saved version if user reset(logout) the app.
*/
public func reset() {
self.storedVersion = nil
}
}
//trigger version config with current version
VersionConfig.shared.validate(currentVersion: "1.0.0")
//reset when user logsout
VersionConfig.shared.reset()

- 7,345
- 1
- 31
- 51
Here is a simple code to know if the current version is different (this code work on simulator too.)
-(BOOL) needsUpdate
{
NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString* appID = infoDictionary[@"CFBundleIdentifier"];
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://itunes.apple.com/lookup?bundleId=%@", appID]];
NSData* data = [NSData dataWithContentsOfURL:url];
NSDictionary* lookup = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if ([lookup[@"resultCount"] integerValue] == 1)
{
NSString* appStoreVersion = lookup[@"results"][0][@"version"];
NSString* currentVersion = infoDictionary[@"CFBundleShortVersionString"];
if (![appStoreVersion isEqualToString:currentVersion])
{
NSLog(@"Need to update [%@ != %@]", appStoreVersion, currentVersion);
return YES;
}
}
return NO;
}
Note: Make sure that when you enter the new version in iTunes, this matches the version in the app you are releasing. If not then the above code will always return YES regardless if the user updates.

- 787
- 1
- 7
- 16
-
Do not simply copy-paste the solutions from other's answers [https://stackoverflow.com/a/25210143/4387347]. Try to add your own suggestions/improvements. – Vishal Sonawane Jul 29 '20 at 12:27
I've created BundleInfoVersioning
swift package to help me solve this issue.
It works with all keys in the info dictionary, like CFBundleVersion
or CFBundleShortVersionString
and with custom key paths like, for example, NSAgora/DatabaseVersion
.
Examples:
let bundleInfoVersioning = BundleInfoVersioning(bundle: .main)
bundleInfoVersioning.check(forKeyPath: "CFBundleVersion") { (old: String?, new: String?) in
if old == nil {
Analytics.install(version: new)
}
else {
Analytics.update(from: old, to: new)
}
}
bundleInfoVersioning.check(forKeyPath: "CFBundleShortVersionString") { _ , newVersion in
self.showWhatsNew(in: newVersion)
}
bundleInfoVersioning.check(forKeyPath: "NSAgora/DatabaseVersion") { (old: Int?, new: Int?) in
self.resetDataBase()
}
You can check it out on github at https://github.com/nsagora/bundle-info-versioning.

- 2,316
- 16
- 18
This worked for me..
func compareVersion(old:String,latest:String) -> Bool {
if latest.compare(old, options: .numeric) == .orderedDescending {
return true
}
return false
}
compareVersion(old: "3.1.5", latest: "3.2")

- 528
- 3
- 17