Detecting first launch, app upgrades and other useful launch informations

One of the first things every iOS developer should add to their project is a way to detect what is happening at launch. It doesn’t have to be complicated, but trust me, this can potentially save you some trouble later on.

I usually create a BaseAppDelegate class that will be responsible for detecting the following:

  • is it the first time the user launch the app?
  • how many times did the user launch count?
  • is this launch the first launch after an app upgrade?
  • when was last time the user launched the app before this launch?

Here is the code I usually put in this BaseAppDelegate class:

//
// BaseAppDelegate.swift
//
// Created by Cyril Chandelier on 21/04/2018.
// Copyright © 2018 Cyril Chandelier. All rights reserved.
//
import UIKit
class BaseAppDelegate: UIResponder, UIApplicationDelegate {
// MARK: – Dependencies
lazy var bundle: Bundle = Bundle.main
lazy var userDefaults: UserDefaults = UserDefaults.standard
// MARK: – UIApplicationDelegate methods
@discardableResult func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
print("Initializing app")
// Try to detect first launch
if launchCount == 0 {
print("…first launch detected")
applicationFirstLaunch()
}
// Update app launches count
launchCount += 1
print("\(launchCount) launches")
// Try to detect version upgrade
let currentVersion = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString")
as! String
if let lastLaunchVersion = lastLaunchVersion, currentVersion != lastLaunchVersion {
print("…upgrade detected")
applicationDidUpgrade(from: lastLaunchVersion, to: currentVersion)
}
// Update last known version if new
if lastLaunchVersion != currentVersion {
print("…saving new version: \(currentVersion)")
lastLaunchVersion = currentVersion
}
// Update last known launch date
print("…saving current launch date")
appLastLaunchDate = Date()
// Make sure user defaults are saved
userDefaults.synchronize()
return true
}
// MARK: – Optional methods to override
func applicationFirstLaunch() {}
func applicationDidUpgrade(from: String, to: String) {}
// MARK: – Utilities
private(set) var launchCount: Int {
get {
return userDefaults.integer(forKey: Keys.appLaunchCount)
}
set {
userDefaults.set(newValue, forKey: Keys.appLaunchCount)
}
}
private(set) var lastLaunchVersion: String? {
get {
return userDefaults.string(forKey: Keys.appLastLaunchVersion)
}
set {
if let newValue = newValue {
userDefaults.set(newValue, forKey: Keys.appLastLaunchVersion)
} else {
userDefaults.removeObject(forKey: Keys.appLastLaunchVersion)
}
}
}
private(set) var appLastLaunchDate: Date? {
get {
return userDefaults.object(forKey: Keys.appLastLaunchDate) as? Date
}
set {
if let newValue = newValue {
userDefaults.set(newValue, forKey: Keys.appLastLaunchDate)
} else {
userDefaults.removeObject(forKey: Keys.appLastLaunchDate)
}
}
}
// MARK: – User default keys
private struct Keys {
static let appLaunchCount = "appLaunchCount"
static let appLastLaunchVersion = "appLastLaunchVersion"
static let appLastLaunchDate = "appLastLaunchDate"
}
}

You just need to make your AppDelegate extends BaseAppDelegate, and call the super method in application(_:didFinishLaunchingWithOptions). Then, you can choose (or not) to override (and therefore implement something for) the applicationFirstLaunch() and/or applicationDidUpgrade(from:to:) methods.

Here are a couple use cases where having this super-class reveals itself handy:

  • I want to know how many times a users came into the app for my analytics
  • I want to know when a users re-open the app after a while, to customize his experience as a returning user
  • I want to show a “What’s new” popup to my returning users who upgraded their app
  • my app was a paid app before, and now it’s free with In-App Purchases to unlock some content, but I don’t want my users who already paid to hit my paywall

Leave a Reply

Your email address will not be published. Required fields are marked *