1
1
//
2
2
// File.swift
3
- //
3
+ //
4
4
//
5
5
// Created by Brandon Sneed on 5/5/22.
6
6
//
@@ -14,8 +14,6 @@ public class AnalyticsJS: JSExport {
14
14
15
15
internal weak var analytics : Analytics ?
16
16
17
- internal var addedPlugins = [ ( String? , LivePlugin) ] ( )
18
-
19
17
internal lazy var currentLivePluginVersion : String ? = {
20
18
return LivePlugins . currentLivePluginVersion ( )
21
19
} ( )
@@ -36,60 +34,95 @@ public class AnalyticsJS: JSExport {
36
34
Self . existingInstances. removeAll ( where: { $0 === self . analytics } )
37
35
}
38
36
37
+
39
38
static func insertOrigin( event: RawEvent ? , data: [ String : Any ] ) -> RawEvent ? {
40
39
guard var working = event else { return event }
41
- if let newContext = try ? working. context? . add ( value: data, forKey: " __eventOrigin " ) {
40
+ if let newContext = try ? working. context? . add (
41
+ value: data,
42
+ forKey: " __eventOrigin "
43
+ ) {
42
44
working. context = newContext
43
45
}
44
46
return working
45
47
}
46
48
47
49
internal func originMarkerEnrichment( event: RawEvent ? ) -> RawEvent ? {
48
50
return Self . insertOrigin ( event: event, data: [
49
- " type " : " signals " ,
51
+ " type " : " js " ,
50
52
" version " : currentLivePluginVersion ?? " "
51
53
] )
52
54
}
53
55
56
+ private func contextEnrichment( with context: [ String : Any ] ? ) -> EnrichmentClosure {
57
+ return { event in
58
+ guard var working = event, let context = context else {
59
+ return event
60
+ }
61
+
62
+ // Get existing context as dictionary and merge with new context
63
+ var mergedContext = working. context? . dictionaryValue ?? [ : ]
64
+ mergedContext. merge ( context) { _, new in new }
65
+
66
+ do {
67
+ working. context = try JSON ( mergedContext)
68
+ } catch {
69
+ // If JSON creation fails, return original event
70
+ return event
71
+ }
72
+ return working
73
+ }
74
+ }
75
+
76
+ private func enrichments( with context: [ String : Any ] ? ) -> [ EnrichmentClosure ] {
77
+ var enrichments = [ originMarkerEnrichment]
78
+ if let context = context {
79
+ enrichments. append ( contextEnrichment ( with: context) )
80
+ }
81
+ return enrichments
82
+ }
83
+
54
84
internal func setupExports( ) {
55
85
exportProperty ( named: " traits " ) { [ weak self] in
56
- guard let self else { return nil }
57
- let traits : [ String : Any ] ? = analytics? . traits ( )
86
+ guard let self, let analytics = self . analytics else { return nil }
87
+ let traits : [ String : Any ] ? = analytics. traits ( )
58
88
return traits as? JSConvertible
59
89
}
60
90
61
91
exportProperty ( named: " userId " ) { [ weak self] in
62
- guard let self else { return nil }
63
- return analytics? . userId
92
+ return self ? . analytics? . userId
64
93
}
65
94
66
95
exportProperty ( named: " anonymousId " ) { [ weak self] in
67
- guard let self else { return nil }
68
- return analytics? . anonymousId
96
+ return self ? . analytics? . anonymousId
69
97
}
70
98
71
99
exportMethod ( named: " track " ) { [ weak self] in self ? . track ( args: $0) }
72
- exportMethod ( named: " identify " ) { [ weak self] in self ? . identify ( args: $0) }
100
+ exportMethod ( named: " identify " ) {
101
+ [ weak self] in self ? . identify ( args: $0)
102
+ }
73
103
exportMethod ( named: " screen " ) { [ weak self] in self ? . screen ( args: $0) }
74
104
exportMethod ( named: " group " ) { [ weak self] in self ? . group ( args: $0) }
75
- exportMethod ( named: " alias " ) { [ weak self] in self ? . alias ( args: $0) }
76
105
exportMethod ( named: " add " ) { [ weak self] in self ? . add ( args: $0) }
77
106
exportMethod ( named: " flush " ) { [ weak self] in self ? . flush ( args: $0) }
78
107
exportMethod ( named: " reset " ) { [ weak self] in self ? . reset ( args: $0) }
79
- exportMethod ( named: " removeLivePlugins " ) { [ weak self] in self ? . removeLivePlugins ( args: $0) }
80
108
}
81
109
82
110
public override func construct( args: [ JSConvertible ? ] ) {
83
111
if let writeKey = args. typed ( as: String . self, index: 0 ) {
84
- let existing = Self . existingInstances. first ( where: { $0. writeKey == writeKey } )
112
+ let existing = Self . existingInstances. first (
113
+ where: { $0. writeKey == writeKey
114
+ } )
85
115
if let existing {
86
116
self . analytics = existing
87
117
return
88
118
} else {
89
119
// we do some work on user-created instances to avoid multiple instances of the same write key
90
120
// by just attaching whatever existing instance that might exist with that write key.
91
- let createdAnalytics = Analytics ( configuration: Configuration ( writeKey: writeKey)
92
- . trackApplicationLifecycleEvents ( false )
121
+ let createdAnalytics = Analytics (
122
+ configuration: Configuration (
123
+ writeKey: writeKey
124
+ )
125
+ . setTrackedApplicationLifecycleEvents ( . none)
93
126
)
94
127
Self . existingInstances. append ( createdAnalytics)
95
128
self . analytics = createdAnalytics
@@ -99,113 +132,109 @@ public class AnalyticsJS: JSExport {
99
132
100
133
public func track( args: [ JSConvertible ? ] ) -> JSConvertible ? {
101
134
guard let analytics else { return nil }
102
- guard let name = args. typed ( as: String . self, index: 0 ) else { return nil }
103
- let properties = args. typed ( as: Dictionary . self, index: 1 )
104
-
105
- let addEventOrigin : EnrichmentClosure = { [ weak self] event in
106
- return Self . insertOrigin ( event: event, data: [
107
- " type " : " signals " ,
108
- " version " : self ? . currentLivePluginVersion ?? " "
109
- ] )
135
+ guard let name = args. typed ( as: String . self, index: 0 ) else {
136
+ return nil
110
137
}
138
+ let properties = args. typed ( as: Dictionary . self, index: 1 )
139
+ let context = args. typed ( as: Dictionary . self, index: 2 )
111
140
112
- analytics. track ( name: name, properties: properties, enrichments: [ addEventOrigin] )
141
+ analytics
142
+ . track (
143
+ name: name,
144
+ properties: properties,
145
+ enrichments: enrichments ( with: context)
146
+ )
113
147
return nil
114
148
}
115
149
116
150
public func identify( args: [ JSConvertible ? ] ) -> JSConvertible ? {
117
151
guard let analytics else { return nil }
118
- guard let userId = args. typed ( as: String . self, index: 0 ) else { return nil }
152
+ guard let userId = args. typed ( as: String . self, index: 0 ) else {
153
+ return nil
154
+ }
119
155
let traits = args. typed ( as: Dictionary . self, index: 1 )
120
- analytics. identify ( userId: userId, traits: traits, enrichments: [ originMarkerEnrichment] )
156
+ let context = args. typed ( as: Dictionary . self, index: 2 )
157
+ analytics
158
+ . identify (
159
+ userId: userId,
160
+ traits: traits,
161
+ enrichments: enrichments ( with: context)
162
+ )
121
163
return nil
122
164
}
123
165
124
166
public func screen( args: [ JSConvertible ? ] ) -> JSConvertible ? {
125
167
guard let analytics else { return nil }
126
- guard let title = args. typed ( as: String . self, index: 0 ) else { return nil }
168
+ guard let title = args. typed ( as: String . self, index: 0 ) else {
169
+ return nil
170
+ }
127
171
let category = args. typed ( as: String . self, index: 1 )
128
172
let properties = args. typed ( as: Dictionary . self, index: 2 )
129
- analytics. screen ( title: title, category: category, properties: properties, enrichments: [ originMarkerEnrichment] )
173
+ let context = args. typed ( as: Dictionary . self, index: 3 )
174
+ analytics
175
+ . screen (
176
+ title: title,
177
+ category: category,
178
+ properties: properties,
179
+ enrichments: enrichments ( with: context)
180
+ )
130
181
return nil
182
+
131
183
}
132
184
133
185
public func group( args: [ JSConvertible ? ] ) -> JSConvertible ? {
134
186
guard let analytics else { return nil }
135
- guard let groupId = args. typed ( as: String . self, index: 0 ) else { return nil }
187
+ guard let groupId = args. typed ( as: String . self, index: 0 ) else {
188
+ return nil
189
+ }
136
190
let traits = args. typed ( as: Dictionary . self, index: 1 )
137
- analytics. group ( groupId: groupId, traits: traits, enrichments: [ originMarkerEnrichment] )
138
- return nil
139
- }
140
-
141
- public func alias( args: [ JSConvertible ? ] ) -> JSConvertible ? {
142
- guard let analytics else { return nil }
143
- guard let newId = args. typed ( as: String . self, index: 0 ) else { return nil }
144
- analytics. alias ( newId: newId, enrichments: [ originMarkerEnrichment] )
191
+ let context = args. typed ( as: Dictionary . self, index: 2 )
192
+ analytics
193
+ . group (
194
+ groupId: groupId,
195
+ traits: traits,
196
+ enrichments: enrichments ( with: context)
197
+ )
145
198
return nil
199
+
146
200
}
147
201
148
202
public func flush( args: [ JSConvertible ? ] ) -> JSConvertible ? {
149
203
guard let analytics else { return nil }
150
204
analytics. flush ( )
151
205
return nil
206
+
152
207
}
153
208
154
209
public func reset( args: [ JSConvertible ? ] ) -> JSConvertible ? {
155
210
guard let analytics else { return nil }
156
211
analytics. reset ( )
157
212
return nil
213
+
158
214
}
159
215
160
216
public func add( args: [ JSConvertible ? ] ) -> JSConvertible ? {
161
- var result = false
162
-
163
- guard let analytics else { return result }
164
- guard let plugin = args . typed ( as : JSClass . self , index : 0 ) else { return result }
217
+ guard let analytics else { return nil }
218
+ guard let plugin = args . typed ( as : JSClass . self , index : 0 ) else {
219
+ return false
220
+ }
165
221
166
222
let type = plugin [ " type " ] ? . typed ( as: Int . self)
167
223
let destination = plugin [ " destination " ] ? . typed ( as: String . self)
168
224
169
- guard let type = type else { return result }
225
+ guard let type = type else { return false }
226
+ guard let pluginType = PluginType ( rawValue: type) else { return false }
170
227
171
- guard let pluginType = PluginType ( rawValue: type) else { return result }
172
228
let edgeFn = LivePlugin ( jsPlugin: plugin, type: pluginType)
173
229
174
230
if let dest = destination {
175
231
// we have a destination specified, so add it there
176
- if let d = analytics. find ( key: dest) {
177
- //DispatchQueue.main.async {
178
- _ = d. add ( plugin: edgeFn)
179
- //}
180
- result = true
181
- self . addedPlugins. append ( ( dest, edgeFn) )
182
- }
232
+ guard let d = analytics. find ( key: dest) else { return false }
233
+ _ = d. add ( plugin: edgeFn)
234
+ return true
183
235
} else {
184
- //DispatchQueue.main.async {
185
- _ = analytics. add ( plugin: edgeFn)
186
- //}
187
- result = true
188
- self . addedPlugins. append ( ( nil , edgeFn) )
236
+ _ = analytics. add ( plugin: edgeFn)
237
+ return true
189
238
}
190
- return result
191
- }
192
-
193
- public func removeLivePlugins( args: [ JSConvertible ? ] ) -> JSConvertible ? {
194
- guard let analytics else { return nil }
195
-
196
- for tuple in self . addedPlugins {
197
- let ( dest, p) = tuple
198
- if let dst = dest {
199
- // Remove from destination
200
- if let d = analytics. find ( key: dst) {
201
- d. remove ( plugin: p)
202
- }
203
- } else {
204
- // Remove from main timeline
205
- analytics. remove ( plugin: p)
206
- }
207
- }
208
- self . addedPlugins. removeAll ( )
209
- return nil
210
239
}
211
240
}
0 commit comments