Skip to content

Commit 0e9f9ae

Browse files
SessionsInitiator triggers new session for every foregrounding after 30 minutes of background (#10360)
* foreground after 30 minutes of background triggers new session * PR review * PR comments * style * copyright * fix watchOS * remove MockDate * attempt to resolve conflict * watchOS comment and rename currentTimeProvider * change OSX to macOS
1 parent e4ef6b0 commit 0e9f9ae

File tree

2 files changed

+105
-2
lines changed

2 files changed

+105
-2
lines changed

FirebaseSessions/Sources/SessionInitiator.swift

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313
// limitations under the License.
1414

1515
import Foundation
16+
#if os(macOS)
17+
import Cocoa
18+
import AppKit
19+
#elseif os(watchOS)
20+
import WatchKit
21+
#endif
1622

1723
///
1824
/// The SessionInitiator is responsible for:
@@ -22,8 +28,73 @@ import Foundation
2228
/// and comes to the foreground.
2329
///
2430
class SessionInitiator {
31+
let sessionTimeout: TimeInterval = 30 * 60 // 30 minutes
32+
let currentTime: () -> Date
33+
var backgroundTime = Date.distantFuture
34+
var initiateSessionStart: () -> Void = {}
35+
36+
init(currentTimeProvider: @escaping () -> Date = Date.init) {
37+
currentTime = currentTimeProvider
38+
}
39+
2540
func beginListening(initiateSessionStart: @escaping () -> Void) {
26-
// Only cold start is implemented right now
27-
initiateSessionStart()
41+
self.initiateSessionStart = initiateSessionStart
42+
self.initiateSessionStart()
43+
44+
let notificationCenter = NotificationCenter.default
45+
#if os(iOS) || os(tvOS)
46+
notificationCenter.addObserver(
47+
self,
48+
selector: #selector(appBackgrounded),
49+
name: UIApplication.didEnterBackgroundNotification,
50+
object: nil
51+
)
52+
notificationCenter.addObserver(
53+
self,
54+
selector: #selector(appForegrounded),
55+
name: UIApplication.didBecomeActiveNotification,
56+
object: nil
57+
)
58+
#elseif os(macOS)
59+
notificationCenter.addObserver(
60+
self,
61+
selector: #selector(appBackgrounded),
62+
name: NSApplication.didResignActiveNotification,
63+
object: nil
64+
)
65+
notificationCenter.addObserver(
66+
self,
67+
selector: #selector(appForegrounded),
68+
name: NSApplication.didBecomeActiveNotification,
69+
object: nil
70+
)
71+
#elseif os(watchOS)
72+
// Versions below WatchOS 7 do not support lifecycle events
73+
if #available(watchOSApplicationExtension 7.0, *) {
74+
notificationCenter.addObserver(
75+
self,
76+
selector: #selector(appBackgrounded),
77+
name: WKExtension.applicationDidEnterBackgroundNotification,
78+
object: nil
79+
)
80+
notificationCenter.addObserver(
81+
self,
82+
selector: #selector(appForegrounded),
83+
name: WKExtension.applicationDidBecomeActiveNotification,
84+
object: nil
85+
)
86+
}
87+
#endif
88+
}
89+
90+
@objc func appBackgrounded() {
91+
backgroundTime = currentTime()
92+
}
93+
94+
@objc func appForegrounded() {
95+
let interval = currentTime().timeIntervalSince(backgroundTime)
96+
if interval > sessionTimeout {
97+
initiateSessionStart()
98+
}
2899
}
29100
}

FirebaseSessions/Tests/Unit/InitiatorTests.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import XCTest
1616
@testable import FirebaseSessions
1717

1818
class InitiatorTests: XCTestCase {
19+
// 2021-11-01 @ 00:00:00 (EST)
20+
let date = Date(timeIntervalSince1970: 1_635_739_200)
21+
1922
func test_beginListening_initiatesColdStart() throws {
2023
let initiator = SessionInitiator()
2124
var initiateCalled = false
@@ -24,4 +27,33 @@ class InitiatorTests: XCTestCase {
2427
}
2528
assert(initiateCalled)
2629
}
30+
31+
func test_appForegrounded_initiatesNewSession() throws {
32+
// Given
33+
var pausedClock = date
34+
let initiator = SessionInitiator(currentTimeProvider: { pausedClock })
35+
var sessionCount = 0
36+
initiator.beginListening {
37+
sessionCount += 1
38+
}
39+
assert(sessionCount == 1)
40+
41+
// When
42+
// Background, advance time by 30 minutes + 1 second, then foreground
43+
initiator.appBackgrounded()
44+
pausedClock.addTimeInterval(30 * 60 + 1)
45+
initiator.appForegrounded()
46+
// Then
47+
// Session count increases because time spent in background > 30 minutes
48+
assert(sessionCount == 2)
49+
50+
// When
51+
// Background, advance time by exactly 30 minutes, then foreground
52+
initiator.appBackgrounded()
53+
pausedClock.addTimeInterval(30 * 60)
54+
initiator.appForegrounded()
55+
// Then
56+
// Session count doesn't increase because time spent in background <= 30 minutes
57+
assert(sessionCount == 2)
58+
}
2759
}

0 commit comments

Comments
 (0)