检测iOS应用的首次启动

70

我正在尝试找到一种在Swift中检测应用首次启动的方法。


3
我在Stackoverflow看到了一个话题,但它已经过时了(使用的是Objective-C)。正如下面的所有答案所显示的那样,无论您是在Objective-C还是Swift中编码,解决您问题的方法基本上是相同的,而且这个方法已经有一段时间了。 - Nicolas Miari
9个回答

166

通常情况下,您会将一个值写入NSUserDefaults以指示应用程序之前已启动过。

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

更新 - 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")
}

2
你写的代码是行不通的。firstLaunch 是一个可选类型,你没有处理它。此外,它将为 nil,因为你没有注册一个值。 - matt
12
我已经测试过,它运行得很好。boolForKey 不会返回可选项,如果该值不存在,则返回 false。 - Jon Shier
1
好的!那就好。 :) 我没有意识到 boolForKey 的巧妙改进。 - matt
1
如果是第一次启动 { println("不是第一次启动。") } 这并没有太多意义;-) - Tim
1
@TimCastelijns 是的,我想应该改成 launchedBefore 或者其他什么名字。 - Jon Shier
显示剩余5条评论

44

我经常需要这个,所以我把它放在一个类别里。

一般用途:

let isFirstLaunch = UserDefaults.isFirstLaunch()

在您的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
}

一些重要的考虑:

  • 此标志仅在第一次调用时设置。 如果您想在不同屏幕中多次了解第一次启动的信息,请设置一个变量,以后可以参考“optionallyStoreTheFirstLaunchFlag”示例。
  • 在iOS中,应用程序通常永远不会关闭。 应用程序会被置于后台、前台、状态保存到闪存中,但只有在用户强制关闭(很少发生)或用户重新启动手机时才会重新启动。 因此,如果将其存储在变量中,它可能会长期保留。 在显示所有教程屏幕等内容后,请手动重置它。

Swift 4

将以下代码放入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
    }
}

提醒其他用户,您需要在viewDidAppear部分添加以下内容:如果是第一次启动 { 这里是说明 } 否则 { 打印("不是首次启动") } - David Sanford
1
你可以按照自己的方式使用它,但要记住它只会在第一次调用时产生“true”值。如果它被用于多个视图中,你需要注意这一点。 - n13
如果您希望在整个应用程序的生命周期中始终如一,直到终止,请查看我的下面的答案。 - jalone
@MihaiDamian 我不确定你在说什么。如果你不调用它,它就不会起作用。这通常是所有代码的情况吧?也许我应该澄清一下用法——也许你有一个代码路径,在启动时没有调用它? - n13
依赖于“iOS应用通常不会关闭”是一个非常糟糕的想法。苹果在整个文档中都非常明确地表示,系统保留随时终止任何进程的权利,出于任何原因 - 特别是在更积极地管理内存和系统资源以节省能源的较新版本的iOS上。 - Sam Spencer
显示剩余2条评论

14

Swift 3

extension UserDefaults {

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

Swift 5(属性包装器)

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
}

使用方法:

UserDefaultsStore.hasLaunchBefore = false

对于属性包装器的尝试,我还没有尝试过+1。 :) - boraseoksoon

8

为了让方法在整个首次启动过程中始终返回true,我对用户n13的答案进行了一些改进。

  • 成为UIApplication的扩展

只需在需要的任何地方使用UIApplication.isFirstLaunch()即可,并确保在首次执行期间至少调用一次

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
    }
}

为什么把字符串存储在用户默认设置中而不是布尔值?:O - Tarvo Mäesepp
我刚刚在飞行中编辑了n13的答案,因为有人请求。还有更多需要改进的地方,但我猜只是为了简洁起见,避免这种情况发生https://dev59.com/O2865IYBdhLWcg3wYNnj#20934386 - jalone
1
我的 Swift 版本存储了一个布尔值 FYI ;) - n13
1
这个答案应该完全重写 :/ - jalone

5
使用NSUserDefaults。注册一个值为false的BOOL键。在启动时读取该键;如果它是false,则将其设置为true并显示欢迎信息。下一次启动时,它将是true,您将不会显示欢迎信息,问题解决了。

1
重置密钥怎么样?假设我推出了我的新应用程序版本,用户更新它,那么在这种情况下,如果我想执行一个任务(比如显示欢迎消息),需要做什么? - Tejas

4
在AppDelegate的applicationdidFinishLaunchingWithOptions中添加以下代码:

In case of Swift

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

并在您想要使用的任何地方使用它。

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

    if isFirstLaunch {
    //It's the initial launch of application.
    }
    else {
    // not initial launch
    }

2

我对n13的帖子进行了编辑。在我看来,这段代码更加简洁。您可以将其作为类或实例函数调用。

此外,根据苹果文档,除非应用程序即将关闭,否则不应调用 synchronize() ,因为它会定期被调用。我在AppDelegate中的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
  }
}

1
你可以使用UserDefaults来存储应用程序已经打开的次数。 第一步:

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
}

每次打开应用程序时,您都应该添加属性 currentTimesOfOpenApp ,因此请在函数 func application(_ application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplicationLaunchOptionsKey:Any]?) -&gt; Bool 中修改此属性。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        self.currentTimesOfOpenApp = getCurrentTimesOfOpenApp()
        return true
    }

此外,当应用程序关闭时,你应该保存当前打开应用程序的次数,这非常重要!
func applicationWillTerminate(_ application: UIApplication) {
        saveTimesOfOpenApp()
        self.saveContext()
    }

第二步:

如果你想显示时间,你可以从UserDefaults获取此值并在标签上显示。

ViewController.swift

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

每次打开应用时,当前应用打开次数将增加。如果您删除了该应用程序,则此值将重置为1。

-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
        }
    }()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接