Skip to content

Commit 70b00b9

Browse files
Enhancements to Segment Plugin for AppsFlyer SDK Integration (#21)
1 parent 4287a28 commit 70b00b9

File tree

1 file changed

+75
-33
lines changed

1 file changed

+75
-33
lines changed

Sources/SegmentAppsFlyer/AppsFlyerDestination.swift

Lines changed: 75 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ public class AppsFlyerDestination: UIResponder, DestinationPlugin {
5050
private weak var segDelegate: AppsFlyerLibDelegate?
5151
private weak var segDLDelegate: DeepLinkDelegate?
5252

53+
private var isFirstLaunch = true
54+
private var manualMode: Bool = false
55+
5356
// MARK: - Initialization
5457

5558
/// Creates and returns an AppsFlyer destination plugin for the Segment SDK
@@ -60,9 +63,11 @@ public class AppsFlyerDestination: UIResponder, DestinationPlugin {
6063
/// - segDelegate: When provided, this delegate will get called back for all AppsFlyerDelegate methods - ``onConversionDataSuccess(_:)``, ``onConversionDataFail(_:)``, ``onAppOpenAttribution(_:)``, ``onAppOpenAttributionFailure(_:)``
6164
/// - segDLDelegate: When provided, this delegate will get called back for all DeepLinkDelegate routines, or just ``didResolveDeeplink``
6265
public init(segDelegate: AppsFlyerLibDelegate? = nil,
63-
segDLDelegate: DeepLinkDelegate? = nil) {
66+
segDLDelegate: DeepLinkDelegate? = nil,
67+
manualMode: Bool = false) {
6468
self.segDelegate = segDelegate
6569
self.segDLDelegate = segDLDelegate
70+
self.manualMode = manualMode
6671
}
6772

6873
// MARK: - Plugin
@@ -75,15 +80,46 @@ public class AppsFlyerDestination: UIResponder, DestinationPlugin {
7580

7681
AppsFlyerLib.shared().appsFlyerDevKey = settings.appsFlyerDevKey
7782
AppsFlyerLib.shared().appleAppID = settings.appleAppID
83+
AppsFlyerLib.shared().setPluginInfo(plugin:Plugin.segment, version:"2.0.0", additionalParams:["Segment":"Analytics-Swift","Platform":"iOS"])
7884

79-
AppsFlyerLib.shared().waitForATTUserAuthorization(timeoutInterval: 60) //OPTIONAL
85+
// Commented this in order to let the developer set it as suits them.
86+
// It is available by the developer with AppsFlyerLib.shared() on their iOS native code.
87+
// AppsFlyerLib.shared().waitForATTUserAuthorization(timeoutInterval: 60) //OPTIONAL
8088
AppsFlyerLib.shared().deepLinkDelegate = self //OPTIONAL
89+
// AppsFlyerLib.shared().isDebug = true
8190

8291
let trackAttributionData = settings.trackAttributionData
8392

8493
if trackAttributionData ?? false {
8594
AppsFlyerLib.shared().delegate = self
8695
}
96+
97+
// Manual mode is a mode which let's the developer the abillity to start the SDK.
98+
// Once setting manualMode=true in the init, the develper should use startAppsflyerSDK method to start the SDK.
99+
// Once started the SDK it will be start automatically by the life cycle - didBecomeActiveNotification.
100+
if (!manualMode){
101+
startAFSDK()
102+
NotificationCenter.default.addObserver(self, selector: #selector(listenerStartSDK), name: UIApplication.didBecomeActiveNotification, object: nil)
103+
}
104+
}
105+
106+
// This is for the Manual Mode !
107+
// Once calling this function every didBecomeActive start will be called.
108+
public func startAppsflyerSDK(){
109+
startAFSDK()
110+
NotificationCenter.default.addObserver(self, selector: #selector(listenerStartSDK), name: UIApplication.didBecomeActiveNotification, object: nil)
111+
}
112+
113+
private func startAFSDK() {
114+
AppsFlyerLib.shared().start()
115+
}
116+
117+
@objc func listenerStartSDK() {
118+
if(isFirstLaunch){
119+
isFirstLaunch = false
120+
return
121+
}
122+
startAFSDK()
87123
}
88124

89125
public func identify(event: IdentifyEvent) -> IdentifyEvent? {
@@ -92,59 +128,62 @@ public class AppsFlyerDestination: UIResponder, DestinationPlugin {
92128
}
93129

94130
if let traits = event.traits?.dictionaryValue {
95-
var aFTraits: [AnyHashable: Any] = [:]
131+
var afTraits: [AnyHashable: Any] = [:]
96132

97133
if let email = traits["email"] as? String {
98-
aFTraits["email"] = email
134+
afTraits["email"] = email
99135
}
100136

101137
if let firstName = traits["firstName"] as? String {
102-
aFTraits["firstName"] = firstName
138+
afTraits["firstName"] = firstName
103139
}
104140

105141
if let lastName = traits["lastName"] as? String {
106-
aFTraits["lastName"] = lastName
142+
afTraits["lastName"] = lastName
143+
}
144+
145+
if let username = traits["username"] as? String {
146+
afTraits["username"] = username
107147
}
108148

109149
if traits["currencyCode"] != nil {
110150
AppsFlyerLib.shared().currencyCode = traits["currencyCode"] as? String
111151
}
112152

113-
AppsFlyerLib.shared().customData = aFTraits
153+
AppsFlyerLib.shared().customData = afTraits
114154
}
115155

116156
return event
117157
}
118158

119159
public func track(event: TrackEvent) -> TrackEvent? {
120-
160+
// Verify we are not looping an event.
161+
if(event.event == "Install Attributed" ||
162+
event.event == "Organic Install" ||
163+
event.event == "Deep Link Opened" ||
164+
event.event == "Direct Deep Link" ||
165+
event.event == "Deferred Deep Link"){
166+
return nil
167+
}
121168
var properties = event.properties?.dictionaryValue
122169

123170
let revenue: Double? = extractRevenue(key: "revenue", from: properties)
124-
let currency: String? = extractCurrency(key: "currency", from: properties, withDefault: "USD")
171+
let currency: String? = extractCurrency(key: "currency", from: properties)
125172

126173
if let afRevenue = revenue, let afCurrency = currency {
127174
properties?["af_revenue"] = afRevenue
128175
properties?["af_currency"] = afCurrency
129176

130177
properties?.removeValue(forKey: "revenue")
131-
properties?.removeValue(forKey: "currency")
132-
133-
AppsFlyerLib.shared().logEvent(event.event, withValues: properties)
134-
135-
} else {
136-
AppsFlyerLib.shared().logEvent(event.event, withValues: properties)
178+
properties?.removeValue(forKey: "currency")
137179
}
138-
180+
181+
AppsFlyerLib.shared().logEvent(event.event, withValues: properties)
139182
return event
140183
}
141184
}
142185

143186
extension AppsFlyerDestination: RemoteNotifications, iOSLifecycle {
144-
public func applicationDidBecomeActive(application: UIApplication?) {
145-
AppsFlyerLib.shared().start()
146-
}
147-
148187
public func openURL(_ url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) {
149188
AppsFlyerLib.shared().handleOpen(url, options: options)
150189
}
@@ -168,25 +207,30 @@ extension AppsFlyerDestination: UserActivities {
168207
// https://github.com/AppsFlyerSDK/segment-appsflyer-ios/blob/master/segment-appsflyer-ios/Classes/SEGAppsFlyerIntegration.m#L148
169208
extension AppsFlyerDestination {
170209
internal func extractRevenue(key: String, from properties: [String: Any]?) -> Double? {
210+
guard let value = properties?[key] else {
211+
return nil
212+
}
171213

172-
guard let revenueProperty = properties?[key] as? Double else {return nil}
173-
174-
if let revenue = properties?["revenue"] as? String {
175-
let revenueProperty = Double(revenue)
176-
return revenueProperty
177-
214+
if let doubleValue = value as? Double {
215+
return doubleValue
216+
} else if let stringValue = value as? String {
217+
return Double(stringValue)
178218
}
179-
return revenueProperty
219+
220+
return nil
180221
}
181222

182223

183-
internal func extractCurrency(key: String, from properties: [String: Any]?, withDefault value: String? = nil) -> String? {
224+
internal func extractCurrency(key: String, from properties: [String: Any]?) -> String? {
225+
guard let value = properties?[key] else {
226+
return nil
227+
}
184228

185-
if let currency = properties?[key] as? String {
186-
return currency
229+
if let stringValue = value as? String {
230+
return stringValue
187231
}
188232

189-
return "USD"
233+
return nil
190234
}
191235

192236
}
@@ -233,9 +277,7 @@ extension AppsFlyerDestination: AppsFlyerLibDelegate {
233277
} else {
234278
analytics?.track(name: "Organic Install")
235279
}
236-
} else {
237280
}
238-
239281
}
240282

241283
public func onConversionDataFail(_ error: Error) {

0 commit comments

Comments
 (0)