168

How can I detect the very first time launch of

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  // if very first launch than perform actionA
  // else perform actionB
}

method?

TheNeil
  • 3,321
  • 2
  • 27
  • 52
Shishir.bobby
  • 10,994
  • 21
  • 71
  • 100

17 Answers17

391
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if (![[NSUserDefaults standardUserDefaults] boolForKey:@"HasLaunchedOnce"])
    {
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"HasLaunchedOnce"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
    return YES;
}
Sameera R.
  • 4,384
  • 2
  • 36
  • 53
  • I get an error because the method isn't returning a boolean value. If I use return 0; to kill the error it fails. – mrEmpty Nov 22 '13 at 17:17
  • @mrEmpty 1. ??? It returns `BOOL`. 2. Then the error is in your code... if returning 0 makes this crash, then something is terribly wrong -- elsewhere. –  Nov 22 '13 at 17:52
  • @H2CO3 - isn't `NSUserDefaults` a common place? what if another application uses the same "key" that i'm using? – Ziv Levy Dec 15 '13 at 21:47
  • 6
    @ZivLevy No, user defaults are stored in a property list on a per-sandbox (=per-application) basis. –  Dec 15 '13 at 21:48
  • There's an API for setting a default value for NSUserDefaults: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/#//apple_ref/occ/instm/NSUserDefaults/registerDefaults: – Aaron Ash Mar 17 '16 at 20:27
  • 4
    It will work only for new apps that never submitted before. – Elad Jan 03 '17 at 08:10
  • Elad: You can version keys if you want... It works perfectly – sigi Nov 22 '17 at 18:54
41

In Swift 3, 4 try this:

func isAppAlreadyLaunchedOnce()->Bool{
        let defaults = UserDefaults.standard
        
        if defaults.bool(forKey: "isAppAlreadyLaunchedOnce"){
            print("App already launched : \(isAppAlreadyLaunchedOnce)")
            return true
        }else{
            defaults.set(true, forKey: "isAppAlreadyLaunchedOnce")
            print("App launched first time")
            return false
        }
    }

In Swift 2 try this,

func isAppAlreadyLaunchedOnce()->Bool{
    let defaults = NSUserDefaults.standardUserDefaults()
    
    if defaults.boolForKey("isAppAlreadyLaunchedOnce"){
        print("App already launched : \(isAppAlreadyLaunchedOnce)")
        return true
    }else{
        defaults.setBool(true, forKey: "isAppAlreadyLaunchedOnce")
        print("App launched first time")
        return false
    }
}

UPDATE:- For OBJ-C I use this,

+ (BOOL)isAppAlreadyLaunchedOnce {
    if ([[NSUserDefaults standardUserDefaults] boolForKey:@"isAppAlreadyLaunchedOnce"])
    {
        return true;
    }
    else
    {
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isAppAlreadyLaunchedOnce"];
        [[NSUserDefaults standardUserDefaults] synchronize];
        return false;
    }
}

Ref for OBJ-C: https://stackoverflow.com/a/9964400/3411787

SwiftiSwift
  • 7,528
  • 9
  • 56
  • 96
Mohammad Zaid Pathan
  • 16,304
  • 7
  • 99
  • 130
34

I wrote a tiny library for this very purpose. It lets me know whether this is the first launch ever, or just for this version, and any past versions the user has installed. It's available on github as a cocoapod under the Apache 2 license: GBVersionTracking

You just call this in application:didFinishLaunching:withOptions:

[GBVersionTracking track];

And then to check if this is the first launch just call this anywhere:

[GBVersionTracking isFirstLaunchEver];

And similarly:

[GBVersionTracking isFirstLaunchForVersion];

[GBVersionTracking currentVersion];
[GBVersionTracking previousVersion];
[GBVersionTracking versionHistory];
Community
  • 1
  • 1
lmirosevic
  • 15,787
  • 13
  • 70
  • 116
14

for Swift 3.0 - Swift 5

add extension

    extension UIApplication {
        class func isFirstLaunch() -> Bool {
            if !UserDefaults.standard.bool(forKey: "hasBeenLaunchedBeforeFlag") {
                UserDefaults.standard.set(true, forKey: "hasBeenLaunchedBeforeFlag")
                UserDefaults.standard.synchronize()
                return true
            }
            return false
        }
    }

then in your code

UIApplication.isFirstLaunch()
SuryaKantSharma
  • 1,113
  • 12
  • 27
Igor Kovryzhkin
  • 2,195
  • 1
  • 27
  • 22
8

You can implement it with the static method below:

+ (BOOL)isFirstTime{
    static BOOL flag=NO;
    static BOOL result;

    if(!flag){
        if ([[NSUserDefaults standardUserDefaults] boolForKey:@"hasLaunchedOnce"]){
            result=NO;
        }else{
            [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"hasLaunchedOnce"];
            [[NSUserDefaults standardUserDefaults] synchronize];
            result=YES;
        }

        flag=YES;
    }
    return result;
}
Leonardo Cavalcante
  • 1,274
  • 1
  • 16
  • 26
Mati Bot
  • 797
  • 6
  • 13
  • keep in mind that you need to lock this method if you want it to be thread safe. – Mati Bot Mar 10 '13 at 09:52
  • 9
    I know, but this method isn't. 2 Threads can reach the if(!flag){ when flag is NO. they will get inside the if blocks. one of them will get to the inner else and set the NSUserDefaults and the second one will pass the "hasLaunchOnce" (because the first thread declared it) and set the result to NO. That means you can get the wrong value. – Mati Bot Mar 17 '13 at 15:33
8

Another idea for Xcode 7 and Swift 2.0 is to use extensions

extension NSUserDefaults {
    func isFirstLaunch() -> Bool {
        if !NSUserDefaults.standardUserDefaults().boolForKey("HasAtLeastLaunchedOnce") {
            NSUserDefaults.standardUserDefaults().setBool(true, forKey: "HasAtLeastLaunchedOnce")
            NSUserDefaults.standardUserDefaults().synchronize()
            return true
        }
        return false
    }
}

Now you can write anywhere in your app

if NSUserDefaults.standardUserDefaults().isFirstLaunch() {
    // do something on first launch
}

I personally prefer an extension of UIApplication like this:

extension UIApplication {
    class func isFirstLaunch() -> Bool {
        if !NSUserDefaults.standardUserDefaults().boolForKey("HasAtLeastLaunchedOnce") {
            NSUserDefaults.standardUserDefaults().setBool(true, forKey: "HasAtLeastLaunchedOnce")
            NSUserDefaults.standardUserDefaults().synchronize()
            return true
        }
        return false
    }
}

Because the function call is more descriptive:

if UIApplication.isFirstLaunch() {
    // do something on first launch
}
dennis-tra
  • 1,309
  • 1
  • 14
  • 23
5

You need to save something when you launch and then check to see if it exists. If not, it's the first time. "Something" can be a file, a database entry, a setting in user defaults....

Phillip Mills
  • 30,888
  • 4
  • 42
  • 57
4

It's quite simple to do this and requires only six lines of code.

It will be useful to add this code in your application launch preferences or anywhere else you might need to test whether or not its the first time your application has been run.

//These next six lines of code are the only ones required! The rest is just running      code when it's the first time.
//Declare an integer and a default.
NSUserDefaults *theDefaults;
int  launchCount;
//Set up the properties for the integer and default.
theDefaults = [NSUserDefaults standardUserDefaults];
launchCount = [theDefaults integerForKey:@"hasRun"] + 1;
[theDefaults setInteger:launchCount forKey:@"hasRun"];
[theDefaults synchronize];

//Log the amount of times the application has been run
NSLog(@"This application has been run %d amount of times", launchCount);

//Test if application is the first time running
if(launchCount == 1) {
    //Run your first launch code (Bring user to info/setup screen, etc.)
    NSLog(@"This is the first time this application has been run";
}

//Test if it has been run before
if(launchCount >= 2) {
    //Run new code if they have opened the app before (Bring user to home screen etc.
    NSLog(@"This application has been run before);
}

P.S. Do NOT use bools in preferences Just stick to integers. They default to zero when undefined.

Also, the [theDefaults synchronize]; line isn't required but I've found that when an app is ran hundreds of times across hundreds of devices, the results aren't always reliable, besides, it's better practice.

Milo
  • 5,041
  • 7
  • 33
  • 59
  • Your example works, but all the OP asks for is whether it is the first start or not. A bool is perfectly fine for this. Your code makes sense if one wants to know how many times the user opened the app. – tilo Jul 12 '13 at 10:01
3

Quick and easy function

- (BOOL) isFirstTimeOpening {
    NSUserDefaults *theDefaults = [NSUserDefaults standardUserDefaults];
    if([theDefaults integerForKey:@"hasRun"] == 0) {
        [theDefaults setInteger:1 forKey:@"hasRun"];
        [theDefaults synchronize];
        return true;
    }
    return false;
}
Chris Fremgen
  • 4,649
  • 1
  • 26
  • 26
3

For Swift 2.0 in Xcode 7. In the AppDelegate.swift file:

import UIKit

@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(application: UIApplication, willFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool
{
    return true
}


func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
    didFinishLaunchingOnce()
    return true
}

func didFinishLaunchingOnce() -> Bool
{
    let defaults = NSUserDefaults.standardUserDefaults()

    if let hasBeenLauncherBefore = defaults.stringForKey("hasAppBeenLaunchedBefore")
    {
        //print(" N-th time app launched ")
        return true
    }
    else
    {
        //print(" First time app launched ")
        defaults.setBool(true, forKey: "hasAppBeenLaunchedBefore")
        return false
    }
}

}
MB_iOSDeveloper
  • 4,178
  • 4
  • 24
  • 36
3

In swift I would suggest to use a global constant which can be done very easily outside of any scope such as above the App delegate. Thus it will be set to the right value for as long as the app is not terminated. it will still return the same value if the app goes to background or so. the value will change only if the app is relaunched entirely.

let isFirstLaunch: Bool = {
    if !UserDefaults.standard.bool(forKey: "hasBeenLaunchedBeforeFlag") {
        UserDefaults.standard.set(true, forKey: "hasBeenLaunchedBeforeFlag")
        UserDefaults.standard.synchronize()
        return true
    }
    return false
}()

But honestly it is better to track the fact that the app has been sent to background at least once. In such case I prefer to use an extension on UIApplication and set the flag in the applicationDidEnterBackground method such that:

extension UIApplication {
    private static let isFirstLaunchKey = "isFirstLaunchKey"
    static var isFirstLaunch: Bool {
        return !UserDefaults.standard.bool(forKey: isFirstLaunchKey)
    }
    static func didEnterBackground() {
        if isFirstLaunch {
            UserDefaults.standard.set(true, forKey: isFirstLaunchKey)
            UserDefaults.standard.synchronize()
        }
    }
}

and then in your app delegate or scene delegate

func sceneDidEnterBackground(_ scene: UIScene) {
        UIApplication.didEnterBackground()
    }
Nicolas Manzini
  • 8,379
  • 6
  • 63
  • 81
3

Updated for XCode 12, Swift 5

 extension UIApplication {
      func isFirstLaunch() -> Bool {
        if !UserDefaults.standard.bool(forKey: "HasLaunched") {
          UserDefaults.standard.set(true, forKey: "HasLaunched")
          UserDefaults.standard.synchronize()
          return true
      }
      return false
    }
}

Then you call it as

UIApplication.isFirstLaunch()
Yogesh Patel
  • 1,893
  • 1
  • 20
  • 55
saurabh
  • 6,687
  • 7
  • 42
  • 63
  • 3
    How does your answer differ from the answer [https://stackoverflow.com/a/42509810/7802772](https://stackoverflow.com/a/42509810/7802772) ?! – V.March Sep 14 '21 at 05:55
3

store a bool key in NSUserDefaults first time it will be no you will change it to yes and keep it like that until the app delete or reinstall it will be again tha first time.

Malek_Jundi
  • 6,140
  • 2
  • 27
  • 36
2

swift

struct Pref {
    static let keyFirstRun = "PrefFirstRun"
    static var isFirstRun: Bool {
        get {
            return UserDefaults.standard.bool(forKey: keyFirstRun)
        }
        set {
            UserDefaults.standard.set(newValue, forKey: keyFirstRun)
        }
    }
}

Register default values on app launch:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        let prefs: [String:Any] = [
            Pref.keyFirstRun: true
            ...
        ]

        UserDefaults.standard.register(defaults: prefs)

Clear value on app termination:

func applicationWillTerminate(_ application: UIApplication) {
        Pref.isFirstRun = false

Check value:

 if Pref.isFirstRun {
    ... do whatever 
Krešimir Prcela
  • 4,257
  • 33
  • 46
2

Swift 5 iOS 13.

I like quick and easy by Chris Fremgen. So I updated it.

func isFirstTimeOpening() -> Bool {
  let defaults = UserDefaults.standard

  if(defaults.integer(forKey: "hasRun") == 0) {
      defaults.set(1, forKey: "hasRun")
      return true
  }
  return false

}
user3069232
  • 8,587
  • 7
  • 46
  • 87
0

NSUserDefaults + Macro

The best approach is to use NSUserDefaults and save a BOOL variable. As mentioned above, the following code will do just fine:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[NSNumber numberWithBool:true] forKey:@"~applicationHasLaunchedBefore"];
[userDefaults synchronize];

You can also create a macro as below to easily check whether it is the first launch or not

#define kApplicationHasLaunchedBefore [[NSUserDefaults standardUserDefaults] objectForKey:@"~applicationHasLaunchedBefore"]

Then use it as such,

if (kApplicationHasLaunchedBefore) {
    //App has previously launched
} else {
    //App has not previously launched
}
Fernando Cervantes
  • 2,962
  • 2
  • 23
  • 34
0

Here is an answer working in swift 5.0. The improvement compared to @Zaid Pathan's answer is that there is no hidden contract. If you don't call setFirstAppLaunch() exactly once before calling isFirstAppLaunch() you'll get an assertion error (only in debug mode).

fileprivate struct _firstAppLaunchStaticData {
    static var alreadyCalled = false
    static var isFirstAppLaunch = true
    static let appAlreadyLaunchedString = "__private__appAlreadyLaunchedOnce"
}

func setFirstAppLaunch() {
    assert(_firstAppLaunchStaticData.alreadyCalled == false, "[Error] You called setFirstAppLaunch more than once")
    _firstAppLaunchStaticData.alreadyCalled = true
    let defaults = UserDefaults.standard

    if defaults.string(forKey: _firstAppLaunchStaticData.appAlreadyLaunchedString) != nil {
        _firstAppLaunchStaticData.isFirstAppLaunch = false
    }
    defaults.set(true, forKey: _firstAppLaunchStaticData.appAlreadyLaunchedString)
}

func isFirstAppLaunch() -> Bool {
    assert(_firstAppLaunchStaticData.alreadyCalled == true, "[Error] Function setFirstAppLaunch wasn't called")
    return _firstAppLaunchStaticData.isFirstAppLaunch
}

Then you just need to call the function setFirstAppLaunch() at the start of your application and isFirstAppLaunch() whenever you want to check if your app has been called.

aeon
  • 83
  • 3
  • 6