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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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