Detect first launch of iOS app [duplicate]
Asked Answered
D

9

71

I am trying to find a way in Swift to detect the first launch.

Danilodanio answered 29/11, 2014 at 23:2 Comment(1)
"I saw a topic on Stackoverflow but it was outdated (objective-C)." As all the answers below show, the solution to your problem is (and has been, for a while now) pretty much the same whether you code in Objective-C or Swift.Jurassic
L
166

Typically you would write a value to NSUserDefaults to indicate that an app has launched before.

let launchedBefore = NSUserDefaults.standardUserDefaults().boolForKey("launchedBefore")
if launchedBefore  {
    print("Not first launch.")
}
else {
    print("First launch, setting NSUserDefault.")
    NSUserDefaults.standardUserDefaults().setBool(true, forKey: "launchedBefore")
}

UPDATE - Swift 3

let launchedBefore = UserDefaults.standard.bool(forKey: "launchedBefore")
if launchedBefore  {
    print("Not first launch.")
} else {
    print("First launch, setting UserDefault.")
    UserDefaults.standard.set(true, forKey: "launchedBefore")
}
Labonte answered 29/11, 2014 at 23:9 Comment(10)
That's not going to work as you've written it. firstLaunch is an Optional. You're not grappling with that. Plus, it will be nil because you didn't register a value.Halflight
It works just fine, as I've tested it. boolForKey does not return an optional but false if the value doesn't exist.Labonte
Okay! Fine then. :) I didn't realize the clever refinement of boolForKey.Halflight
Though I suppose returning an optional could be more useful, as then you could tell the difference between a value being set to false and not being set at all. Though in that case you could use setValue, as that take an AnyObject?.Labonte
Things like objectForKey: do return an Optional. But boolForKey: has special behavior. So that was a good choice!Halflight
if firstLaunch { println("Not first launch.") } that doesn't make much sense ;-)Handcraft
@TimCastelijns Yeah, I suppose it should be launchedBefore or something.Labonte
@JonShier Any simple way to detect if the user has launched the app first time after update from App Store?Chromyl
@GurjitSingh Storing the version number you see on launch should let you detect that. If the version number changes you should know that an update has been made.Labonte
If you request for it in multiple places in the application, then it will be TRUE for the second and subsequent requests, although it may actually be the first run. Better to use a launch counter.Nearsighted
A
44

I kinda always need this so I put it in a category

General Usage:

let isFirstLaunch = UserDefaults.isFirstLaunch()

Usage inside your AppDelegate

// use this if you need to refer to it later
var optionallyStoreTheFirstLaunchFlag = false

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        optionallyStoreTheFirstLaunchFlag = UserDefaults.isFirstLaunch()
   // .. do whatever else

    return true
}

Some important considerations:

  • This flag is only set on the first invocation. If you want to know about the first launch multiple times throughout different screens, set a variable you can later refer to, as per the 'optionallyStoreTheFirstLaunchFlag' example.
  • In iOS, apps are usually never shut down. Apps are backgrounded, foregrounded, state-saved to flash memory, but they are only relaunched if they're force shutdown by the user (rare) or the user restarts their phone. So if you store it in a variable, it could potentially stick around for a long time. Manually reset it once you're done with showing all the tutorial screens and whatnot.

Swift 4

Put the following in UserDefaults+isFirstLaunch.swift

extension UserDefaults {
    // check for is first launch - only true on first invocation after app install, false on all further invocations
    // Note: Store this value in AppDelegate if you have multiple places where you are checking for this flag
    static func isFirstLaunch() -> Bool {
        let hasBeenLaunchedBeforeFlag = "hasBeenLaunchedBeforeFlag"
        let isFirstLaunch = !UserDefaults.standard.bool(forKey: hasBeenLaunchedBeforeFlag)
        if (isFirstLaunch) {
            UserDefaults.standard.set(true, forKey: hasBeenLaunchedBeforeFlag)
            UserDefaults.standard.synchronize()
        }
        return isFirstLaunch
    }
}
Antalya answered 28/3, 2016 at 1:31 Comment(7)
FYI to other users, you will need to add in the viewDidAppear section: if isFirstLaunch { instructions here } else { print ("Not first launch")}Silvestro
Well you can use it in any way you like, only keep in mind that it will produce a "true" value only on first invocation. If it gets used across multiple views, you will need to be mindful of that.Antalya
See my answer below if you want it always true during whole first app life until terminated.Bethlehem
Also it will produce a "true" on a second launch if for any reason you did not call the method on the first launch.Verbena
@MihaiDamian I'm not sure what you're saying. If you don't call it, it won't work. As is generally the case with all code?! Maybe I should clarify usage - maybe you have a code path where it wasn't called on launch?Antalya
Very bad idea to rely on "iOS apps are usually never shut down". Apple makes extremely clear throughout documentation that the system reserves the right to terminate any process at any time for any reason -- especially on newer versions of iOS that more aggressively manage memory and system resources to conserve energy.Ham
@SamuelSpencer Of course we shouldn't rely on it not being shut down, we just need to keep in mind that 99% of the time when a user pulls out your app, it will continue where it left off. That's different from browsers, computers, where apps are shut down frequently. It's not about relying on anything, it's only about seeing how the usage is like. So I was warning about the fact that an app may live for a much longer time than you'd think.Antalya
C
16

Swift 3

extension UserDefaults {

     var hasLaunchBefore: Bool {
           get {
             return self.bool(forKey: #function)
           }
           set {
             self.set(newValue, forKey: #function)
           }
     }
}

Swift 5 (Property wrappers)

UserDefaultWrapper:

@propertyWrapper
struct UserDefaultWrapper<T> {
    let key: String
    let defaultValue: T

    init(_ key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }

    var wrappedValue: T {
        get {
            return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
        }
        set {
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }
}

UserDefaultsStore:

struct UserDefaultsStore {
    @UserDefaultWrapper("has_launch_before", defaultValue: false)
    static var hasLaunchBefore: Bool
}

Usage:

UserDefaultsStore.hasLaunchBefore = false
Cinelli answered 31/3, 2017 at 9:54 Comment(1)
for property wrapper attempt +1 although I haven't tried. :)Unplaced
B
8

I refined a bit user n13 answer in order to

  • have the method always return true during the whole first launch
  • be an extension to UIApplication

Just use it wherever you want as UIApplication.isFirstLaunch() and be sure to reach it at least once during first execution.

Swift 3

import UIKit

private var firstLaunch : Bool = false

extension UIApplication {

    static func isFirstLaunch() -> Bool {
        let firstLaunchFlag = "isFirstLaunchFlag"
        let isFirstLaunch = UserDefaults.standard.string(forKey: firstLaunchFlag) == nil
        if (isFirstLaunch) {
            firstLaunch = isFirstLaunch
            UserDefaults.standard.set("false", forKey: firstLaunchFlag)
            UserDefaults.standard.synchronize()
        }
        return firstLaunch || isFirstLaunch
    }
}

Swift 2

import UIKit

private var firstLaunch : Bool = false

extension UIApplication {

    static func isFirstLaunch() -> Bool {
        let firstLaunchFlag = "isFirstLaunchFlag"
        let isFirstLaunch = NSUserDefaults.standardUserDefaults().stringForKey(firstLaunchFlag) == nil
        if (isFirstLaunch) {
            firstLaunch = isFirstLaunch
            NSUserDefaults.standardUserDefaults().setObject("false", forKey: firstLaunchFlag)
            NSUserDefaults.standardUserDefaults().synchronize()
        }
        return firstLaunch || isFirstLaunch
    }
}
Bethlehem answered 12/9, 2016 at 22:8 Comment(4)
Why storing string inside userdefaults instead of boolean? :OAuberta
I just edited n13 answer on the fly since somebody requested it. There is more than just that to improve, but i guess was just for brevity to avoid this https://mcmap.net/q/224670/-ios-use-a-boolean-in-nsuserdefaultsBethlehem
My Swift version stores a boolean FYI ;)Antalya
This answer should be completely rewritten :/Bethlehem
H
5

Use NSUserDefaults. Register a BOOL key with a value of false. Read the key at launch time; if it's false, set it to true and show the welcome. Next launch, it will be true, you won't show the welcome, problem solved.

Halflight answered 29/11, 2014 at 23:8 Comment(1)
What about resetting the key? Suppose I roll out my new version of app and User update it then In this case also I want to perform a task (say, display welcome message) then what need to be done?Insessorial
C
4

In case of Swift In applicationdidFinishLaunchingWithOptions in AppDelegate Add:

if UserDefaults.standard.bool(forKey: "isFirstLaunch") {
            UserDefaults.standard.set(true, forKey: "isFirstLaunch")
            UserDefaults.standard.synchronize()
        }

And Use this wherever you want to.

let isFirstLaunch = UserDefaults.standard.value(forKey: "isFirstLaunch") as? Bool

    if isFirstLaunch {
    //It's the initial launch of application.
    }
    else {
    // not initial launch
    }
Conserve answered 11/3, 2016 at 11:15 Comment(0)
T
2

I did an edit of n13's post. This code seems cleaner to me. You can call as a class or instance function.

Also, according to apple docs you shouldn't call synchronize() since it's called periodically, unless the app is about to close. I have it called in the AppDelegate in applicationDidEnterBackground(). https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/#//apple_ref/occ/instm/NSUserDefaults/synchronize

    if NSUserDefaults().isFirstLaunchForUser("me") {
        print("First launch")
    } else {
        print("Not first launch")
    }


    if NSUserDefaults.isFirstLaunch() {
        print("First launch")
    } else {
        print("Not first launch")
    }



extension NSUserDefaults {

  static func isFirstLaunch() -> Bool {
      let firstLaunchFlag = "FirstLaunchFlag"

      if !standardUserDefaults().boolForKey(firstLaunchFlag) {
          standardUserDefaults().setBool(true, forKey: firstLaunchFlag)
          // standardUserDefaults().synchronize()
          return true
      }
      return false
    }

  // For multi user login
  func isFirstLaunchForUser(user: String) -> Bool {

      if !boolForKey(user) {
          setBool(true, forKey: user)
          // synchronize()
          return true
      }
      return false
  }
}
Tomasatomasina answered 25/8, 2016 at 0:55 Comment(0)
S
1

you can use UserDefaults to store the times that App has opened

First:

AppDelegate.swift

let userDefaults = UserDefaults.standard
var currentTimesOfOpenApp:Int = 0

func saveTimesOfOpenApp() -> Void {
    userDefaults.set(currentTimesOfOpenApp, forKey: "timesOfOpenApp")
}

func getCurrentTimesOfOpenApp() -> Int {
    return userDefaults.integer(forKey: "timesOfOpenApp") + 1
}

each time the App is open, you should add the property currentTimesOfOpenApp, so modify this property in the function func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        self.currentTimesOfOpenApp = getCurrentTimesOfOpenApp()
        return true
    }

in addition, when the app is closed, you should save the currentTimesOfOpenApp, that is important!

func applicationWillTerminate(_ application: UIApplication) {
        saveTimesOfOpenApp()
        self.saveContext()
    }

Second:

if you want to show the times, you can get this value form UserDefaults to display it on the Label.

ViewController.swift

let delegate = UIApplication.shared.delegate as! AppDelegate
let times = delegate.currentTimesOfOpenApp
timesToOpenAppLabel.text = "\(times)"

the App is open every time, the currentTimesOfOpenApp will be increase. if you delete the App, this value will be reset as 1.

Scaler answered 26/10, 2016 at 17:44 Comment(0)
B
-3
let applicationLaunchedOnce: Bool = {
        let launchedOnce = NSUserDefaults.standardUserDefaults().boolForKey(UserDefaultsService.ApplicationLaunchedOnce)
        if launchedOnce {
            return launchedOnce
        } else {
            NSUserDefaults.standardUserDefaults().setBool(true, forKey: UserDefaultsService.ApplicationLaunchedOnce)
            NSUserDefaults.standardUserDefaults().synchronize()
            return false
        }
    }()
Bassorilievo answered 14/3, 2016 at 17:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.