Skip to content

Commit

Permalink
fix: Improve application opened event reliability (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
crleona authored May 15, 2024
1 parent 7777cdd commit d3b9de7
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 36 deletions.
24 changes: 17 additions & 7 deletions Sources/Amplitude/Plugins/iOS/IOSLifecycleMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
UIApplication.willEnterForegroundNotification,
UIApplication.didFinishLaunchingNotification,
]
private var trackAppOpenedEventOnEnterForeground: Bool = true
private var utils: DefaultEventUtils?

override init() {
Expand Down Expand Up @@ -67,22 +66,35 @@

func applicationWillEnterForeground(notification: NSNotification) {
let timestamp = Int64(NSDate().timeIntervalSince1970 * 1000)

let fromBackground: Bool
if let sharedApplication = application {
switch sharedApplication.applicationState {
case .active, .inactive:
fromBackground = false
case .background:
fromBackground = true
@unknown default:
fromBackground = false
}
} else {
fromBackground = false
}

self.amplitude?.onEnterForeground(timestamp: timestamp)
if self.amplitude?.configuration.defaultTracking.appLifecycles == true && self.trackAppOpenedEventOnEnterForeground {
if self.amplitude?.configuration.defaultTracking.appLifecycles == true {
let info = Bundle.main.infoDictionary
let currentBuild = info?["CFBundleVersion"] as? String
let currentVersion = info?["CFBundleShortVersionString"] as? String
self.amplitude?.track(eventType: Constants.AMP_APPLICATION_OPENED_EVENT, eventProperties: [
Constants.AMP_APP_BUILD_PROPERTY: currentBuild ?? "",
Constants.AMP_APP_VERSION_PROPERTY: currentVersion ?? "",
Constants.AMP_APP_FROM_BACKGROUND_PROPERTY: true,
Constants.AMP_APP_FROM_BACKGROUND_PROPERTY: fromBackground,
])
}
}

func didEnterBackground(notification: NSNotification) {
self.trackAppOpenedEventOnEnterForeground = true

let timestamp = Int64(NSDate().timeIntervalSince1970 * 1000)
self.amplitude?.onExitForeground(timestamp: timestamp)
if self.amplitude?.configuration.defaultTracking.appLifecycles == true {
Expand All @@ -91,8 +103,6 @@
}

func applicationDidFinishLaunchingNotification(notification: NSNotification) {
self.trackAppOpenedEventOnEnterForeground = false

utils?.trackAppUpdatedInstalledEvent()
}
}
Expand Down
5 changes: 0 additions & 5 deletions Sources/Amplitude/Utilities/DefaultEventUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ public class DefaultEventUtils {
Constants.AMP_APP_PREVIOUS_VERSION_PROPERTY: previousVersion ?? "",
])
}
self.amplitude?.track(eventType: Constants.AMP_APPLICATION_OPENED_EVENT, eventProperties: [
Constants.AMP_APP_BUILD_PROPERTY: currentBuild ?? "",
Constants.AMP_APP_VERSION_PROPERTY: currentVersion ?? "",
Constants.AMP_APP_FROM_BACKGROUND_PROPERTY: false,
])
}

if currentBuild != previousBuild {
Expand Down
66 changes: 42 additions & 24 deletions Tests/AmplitudeTests/AmplitudeIOSTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,12 @@ final class AmplitudeIOSTests: XCTestCase {
let currentVersion = info?["CFBundleShortVersionString"] ?? ""

let events = storageMem.events()
XCTAssertEqual(events.count, 2)
XCTAssertEqual(events.count, 1)
XCTAssertEqual(events[0].eventType, Constants.AMP_APPLICATION_INSTALLED_EVENT)
XCTAssertEqual(getDictionary(events[0].eventProperties!), [
Constants.AMP_APP_BUILD_PROPERTY: currentBuild,
Constants.AMP_APP_VERSION_PROPERTY: currentVersion
])
XCTAssertEqual(events[1].eventType, Constants.AMP_APPLICATION_OPENED_EVENT)
XCTAssertEqual(getDictionary(events[1].eventProperties!), [
Constants.AMP_APP_BUILD_PROPERTY: currentBuild,
Constants.AMP_APP_VERSION_PROPERTY: currentVersion,
Constants.AMP_APP_FROM_BACKGROUND_PROPERTY: false
])
}

func testDidFinishLaunching_ApplicationUpdated() throws {
Expand All @@ -69,20 +63,14 @@ final class AmplitudeIOSTests: XCTestCase {
let currentVersion = info?["CFBundleShortVersionString"] ?? ""

let events = storageMem.events()
XCTAssertEqual(events.count, 2)
XCTAssertEqual(events.count, 1)
XCTAssertEqual(events[0].eventType, Constants.AMP_APPLICATION_UPDATED_EVENT)
XCTAssertEqual(getDictionary(events[0].eventProperties!), [
Constants.AMP_APP_BUILD_PROPERTY: currentBuild,
Constants.AMP_APP_VERSION_PROPERTY: currentVersion,
Constants.AMP_APP_PREVIOUS_BUILD_PROPERTY: "abc",
Constants.AMP_APP_PREVIOUS_VERSION_PROPERTY: "xyz"
])
XCTAssertEqual(events[1].eventType, Constants.AMP_APPLICATION_OPENED_EVENT)
XCTAssertEqual(getDictionary(events[1].eventProperties!), [
Constants.AMP_APP_BUILD_PROPERTY: currentBuild,
Constants.AMP_APP_VERSION_PROPERTY: currentVersion,
Constants.AMP_APP_FROM_BACKGROUND_PROPERTY: false
])
}

func testDidFinishLaunching_ApplicationOpened() throws {
Expand All @@ -105,16 +93,30 @@ final class AmplitudeIOSTests: XCTestCase {
amplitude.waitForTrackingQueue()

let events = storageMem.events()
XCTAssertEqual(events.count, 1)
XCTAssertEqual(events[0].eventType, Constants.AMP_APPLICATION_OPENED_EVENT)
XCTAssertEqual(getDictionary(events[0].eventProperties!), [
Constants.AMP_APP_BUILD_PROPERTY: currentBuild,
Constants.AMP_APP_VERSION_PROPERTY: currentVersion,
Constants.AMP_APP_FROM_BACKGROUND_PROPERTY: false
])
XCTAssertEqual(events.count, 0)
}

func testWillEnterForeground() throws {
func testWillEnterForegroundFromBackground() throws {
class TestApplication {

static let sharedTest = TestApplication()

@objc class var shared: AnyObject {
return sharedTest
}

@objc var applicationState: UIApplication.State = .active
}

guard let originalMethod = class_getClassMethod(UIApplication.self, #selector(getter: UIApplication.shared)),
let testMethod = class_getClassMethod(TestApplication.self, #selector(getter: TestApplication.shared)) else {
XCTFail("Unable to find methods to swizzle")
return
}
let originalImplementation = method_getImplementation(originalMethod)
let testImplementation = method_getImplementation(testMethod)
method_setImplementation(originalMethod, testImplementation)

let configuration = Configuration(
apiKey: "api-key",
storageProvider: storageMem,
Expand All @@ -127,17 +129,33 @@ final class AmplitudeIOSTests: XCTestCase {
let currentVersion = info?["CFBundleShortVersionString"] ?? ""

let amplitude = Amplitude(configuration: configuration)

TestApplication.sharedTest.applicationState = .inactive
NotificationCenter.default.post(name: UIApplication.willEnterForegroundNotification, object: nil)

TestApplication.sharedTest.applicationState = .background
NotificationCenter.default.post(name: UIApplication.willEnterForegroundNotification, object: nil)

amplitude.waitForTrackingQueue()

let events = storageMem.events()
XCTAssertEqual(events.count, 1)
XCTAssertEqual(events.count, 2)
XCTAssertEqual(events[0].eventType, Constants.AMP_APPLICATION_OPENED_EVENT)
XCTAssertEqual(getDictionary(events[0].eventProperties!), [
Constants.AMP_APP_BUILD_PROPERTY: currentBuild,
Constants.AMP_APP_VERSION_PROPERTY: currentVersion,
Constants.AMP_APP_FROM_BACKGROUND_PROPERTY: true
Constants.AMP_APP_FROM_BACKGROUND_PROPERTY: false
])

XCTAssertEqual(events[1].eventType, Constants.AMP_APPLICATION_OPENED_EVENT)
XCTAssertEqual(getDictionary(events[1].eventProperties!), [
Constants.AMP_APP_BUILD_PROPERTY: currentBuild,
Constants.AMP_APP_VERSION_PROPERTY: currentVersion,
Constants.AMP_APP_FROM_BACKGROUND_PROPERTY: false
])

// re-replace UIApplication.shared
method_setImplementation(originalMethod, originalImplementation)
}

func testDidEnterBackground() throws {
Expand Down

0 comments on commit d3b9de7

Please sign in to comment.