Skip to content

Commit df48ac9

Browse files
authored
feat: support init SDK with custom configuration (#59)
1 parent 32f44a8 commit df48ac9

20 files changed

+489
-155
lines changed

Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ let package = Package(
3030
),
3131
.testTarget(
3232
name: "ClickstreamTests",
33-
dependencies: ["Clickstream", .product(name: "Swifter", package: "swifter")]
33+
dependencies: ["Clickstream", .product(name: "Swifter", package: "swifter")],
34+
resources: [.process("amplifyconfiguration.json")]
3435
)
3536
]
3637
)

README.md

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The Clickstream SDK supports iOS 13+.
2020

2121
Clickstream requires Xcode 13.4 or higher to build.
2222

23-
**1.Add Package**
23+
### 1.Add Package
2424

2525
We use **Swift Package Manager** to distribute Clickstream Swift SDK, open your project in Xcode and select **File > Add Pckages**.
2626

@@ -30,7 +30,7 @@ Enter the Clickstream Library for Swift GitHub repo URL (`https://github.com/aws
3030

3131
![](images/add_package_url.png)
3232

33-
**2.Parameter configuration**
33+
### 2.Parameter configuration
3434

3535
Downlod your `amplifyconfiguration.json` file from your Clickstream solution control plane, and paste it to your project root folder:
3636

@@ -62,15 +62,15 @@ Your `appId` and `endpoint` are already set up in it, here's an explanation of e
6262
- **autoFlushEventsInterval**: event sending interval, the default is `10s`
6363
- **isTrackAppExceptionEvents**: whether auto track exception event in app, default is `false`
6464

65-
**3.Initialize the SDK**
65+
### 3.Initialize the SDK
6666

6767
Once you have configured the parameters, you need to initialize it in your app delegate's `application(_:didFinishLaunchingWithOptions:)` lifecycle method:
6868

69+
#### 3.1 Initialize the SDK with default configuration
6970
```swift
7071
import Clickstream
7172
...
7273
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
73-
// Override point for customization after application launch.
7474
do {
7575
try ClickstreamAnalytics.initSDK()
7676
} catch {
@@ -80,6 +80,34 @@ func application(_ application: UIApplication, didFinishLaunchingWithOptions lau
8080
}
8181
```
8282

83+
#### 3.2 Initialize the SDK with global attributes and custom configuration
84+
85+
```swift
86+
import Clickstream
87+
...
88+
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
89+
do {
90+
let configuration = ClickstreamConfiguration()
91+
.withAppId("your appId")
92+
.withEndpoint("https://example.com/collect")
93+
.withLogEvents(true)
94+
.withInitialGlobalAttributes([
95+
"_traffic_source_name": "Summer promotion",
96+
"_traffic_source_medium": "Search engine"
97+
])
98+
try ClickstreamAnalytics.initSDK(configuration)
99+
} catch {
100+
assertionFailure("Fail to initialize ClickstreamAnalytics: \(error)")
101+
}
102+
return true
103+
}
104+
```
105+
106+
By default, we will use the configurations in `amplifyconfiguration.json` file. If you add a custom configuration, the added configuration items will override the default values.
107+
108+
You can also add all the configuration parameters you need in the `initSDK` method without using the `amplifyconfiguration.json` file.
109+
110+
#### 3.3 SwiftUI configuration
83111
If your project is developed with SwiftUI, you need to create an application delegate and attach it to your `App` through `UIApplicationDelegateAdaptor`.
84112

85113
```swift
@@ -94,24 +122,24 @@ struct YourApp: App {
94122
}
95123
```
96124

97-
You also need to disable swzzling by setting `configuration.isTrackScreenViewEvents = false`, see the next configuration steps.
125+
Clickstream Swift SDK depends on method swizzling to automatically record screen views. SwiftUI apps must [record screen view events manually](#record-screen-view-events-manually), and disable automatic tracking of screen view events by setting `configuration.withTrackScreenViewEvents(false)` when the SDK is initialized.
98126

99-
**4.Configure the SDK**
127+
### 4. Update Configuration
100128

101129
```swift
102130
import Clickstream
103131

104-
// config the sdk after initialize.
132+
// configure the sdk after initialize.
105133
do {
106-
var configuration = try ClickstreamAnalytics.getClickstreamConfiguration()
107-
configuration.appId = "appId"
108-
configuration.endpoint = "https://example.com/collect"
109-
configuration.authCookie = "your authentication cookie"
110-
configuration.sessionTimeoutDuration = 1800000
111-
configuration.isTrackScreenViewEvents = true
112-
configuration.isTrackUserEngagementEvents = true
113-
configuration.isLogEvents = true
114-
configuration.isCompressEvents = true
134+
let configuration = try ClickstreamAnalytics.getClickstreamConfiguration()
135+
configuration.withAppId("your appId")
136+
.withEndpoint("https://example.com/collect")
137+
.withLogEvents(true)
138+
.withCompressEvents(true)
139+
.withSessionTimeoutDuration(1800000)
140+
.withTrackAppExceptionEvents(true)
141+
.withTrackScreenViewEvents(true)
142+
.withTrackUserEngagementEvents(true)
115143
} catch {
116144
print("Failed to config ClickstreamAnalytics: \(error)")
117145
}
@@ -136,7 +164,7 @@ let attributes: ClickstreamAttribute = [
136164
]
137165
ClickstreamAnalytics.recordEvent("testEvent", attributes)
138166

139-
// for record an event directly
167+
// for record an event with event name
140168
ClickstreamAnalytics.recordEvent("button_click")
141169
```
142170

Sources/Clickstream/AWSClickstreamPlugin+Configure.swift

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,10 @@ extension AWSClickstreamPlugin {
2626
}
2727

2828
/// Configure AWSClickstreamPlugin programatically using AWSClickstreamConfiguration
29-
func configure(using configuration: AWSClickstreamConfiguration) throws {
30-
let contextConfiguration = ClickstreamContextConfiguration(appId: configuration.appId,
31-
endpoint: configuration.endpoint,
32-
sendEventsInterval: configuration.sendEventsInterval,
33-
isTrackAppExceptionEvents:
34-
configuration.isTrackAppExceptionEvents,
35-
isCompressEvents: configuration.isCompressEvents)
36-
clickstream = try ClickstreamContext(with: contextConfiguration)
29+
func configure(using amplifyConfigure: AWSClickstreamConfiguration) throws {
30+
try mergeConfiguration(amplifyConfigure: amplifyConfigure)
3731

32+
clickstream = try ClickstreamContext(with: configuration)
3833
let sessionClient = SessionClient(clickstream: clickstream)
3934
clickstream.sessionClient = sessionClient
4035
let eventRecorder = try EventRecorder(clickstream: clickstream)
@@ -61,6 +56,7 @@ extension AWSClickstreamPlugin {
6156
autoFlushEventsTimer: autoFlushEventsTimer,
6257
networkMonitor: networkMonitor
6358
)
59+
initGlobalAttributes()
6460
log.debug("initialize Clickstream SDK successful")
6561
sessionClient.handleAppStart()
6662
}
@@ -82,4 +78,79 @@ extension AWSClickstreamPlugin {
8278
)
8379
)
8480
}
81+
82+
/// Internal method to merge the configurations
83+
func mergeConfiguration(amplifyConfigure: AWSClickstreamConfiguration) throws {
84+
let defaultConfiguration = ClickstreamConfiguration.getDefaultConfiguration()
85+
if (configuration.appId.isNilOrEmpty() && amplifyConfigure.appId.isEmpty) ||
86+
(configuration.endpoint.isNilOrEmpty() && amplifyConfigure.endpoint.isEmpty)
87+
{
88+
throw ConfigurationError.unableToDecode(
89+
"Configuration Error: `appId` and `endpoint` are required", """
90+
Ensure they are correctly set in `amplifyconfiguration.json`\
91+
or provided during SDK initialization with `initSDK()`
92+
"""
93+
)
94+
}
95+
96+
if configuration.appId.isNilOrEmpty() {
97+
defaultConfiguration.appId = amplifyConfigure.appId
98+
} else {
99+
defaultConfiguration.appId = configuration.appId
100+
}
101+
if configuration.endpoint.isNilOrEmpty() {
102+
defaultConfiguration.endpoint = amplifyConfigure.endpoint
103+
} else {
104+
defaultConfiguration.endpoint = configuration.endpoint
105+
}
106+
if configuration.sendEventsInterval > 0 {
107+
defaultConfiguration.sendEventsInterval = configuration.sendEventsInterval
108+
} else if amplifyConfigure.sendEventsInterval > 0 {
109+
defaultConfiguration.sendEventsInterval = amplifyConfigure.sendEventsInterval
110+
}
111+
if configuration.isTrackAppExceptionEvents != nil {
112+
defaultConfiguration.isTrackAppExceptionEvents = configuration.isTrackAppExceptionEvents
113+
} else if amplifyConfigure.isTrackAppExceptionEvents != nil {
114+
defaultConfiguration.isTrackAppExceptionEvents = amplifyConfigure.isTrackAppExceptionEvents
115+
}
116+
if configuration.isCompressEvents != nil {
117+
defaultConfiguration.isCompressEvents = configuration.isCompressEvents
118+
} else if amplifyConfigure.isCompressEvents != nil {
119+
defaultConfiguration.isCompressEvents = amplifyConfigure.isCompressEvents
120+
}
121+
122+
mergeDefaultConfiguration(defaultConfiguration)
123+
configuration = defaultConfiguration
124+
}
125+
126+
/// Internal method to merge the default configurations
127+
func mergeDefaultConfiguration(_ defaultConfiguration: ClickstreamConfiguration) {
128+
if let isTrackScreenViewEvents = configuration.isTrackScreenViewEvents {
129+
defaultConfiguration.isTrackScreenViewEvents = isTrackScreenViewEvents
130+
}
131+
if let isTrackUserEngagementEvents = configuration.isTrackUserEngagementEvents {
132+
defaultConfiguration.isTrackUserEngagementEvents = isTrackUserEngagementEvents
133+
}
134+
if let isLogEvents = configuration.isLogEvents {
135+
defaultConfiguration.isLogEvents = isLogEvents
136+
}
137+
if configuration.sessionTimeoutDuration > 0 {
138+
defaultConfiguration.sessionTimeoutDuration = configuration.sessionTimeoutDuration
139+
}
140+
if configuration.authCookie != nil {
141+
defaultConfiguration.authCookie = configuration.authCookie
142+
}
143+
if configuration.globalAttributes != nil {
144+
defaultConfiguration.globalAttributes = configuration.globalAttributes
145+
}
146+
}
147+
148+
/// Internal method to add global attributes
149+
func initGlobalAttributes() {
150+
if let globalAttributes = configuration.globalAttributes {
151+
for (key, value) in globalAttributes {
152+
analyticsClient.addGlobalAttribute(value, forKey: key)
153+
}
154+
}
155+
}
85156
}

Sources/Clickstream/AWSClickstreamPlugin.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ final class AWSClickstreamPlugin: AnalyticsCategoryPlugin {
2828
"awsClickstreamPlugin"
2929
}
3030

31+
var configuration: ClickstreamConfiguration
32+
3133
/// Instantiates an instance of the AWSClickstreamPlugin
32-
init() {}
34+
init(_ configuration: ClickstreamConfiguration? = nil) {
35+
self.configuration = configuration ?? ClickstreamConfiguration()
36+
}
3337
}

Sources/Clickstream/ClickstreamAnalytics.swift

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
//
77

88
import Amplify
9+
import Foundation
910

1011
/// ClickstreamAnalytics api for swift
1112
public enum ClickstreamAnalytics {
1213
/// Init ClickstreamAnalytics
13-
public static func initSDK() throws {
14-
try Amplify.add(plugin: AWSClickstreamPlugin())
15-
try Amplify.configure()
14+
public static func initSDK(_ configuration: ClickstreamConfiguration? = nil) throws {
15+
try Amplify.add(plugin: AWSClickstreamPlugin(configuration))
16+
try Amplify.configure(getAmplifyConfigurationSafely())
1617
}
1718

1819
/// Use this method to record event
@@ -70,7 +71,7 @@ public enum ClickstreamAnalytics {
7071

7172
/// Get Clickstream configuration, please config it after initialize sdk
7273
/// - Returns: ClickstreamContextConfiguration to modify the configuration of clickstream sdk
73-
public static func getClickstreamConfiguration() throws -> ClickstreamContextConfiguration {
74+
public static func getClickstreamConfiguration() throws -> ClickstreamConfiguration {
7475
let plugin = try Amplify.Analytics.getPlugin(for: "awsClickstreamPlugin")
7576
// swiftlint:disable force_cast
7677
return (plugin as! AWSClickstreamPlugin).getEscapeHatch().configuration
@@ -89,6 +90,22 @@ public enum ClickstreamAnalytics {
8990
Amplify.Analytics.enable()
9091
}
9192

93+
static func getAmplifyConfigurationSafely(_ bundle: Bundle = Bundle.main) throws -> AmplifyConfiguration {
94+
guard let path = bundle.path(forResource: "amplifyconfiguration", ofType: "json") else {
95+
log.debug("Could not load default `amplifyconfiguration.json` file")
96+
let plugins: [String: JSONValue] = [
97+
"awsClickstreamPlugin": [
98+
"appId": JSONValue.string(""),
99+
"endpoint": JSONValue.string("")
100+
]
101+
]
102+
let analyticsConfiguration = AnalyticsCategoryConfiguration(plugins: plugins)
103+
return AmplifyConfiguration(analytics: analyticsConfiguration)
104+
}
105+
let url = URL(fileURLWithPath: path)
106+
return try AmplifyConfiguration(configurationFile: url)
107+
}
108+
92109
/// ClickstreamAnalytics preset events
93110
public enum EventName {
94111
public static let SCREEN_VIEW = "_screen_view"
@@ -133,3 +150,5 @@ public enum ClickstreamAnalytics {
133150
public static let ITEM_CATEGORY5 = "item_category5"
134151
}
135152
}
153+
154+
extension ClickstreamAnalytics: ClickstreamLogger {}

Sources/Clickstream/ClickstreamObjc.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ import Foundation
2020
try ClickstreamAnalytics.initSDK()
2121
}
2222

23+
/// Init the Clickstream sdk
24+
public static func initSDK(_ configuration: ClickstreamConfiguration) throws {
25+
try ClickstreamAnalytics.initSDK(configuration)
26+
}
27+
2328
/// Use this method to record event
2429
/// - Parameter eventName: the event name
2530
public static func recordEvent(_ eventName: String) {
@@ -76,7 +81,7 @@ import Foundation
7681

7782
/// Get Clickstream configuration, please config it after initialize sdk
7883
/// - Returns: ClickstreamContextConfiguration to modify the configuration of clickstream sdk
79-
public static func getClickstreamConfiguration() throws -> ClickstreamContextConfiguration {
84+
public static func getClickstreamConfiguration() throws -> ClickstreamConfiguration {
8085
try ClickstreamAnalytics.getClickstreamConfiguration()
8186
}
8287

0 commit comments

Comments
 (0)