Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support init SDK with custom configuration #59

Merged
merged 5 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ let package = Package(
),
.testTarget(
name: "ClickstreamTests",
dependencies: ["Clickstream", .product(name: "Swifter", package: "swifter")]
dependencies: ["Clickstream", .product(name: "Swifter", package: "swifter")],
resources: [.process("amplifyconfiguration.json")]
)
]
)
62 changes: 45 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The Clickstream SDK supports iOS 13+.

Clickstream requires Xcode 13.4 or higher to build.

**1.Add Package**
### 1.Add Package

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

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

![](images/add_package_url.png)

**2.Parameter configuration**
### 2.Parameter configuration

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

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

**3.Initialize the SDK**
### 3.Initialize the SDK

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

#### 3.1 Initialize the SDK with default configuration
```swift
import Clickstream
...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
do {
try ClickstreamAnalytics.initSDK()
} catch {
Expand All @@ -80,6 +80,34 @@ func application(_ application: UIApplication, didFinishLaunchingWithOptions lau
}
```

#### 3.2 Initialize the SDK with global attributes and custom configuration

```swift
import Clickstream
...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
do {
let configuration = ClickstreamConfiguration()
.withAppId("your appId")
.withEndpoint("https://example.com/collect")
.withLogEvents(true)
.withInitialGlobalAttributes([
"_traffic_source_name": "Summer promotion",
"_traffic_source_medium": "Search engine"
])
try ClickstreamAnalytics.initSDK(configuration)
} catch {
assertionFailure("Fail to initialize ClickstreamAnalytics: \(error)")
}
return true
}
```

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.

You can also add all the configuration parameters you need in the `initSDK` method without using the `amplifyconfiguration.json` file.

#### 3.3 SwiftUI configuration
If your project is developed with SwiftUI, you need to create an application delegate and attach it to your `App` through `UIApplicationDelegateAdaptor`.

```swift
Expand All @@ -94,24 +122,24 @@ struct YourApp: App {
}
```

You also need to disable swzzling by setting `configuration.isTrackScreenViewEvents = false`, see the next configuration steps.
You also need to disable swzzling by setting `configuration.withTrackScreenViewEvents(false)`, see the next configuration steps.
zhu-xiaowei marked this conversation as resolved.
Show resolved Hide resolved

**4.Configure the SDK**
### 4. Update Configuration

```swift
import Clickstream

// config the sdk after initialize.
// configure the sdk after initialize.
do {
var configuration = try ClickstreamAnalytics.getClickstreamConfiguration()
configuration.appId = "appId"
configuration.endpoint = "https://example.com/collect"
configuration.authCookie = "your authentication cookie"
configuration.sessionTimeoutDuration = 1800000
configuration.isTrackScreenViewEvents = true
configuration.isTrackUserEngagementEvents = true
configuration.isLogEvents = true
configuration.isCompressEvents = true
let configuration = try ClickstreamAnalytics.getClickstreamConfiguration()
configuration.withAppId("your appId")
.withEndpoint("https://example.com/collect")
.withLogEvents(true)
.withCompressEvents(true)
.withSessionTimeoutDuration(1800000)
.withTrackAppExceptionEvents(true)
.withTrackScreenViewEvents(true)
.withTrackUserEngagementEvents(true)
} catch {
print("Failed to config ClickstreamAnalytics: \(error)")
}
Expand All @@ -136,7 +164,7 @@ let attributes: ClickstreamAttribute = [
]
ClickstreamAnalytics.recordEvent("testEvent", attributes)

// for record an event directly
// for record an event with event name
ClickstreamAnalytics.recordEvent("button_click")
```

Expand Down
87 changes: 79 additions & 8 deletions Sources/Clickstream/AWSClickstreamPlugin+Configure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,10 @@ extension AWSClickstreamPlugin {
}

/// Configure AWSClickstreamPlugin programatically using AWSClickstreamConfiguration
func configure(using configuration: AWSClickstreamConfiguration) throws {
let contextConfiguration = ClickstreamContextConfiguration(appId: configuration.appId,
endpoint: configuration.endpoint,
sendEventsInterval: configuration.sendEventsInterval,
isTrackAppExceptionEvents:
configuration.isTrackAppExceptionEvents,
isCompressEvents: configuration.isCompressEvents)
clickstream = try ClickstreamContext(with: contextConfiguration)
func configure(using amplifyConfigure: AWSClickstreamConfiguration) throws {
try mergeConfiguration(amplifyConfigure: amplifyConfigure)

clickstream = try ClickstreamContext(with: configuration)
let sessionClient = SessionClient(clickstream: clickstream)
clickstream.sessionClient = sessionClient
let eventRecorder = try EventRecorder(clickstream: clickstream)
Expand All @@ -61,6 +56,7 @@ extension AWSClickstreamPlugin {
autoFlushEventsTimer: autoFlushEventsTimer,
networkMonitor: networkMonitor
)
initGlobalAttributes()
log.debug("initialize Clickstream SDK successful")
sessionClient.handleAppStart()
}
Expand All @@ -82,4 +78,79 @@ extension AWSClickstreamPlugin {
)
)
}

/// Internal method to merge the configurations
func mergeConfiguration(amplifyConfigure: AWSClickstreamConfiguration) throws {
let defaultConfiguration = ClickstreamConfiguration.getDefaultConfiguration()
if (configuration.appId.isNilOrEmpty() && amplifyConfigure.appId.isEmpty) ||
(configuration.endpoint.isNilOrEmpty() && amplifyConfigure.endpoint.isEmpty)
{
throw ConfigurationError.unableToDecode(
"Configuration Error: `appId` and `endpoint` are required", """
Ensure they are correctly set in `amplifyconfiguration.json`\
or provided during SDK initialization with `initSDK()`
"""
)
}

if configuration.appId.isNilOrEmpty() {
defaultConfiguration.appId = amplifyConfigure.appId
} else {
defaultConfiguration.appId = configuration.appId
}
if configuration.endpoint.isNilOrEmpty() {
defaultConfiguration.endpoint = amplifyConfigure.endpoint
} else {
defaultConfiguration.endpoint = configuration.endpoint
}
if configuration.sendEventsInterval > 0 {
defaultConfiguration.sendEventsInterval = configuration.sendEventsInterval
} else if amplifyConfigure.sendEventsInterval > 0 {
defaultConfiguration.sendEventsInterval = amplifyConfigure.sendEventsInterval
}
if configuration.isTrackAppExceptionEvents != nil {
defaultConfiguration.isTrackAppExceptionEvents = configuration.isTrackAppExceptionEvents
} else if amplifyConfigure.isTrackAppExceptionEvents != nil {
defaultConfiguration.isTrackAppExceptionEvents = amplifyConfigure.isTrackAppExceptionEvents
}
if configuration.isCompressEvents != nil {
defaultConfiguration.isCompressEvents = configuration.isCompressEvents
} else if amplifyConfigure.isCompressEvents != nil {
defaultConfiguration.isCompressEvents = amplifyConfigure.isCompressEvents
}

mergeDefaultConfiguration(defaultConfiguration)
configuration = defaultConfiguration
}

/// Internal method to merge the default configurations
func mergeDefaultConfiguration(_ defaultConfiguration: ClickstreamConfiguration) {
if let isTrackScreenViewEvents = configuration.isTrackScreenViewEvents {
defaultConfiguration.isTrackScreenViewEvents = isTrackScreenViewEvents
}
if let isTrackUserEngagementEvents = configuration.isTrackUserEngagementEvents {
defaultConfiguration.isTrackUserEngagementEvents = isTrackUserEngagementEvents
}
if let isLogEvents = configuration.isLogEvents {
defaultConfiguration.isLogEvents = isLogEvents
}
if configuration.sessionTimeoutDuration > 0 {
defaultConfiguration.sessionTimeoutDuration = configuration.sessionTimeoutDuration
}
if configuration.authCookie != nil {
defaultConfiguration.authCookie = configuration.authCookie
}
if configuration.globalAttributes != nil {
defaultConfiguration.globalAttributes = configuration.globalAttributes
}
}

/// Internal method to add global attributes
func initGlobalAttributes() {
if let globalAttributes = configuration.globalAttributes {
for (key, value) in globalAttributes {
analyticsClient.addGlobalAttribute(value, forKey: key)
}
}
}
}
6 changes: 5 additions & 1 deletion Sources/Clickstream/AWSClickstreamPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ final class AWSClickstreamPlugin: AnalyticsCategoryPlugin {
"awsClickstreamPlugin"
}

var configuration: ClickstreamConfiguration

/// Instantiates an instance of the AWSClickstreamPlugin
init() {}
init(_ configuration: ClickstreamConfiguration? = nil) {
self.configuration = configuration ?? ClickstreamConfiguration()
}
}
35 changes: 31 additions & 4 deletions Sources/Clickstream/ClickstreamAnalytics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
//

import Amplify
import Foundation

/// ClickstreamAnalytics api for swift
public enum ClickstreamAnalytics {
/// Init ClickstreamAnalytics
public static func initSDK() throws {
try Amplify.add(plugin: AWSClickstreamPlugin())
try Amplify.configure()
public static func initSDK(_ configuration: ClickstreamConfiguration? = nil) throws {
try Amplify.add(plugin: AWSClickstreamPlugin(configuration))
try Amplify.configure(getAmplifyConfigurationSafely())
}

/// Use this method to record event
Expand Down Expand Up @@ -70,7 +71,7 @@ public enum ClickstreamAnalytics {

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

static func getAmplifyConfigurationSafely(_ bundle: Bundle = Bundle.main) -> AmplifyConfiguration {
var amplifyConfiguraion: AmplifyConfiguration!
do {
guard let path = bundle.path(forResource: "amplifyconfiguration", ofType: "json") else {
throw ConfigurationError.invalidAmplifyConfigurationFile(
"Could not load default `amplifyconfiguration.json` file",
"please check if you added the correct configuration file")
}
let url = URL(fileURLWithPath: path)
amplifyConfiguraion = try AmplifyConfiguration(configurationFile: url)
} catch {
log.debug("Could not load default `amplifyconfiguration.json` file")
zhu-xiaowei marked this conversation as resolved.
Show resolved Hide resolved
let plugins: [String: JSONValue] = [
"awsClickstreamPlugin": [
"appId": JSONValue.string(""),
"endpoint": JSONValue.string("")
]
]
let analyticsConfiguration = AnalyticsCategoryConfiguration(plugins: plugins)
amplifyConfiguraion = AmplifyConfiguration(analytics: analyticsConfiguration)
}
return amplifyConfiguraion
}

/// ClickstreamAnalytics preset events
public enum EventName {
public static let SCREEN_VIEW = "_screen_view"
Expand Down Expand Up @@ -133,3 +158,5 @@ public enum ClickstreamAnalytics {
public static let ITEM_CATEGORY5 = "item_category5"
}
}

extension ClickstreamAnalytics: ClickstreamLogger {}
7 changes: 6 additions & 1 deletion Sources/Clickstream/ClickstreamObjc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ import Foundation
try ClickstreamAnalytics.initSDK()
}

/// Init the Clickstream sdk
public static func initSDK(_ configuration: ClickstreamConfiguration) throws {
try ClickstreamAnalytics.initSDK(configuration)
}

/// Use this method to record event
/// - Parameter eventName: the event name
public static func recordEvent(_ eventName: String) {
Expand Down Expand Up @@ -76,7 +81,7 @@ import Foundation

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

Expand Down
Loading
Loading