Skip to content

Commit ee3abff

Browse files
zhu-xiaoweixiaoweii
andauthored
fix: sessionId in first open and session start events (#54)
Co-authored-by: xiaoweii <[email protected]>
1 parent 63e1df1 commit ee3abff

File tree

11 files changed

+117
-112
lines changed

11 files changed

+117
-112
lines changed

Sources/Clickstream/AWSClickstreamPlugin+Configure.swift

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,15 @@ extension AWSClickstreamPlugin {
3737

3838
let sessionClient = SessionClient(clickstream: clickstream)
3939
clickstream.sessionClient = sessionClient
40-
let sessionProvider: () -> Session? = { [weak sessionClient] in
41-
guard let sessionClient else {
42-
fatalError("SessionClient was deallocated")
43-
}
44-
return sessionClient.getCurrentSession()
45-
}
4640
let eventRecorder = try EventRecorder(clickstream: clickstream)
4741
analyticsClient = try AnalyticsClient(clickstream: clickstream,
4842
eventRecorder: eventRecorder,
49-
sessionProvider: sessionProvider)
43+
sessionClient: sessionClient)
5044
clickstream.analyticsClient = analyticsClient
45+
5146
let networkMonitor = NWPathMonitor()
5247
clickstream.networkMonitor = networkMonitor
53-
sessionClient.initialSession()
48+
sessionClient.startActivityTracking()
5449
var autoFlushEventsTimer: DispatchSourceTimer?
5550
if configuration.sendEventsInterval != 0 {
5651
let timeInterval = TimeInterval(Double(configuration.sendEventsInterval) / 1_000)
@@ -66,7 +61,7 @@ extension AWSClickstreamPlugin {
6661
autoFlushEventsTimer: autoFlushEventsTimer,
6762
networkMonitor: networkMonitor
6863
)
69-
log.debug("init the sdk success")
64+
log.debug("initialize Clickstream SDK successful")
7065
}
7166

7267
// MARK: Internal

Sources/Clickstream/Dependency/Clickstream/Analytics/AnalyticsClient.swift

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,27 @@ protocol AnalyticsClientBehaviour {
2121
func submitEvents(isBackgroundMode: Bool)
2222
}
2323

24-
typealias SessionProvider = () -> Session?
25-
2624
class AnalyticsClient: AnalyticsClientBehaviour {
2725
private(set) var eventRecorder: AnalyticsEventRecording
28-
private let sessionProvider: SessionProvider
26+
private let sessionClient: SessionClient
2927
private(set) lazy var globalAttributes: [String: AttributeValue] = [:]
3028
private(set) var allUserAttributes: [String: Any] = [:]
3129
private(set) var simpleUserAttributes: [String: Any] = [:]
3230
private let clickstream: ClickstreamContext
3331
private(set) var userId: String?
34-
var autoRecordClient: AutoRecordEventClient?
32+
var autoRecordClient: AutoRecordEventClient
3533

3634
init(clickstream: ClickstreamContext,
3735
eventRecorder: AnalyticsEventRecording,
38-
sessionProvider: @escaping SessionProvider) throws
36+
sessionClient: SessionClient) throws
3937
{
4038
self.clickstream = clickstream
4139
self.eventRecorder = eventRecorder
42-
self.sessionProvider = sessionProvider
40+
self.sessionClient = sessionClient
4341
self.userId = UserDefaultsUtil.getCurrentUserId(storage: clickstream.storage)
4442
self.allUserAttributes = UserDefaultsUtil.getUserAttributes(storage: clickstream.storage)
43+
self.autoRecordClient = sessionClient.autoRecordClient
4544
self.simpleUserAttributes = getSimpleUserAttributes()
46-
self.autoRecordClient = (clickstream.sessionClient as? SessionClient)?.autoRecordClient
4745
}
4846

4947
func addGlobalAttribute(_ attribute: AttributeValue, forKey key: String) {
@@ -116,7 +114,7 @@ class AnalyticsClient: AnalyticsClientBehaviour {
116114
let event = ClickstreamEvent(eventType: eventType,
117115
appId: clickstream.configuration.appId,
118116
uniqueId: clickstream.userUniqueId,
119-
session: sessionProvider(),
117+
session: sessionClient.getCurrentSession(),
120118
systemInfo: clickstream.systemInfo,
121119
netWorkType: clickstream.networkMonitor.netWorkType)
122120
return event
@@ -135,15 +133,13 @@ class AnalyticsClient: AnalyticsClientBehaviour {
135133
for (key, attribute) in globalAttributes {
136134
event.addGlobalAttribute(attribute, forKey: key)
137135
}
138-
if let autoRecordClient {
139-
if autoRecordClient.lastScreenName != nil {
140-
event.addGlobalAttribute(autoRecordClient.lastScreenName!,
141-
forKey: Event.ReservedAttribute.SCREEN_NAME)
142-
}
143-
if autoRecordClient.lastScreenUniqueId != nil {
144-
event.addGlobalAttribute(autoRecordClient.lastScreenUniqueId!,
145-
forKey: Event.ReservedAttribute.SCREEN_UNIQUEID)
146-
}
136+
if autoRecordClient.lastScreenName != nil {
137+
event.addGlobalAttribute(autoRecordClient.lastScreenName!,
138+
forKey: Event.ReservedAttribute.SCREEN_NAME)
139+
}
140+
if autoRecordClient.lastScreenUniqueId != nil {
141+
event.addGlobalAttribute(autoRecordClient.lastScreenUniqueId!,
142+
forKey: Event.ReservedAttribute.SCREEN_UNIQUEID)
147143
}
148144
if event.eventType == Event.PresetEvent.PROFILE_SET {
149145
event.setUserAttribute(allUserAttributes)

Sources/Clickstream/Dependency/Clickstream/AutoRecord/AutoRecordEventClient.swift

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ class AutoRecordEventClient {
4848
if !clickstream.configuration.isTrackScreenViewEvents {
4949
return
5050
}
51-
let event = clickstream.analyticsClient.createEvent(withEventType: Event.PresetEvent.SCREEN_VIEW)
52-
recordScreenViewEvent(event, screenName, screenPath, screenUniqueId)
51+
if clickstream.analyticsClient != nil {
52+
let event = clickstream.analyticsClient.createEvent(withEventType: Event.PresetEvent.SCREEN_VIEW)
53+
recordScreenViewEvent(event, screenName, screenPath, screenUniqueId)
54+
}
5355
}
5456

5557
func recordViewScreenManually(_ event: ClickstreamEvent) {
@@ -176,17 +178,18 @@ class AutoRecordEventClient {
176178
}
177179
}
178180

179-
func handleAppStart() {
180-
if isFirstTime {
181-
checkAppVersionUpdate(clickstream: clickstream)
182-
checkOSVersionUpdate(clickstream: clickstream)
183-
}
181+
func handleFirstOpen() {
182+
checkAppVersionUpdate(clickstream: clickstream)
183+
checkOSVersionUpdate(clickstream: clickstream)
184184
if isFirstOpen {
185185
let event = clickstream.analyticsClient.createEvent(withEventType: Event.PresetEvent.FIRST_OPEN)
186186
recordEvent(event)
187187
UserDefaultsUtil.saveIsFirstOpen(storage: clickstream.storage, isFirstOpen: "false")
188188
isFirstOpen = false
189189
}
190+
}
191+
192+
func handleAppStart() {
190193
let event = clickstream.analyticsClient.createEvent(withEventType: Event.PresetEvent.APP_START)
191194
event.addAttribute(isFirstTime, forKey: Event.ReservedAttribute.IS_FIRST_TIME)
192195
recordEvent(event)
@@ -229,7 +232,7 @@ class AutoRecordEventClient {
229232

230233
func recordEvent(_ event: ClickstreamEvent) {
231234
do {
232-
try clickstream.analyticsClient.record(event)
235+
try clickstream.analyticsClient?.record(event)
233236
} catch {
234237
log.error("Failed to record event with error:\(error)")
235238
}

Sources/Clickstream/Dependency/Clickstream/Session/Session.swift

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class Session: Codable {
1212
let startTime: Int64
1313
let sessionIndex: Int
1414
private(set) var pauseTime: Int64?
15+
var isRecorded = false
1516

1617
init(uniqueId: String, sessionIndex: Int) {
1718
self.sessionId = Self.generateSessionId(uniqueId: uniqueId)
@@ -27,19 +28,22 @@ class Session: Codable {
2728
self.sessionIndex = sessionIndex
2829
}
2930

30-
static func getCurrentSession(clickstream: ClickstreamContext) -> Session {
31-
let storedSession = UserDefaultsUtil.getSession(storage: clickstream.storage)
32-
var sessionIndex = 1
33-
if storedSession != nil {
34-
if Date().millisecondsSince1970 - storedSession!.pauseTime!
31+
static func getCurrentSession(clickstream: ClickstreamContext, previousSession: Session? = nil) -> Session {
32+
var session = previousSession
33+
if session == nil {
34+
session = UserDefaultsUtil.getSession(storage: clickstream.storage)
35+
}
36+
if session != nil {
37+
if session!.isNewSession || Date().millisecondsSince1970 - session!.pauseTime!
3538
< clickstream.configuration.sessionTimeoutDuration
3639
{
37-
return storedSession!
40+
return session!
3841
} else {
39-
sessionIndex = storedSession!.sessionIndex + 1
42+
return Session(uniqueId: clickstream.userUniqueId, sessionIndex: session!.sessionIndex + 1)
4043
}
44+
} else {
45+
return Session(uniqueId: clickstream.userUniqueId, sessionIndex: 1)
4146
}
42-
return Session(uniqueId: clickstream.userUniqueId, sessionIndex: sessionIndex)
4347
}
4448

4549
var isNewSession: Bool {

Sources/Clickstream/Dependency/Clickstream/Session/SessionClient.swift

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ import Foundation
1010

1111
protocol SessionClientBehaviour: AnyObject {
1212
func startActivityTracking()
13-
func initialSession()
1413
func storeSession()
1514
func onManualScreenView(_ event: ClickstreamEvent)
1615
}
1716

1817
class SessionClient: SessionClientBehaviour {
19-
private var session: Session?
18+
private var session: Session
2019
private let clickstream: ClickstreamContext
2120
private let activityTracker: ActivityTrackerBehaviour
2221
private let sessionClientQueue = DispatchQueue(label: Constants.queue,
@@ -25,9 +24,9 @@ class SessionClient: SessionClientBehaviour {
2524

2625
init(activityTracker: ActivityTrackerBehaviour? = nil, clickstream: ClickstreamContext) {
2726
self.clickstream = clickstream
28-
self.activityTracker = activityTracker ?? ActivityTracker()
27+
self.session = Session.getCurrentSession(clickstream: clickstream)
2928
self.autoRecordClient = AutoRecordEventClient(clickstream: clickstream)
30-
startActivityTracking()
29+
self.activityTracker = activityTracker ?? ActivityTracker()
3130
}
3231

3332
func startActivityTracking() {
@@ -39,31 +38,31 @@ class SessionClient: SessionClientBehaviour {
3938
}
4039
}
4140

42-
func initialSession() {
43-
session = Session.getCurrentSession(clickstream: clickstream)
44-
if session!.isNewSession {
45-
autoRecordClient.recordSessionStartEvent()
46-
autoRecordClient.setIsEntrances()
47-
autoRecordClient.recordScreenViewAfterSessionStart()
48-
}
49-
}
50-
5141
func storeSession() {
52-
if session != nil {
53-
session?.pause()
54-
UserDefaultsUtil.saveSession(storage: clickstream.storage, session: session!)
55-
}
42+
session.pause()
43+
UserDefaultsUtil.saveSession(storage: clickstream.storage, session: session)
5644
}
5745

58-
func getCurrentSession() -> Session? {
46+
func getCurrentSession() -> Session {
5947
session
6048
}
6149

6250
private func handleAppEnterForeground() {
6351
log.debug("Application entered the foreground.")
52+
autoRecordClient.handleFirstOpen()
53+
session = Session.getCurrentSession(clickstream: clickstream, previousSession: session)
6454
autoRecordClient.handleAppStart()
6555
autoRecordClient.updateLastScreenStartTimestamp(Date().millisecondsSince1970)
66-
initialSession()
56+
handleSesionStart()
57+
}
58+
59+
private func handleSesionStart() {
60+
if session.isNewSession, !session.isRecorded {
61+
autoRecordClient.recordSessionStartEvent()
62+
autoRecordClient.setIsEntrances()
63+
autoRecordClient.recordScreenViewAfterSessionStart()
64+
session.isRecorded = true
65+
}
6766
}
6867

6968
private func handleAppEnterBackground() {

Tests/ClickstreamTests/Clickstream/AnalyticsClientTest.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,16 @@ class AnalyticsClientTest: XCTestCase {
2424
isTrackAppExceptionEvents: false,
2525
isCompressEvents: false)
2626
clickstream = try ClickstreamContext(with: contextConfiguration)
27+
let sessionClient = SessionClient(clickstream: clickstream)
28+
clickstream.sessionClient = sessionClient
29+
2730
clickstream.networkMonitor = MockNetworkMonitor()
2831
eventRecorder = MockEventRecorder()
29-
session = Session(uniqueId: "uniqueId", sessionIndex: 1)
32+
session = sessionClient.getCurrentSession()
3033
analyticsClient = try AnalyticsClient(
3134
clickstream: clickstream,
3235
eventRecorder: eventRecorder,
33-
sessionProvider: {
34-
self.session
35-
}
36+
sessionClient: sessionClient
3637
)
3738
}
3839

Tests/ClickstreamTests/Clickstream/AutoRecordEventClientTest.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class AutoRecordEventClientTest: XCTestCase {
3535
let analyticsClient = try AnalyticsClient(
3636
clickstream: clickstream,
3737
eventRecorder: eventRecorder,
38-
sessionProvider: { nil }
38+
sessionClient: sessionClient
3939
)
4040
clickstream.analyticsClient = analyticsClient
4141

@@ -78,6 +78,7 @@ class AutoRecordEventClientTest: XCTestCase {
7878
}
7979

8080
func testOneScreenView() {
81+
sessionClient.startActivityTracking()
8182
activityTracker.callback?(.runningInForeground)
8283
autoRecordEventClient.setIsEntrances()
8384
let viewController = MockViewControllerA()

Tests/ClickstreamTests/Clickstream/EventRecorderTest.swift

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class EventRecorderTest: XCTestCase {
2222
var clickstream: ClickstreamContext!
2323
var server: HttpServer!
2424
var activityTracker: MockActivityTracker!
25+
var sessionClient: SessionClient!
2526

2627
override func setUp() async throws {
2728
do {
@@ -56,18 +57,12 @@ class EventRecorderTest: XCTestCase {
5657
dbUtil = eventRecorder.dbUtil
5758

5859
activityTracker = MockActivityTracker()
59-
let sessionClient = SessionClient(activityTracker: activityTracker, clickstream: clickstream)
60+
sessionClient = SessionClient(activityTracker: activityTracker, clickstream: clickstream)
6061
clickstream.sessionClient = sessionClient
61-
let sessionProvider: () -> Session? = { [weak sessionClient] in
62-
guard let sessionClient else {
63-
fatalError("SessionClient was deallocated")
64-
}
65-
return sessionClient.getCurrentSession()
66-
}
6762
let analyticsClient = try AnalyticsClient(
6863
clickstream: clickstream,
6964
eventRecorder: eventRecorder,
70-
sessionProvider: sessionProvider
65+
sessionClient: sessionClient
7166
)
7267
clickstream.analyticsClient = analyticsClient
7368
clickstream.networkMonitor = MockNetworkMonitor()
@@ -408,6 +403,7 @@ class EventRecorderTest: XCTestCase {
408403
}
409404

410405
func testBackgroundModeAutoSendRequest() throws {
406+
sessionClient.startActivityTracking()
411407
activityTracker.callback?(.runningInForeground)
412408
try eventRecorder.save(clickstreamEvent)
413409
activityTracker.callback?(.runningInBackground)

0 commit comments

Comments
 (0)