Skip to content

Commit 95b90f2

Browse files
authored
Refactor plugin interface and update apis (#19)
* disable destination based on settings * revert Main.kt * update README.md * remove `name` prop from plugin, change `name` to key in DestinationPlugin, refactor find/remove plugin apis * update webhook plugin and AmplitudeSession plugin * fix tests
1 parent 828d8aa commit 95b90f2

File tree

36 files changed

+159
-244
lines changed

36 files changed

+159
-244
lines changed

README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ JVM
105105
```kotlin
106106
Analytics("SEGMENT_API_KEY") {
107107
collectDeviceId = true
108-
recordScreenViews = true
109108
trackApplicationLifecycleEvents = true
110109
trackDeepLinks = true
111110
flushAt = 1
@@ -115,7 +114,6 @@ Analytics("SEGMENT_API_KEY") {
115114
Analytics(Configuration (
116115
writeKey = "123",
117116
collectDeviceId = true,
118-
recordScreenViews = true,
119117
trackApplicationLifecycleEvents = true,
120118
trackDeepLinks = true,
121119
flushAt = 1,
@@ -132,7 +130,6 @@ Analytics(Configuration (
132130
| ioDispatcher | `Dispatchers.IO` | Dispatcher running IO tasks |
133131
| storageProvider | `ConcreteStorageProvider` | Provider for storage class, generally do not want to modify |
134132
| collectDeviceId | `false` | automatically collect deviceId |
135-
| recordScreenViews | `false` | automatically trigger screen events on Activity Start |
136133
| trackApplicationLifecycleEvents | `false` | automatically track Lifecycle events |
137134
| trackDeepLinks | `false` | automatically track [Deep link](https://developer.android.com/training/app-links/deep-linking) opened based on intents |
138135
| useLifecycleObserver | `false` | enables the use of LifecycleObserver to track Application lifecycle events |
@@ -200,7 +197,7 @@ analytics.screen("ScreenName", buildJsonObject {
200197
put("productSlug", "example-product-123")
201198
});
202199
```
203-
You can enable automatic screen tracking using the Config option `autoRecordScreenViews = true`
200+
You can also opt-into auto screen tracking by adding this [plugin](https://github.com/segmentio/analytics-kotlin/blob/main/samples/kotlin-android-app/src/main/java/com/segment/analytics/next/plugins/AndroidRecordScreenPlugin.kt)
204201

205202
### group
206203
The group API call is how you associate an individual user with a group—be it a company, organization, account, project, team or whatever other crazy name you came up with for the same concept! This includes a unique group ID and any optional group traits you know about them like the company name industry, number of employees, etc. The traits option can include any information you might want to tie to the group, but when using any of the reserved group traits, you should make sure to only use them for their intended meaning.

android/src/main/java/com/segment/analytics/kotlin/android/AndroidAnalytics.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public fun Analytics(
6767
}
6868

6969
// Logger instance that uses the android `Log` class
70-
object AndroidLogger : Logger("AndroidLogger") {
70+
object AndroidLogger : Logger() {
7171
override fun log(type: LogType, message: String, event: BaseEvent?) {
7272
when (type) {
7373
LogType.ERROR -> {

android/src/main/java/com/segment/analytics/kotlin/android/plugins/AndroidContextPlugin.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import java.lang.System as JavaSystem
2929
// Plugin that applies context related changes. Auto-added to system on build
3030
class AndroidContextPlugin : Plugin {
3131
override val type: Plugin.Type = Plugin.Type.Before
32-
override val name: String = "AndroidContextCollector"
3332
override lateinit var analytics: Analytics
3433
private lateinit var context: Context
3534
private lateinit var storage: Storage

android/src/main/java/com/segment/analytics/kotlin/android/plugins/AndroidLifecyclePlugin.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class AndroidLifecyclePlugin() : Application.ActivityLifecycleCallbacks, Default
2828
Plugin {
2929

3030
override val type: Plugin.Type = Plugin.Type.Utility
31-
override val name: String = "AnalyticsActivityLifecycleCallbacks"
3231
override lateinit var analytics: Analytics
3332
private lateinit var packageInfo: PackageInfo
3433
private lateinit var application: Application

android/src/test/java/com/segment/analytics/kotlin/android/AndroidLifecyclePluginTests.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ class AndroidLifecyclePluginTests {
8383
var invokedSaveInstance = false
8484
val test = object : Plugin, AndroidLifecycle {
8585
override val type: Plugin.Type = Plugin.Type.Utility
86-
override val name: String = "TestPlugin"
8786
override lateinit var analytics: Analytics
8887

8988
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {

android/src/test/java/com/segment/analytics/kotlin/android/utils/Plugins.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.segment.analytics.kotlin.android.utils
33
import com.segment.analytics.kotlin.core.*
44
import com.segment.analytics.kotlin.core.platform.*
55

6-
class TestRunPlugin(override val name: String = "TestRunPlugin", var closure: (BaseEvent?) -> Unit): EventPlugin {
6+
class TestRunPlugin(var closure: (BaseEvent?) -> Unit): EventPlugin {
77
override val type: Plugin.Type = Plugin.Type.Before
88
override lateinit var analytics: Analytics
99
var ran = false
@@ -48,7 +48,7 @@ class TestRunPlugin(override val name: String = "TestRunPlugin", var closure: (B
4848
}
4949
}
5050

51-
class StubPlugin(override val name: String = "StubPlugin") : EventPlugin {
51+
class StubPlugin : EventPlugin {
5252
override val type: Plugin.Type = Plugin.Type.Before
5353
override lateinit var analytics: Analytics
5454
}

core/src/main/java/com/segment/analytics/kotlin/core/Analytics.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import kotlinx.serialization.json.jsonObject
1818
import kotlinx.serialization.serializer
1919
import sovran.kotlin.Store
2020
import sovran.kotlin.Subscriber
21+
import kotlin.reflect.KClass
2122

2223
class Analytics(val configuration: Configuration) : Subscriber {
2324

@@ -355,30 +356,29 @@ class Analytics(val configuration: Configuration) : Subscriber {
355356
*/
356357
fun add(plugin: Plugin): Analytics {
357358
this.timeline.add(plugin)
358-
if (plugin is DestinationPlugin && plugin.name != "Segment.io") {
359+
if (plugin is DestinationPlugin && plugin !is SegmentDestination) {
359360
analyticsScope.launch(ioDispatcher) {
360-
store.dispatch(System.AddIntegrationAction(plugin.name), System::class)
361+
store.dispatch(System.AddIntegrationAction(plugin.key), System::class)
361362
}
362363
}
363364
return this
364365
}
365366

366367
/**
367-
* Retrieve a registered plugin by name
368-
* @param pluginName [String]
368+
* Retrieve a registered plugin by reference
369+
* @param plugin [Plugin]
369370
*/
370-
fun find(pluginName: String): Plugin? = this.timeline.find(pluginName)
371+
fun <T: Plugin> find(plugin: KClass<T>): T? = this.timeline.find(plugin)
371372

372373
/**
373374
* Remove a plugin from the analytics timeline using its name
374375
* @param pluginName [Plugin] to be remove
375376
*/
376-
fun remove(pluginName: String): Analytics {
377-
val pluginToRemove = find(pluginName)
378-
this.timeline.remove(pluginName)
379-
if (pluginToRemove is DestinationPlugin && pluginToRemove.name != "Segment.io") {
377+
fun remove(plugin: Plugin): Analytics {
378+
this.timeline.remove(plugin)
379+
if (plugin is DestinationPlugin && plugin !is SegmentDestination) {
380380
analyticsScope.launch(ioDispatcher) {
381-
store.dispatch(System.RemoveIntegrationAction(pluginToRemove.name), System::class)
381+
store.dispatch(System.RemoveIntegrationAction(plugin.key), System::class)
382382
}
383383
}
384384
return this

core/src/main/java/com/segment/analytics/kotlin/core/SegmentDestination.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class SegmentDestination(
3030
private var apiHost: String = "api.segment.io/v1"
3131
) : DestinationPlugin() {
3232

33-
override val name: String = "Segment.io"
33+
override val key: String = "Segment.io"
3434
internal val httpClient: HTTPClient = HTTPClient()
3535
internal lateinit var storage: Storage
3636
lateinit var flushScheduler: ScheduledExecutorService
@@ -71,7 +71,7 @@ class SegmentDestination(
7171
}
7272

7373
val stringVal = Json.encodeToString(jsonVal)
74-
analytics.log("$name running $stringVal")
74+
analytics.log("$key running $stringVal")
7575
try {
7676
storage.write(Storage.Constants.Events, stringVal)
7777
if (eventCount.incrementAndGet() >= flushCount) {
@@ -108,7 +108,7 @@ class SegmentDestination(
108108
}
109109

110110
override fun update(settings: Settings) {
111-
settings.integrations[name]?.jsonObject?.let {
111+
settings.integrations[key]?.jsonObject?.let {
112112
apiKey = it["apiKey"]?.jsonPrimitive?.content ?: apiKey
113113
apiHost = it["apiHost"]?.jsonPrimitive?.content ?: apiHost
114114
}
@@ -126,7 +126,7 @@ class SegmentDestination(
126126
if (eventCount.get() < 1) {
127127
return
128128
}
129-
analytics.log("$name performing flush")
129+
analytics.log("$key performing flush")
130130
val fileUrls = parseFilePaths(storage.read(Storage.Constants.Events))
131131
if (fileUrls.isEmpty()) {
132132
analytics.log("No events to upload")
@@ -153,9 +153,9 @@ class SegmentDestination(
153153
}
154154
// Cleanup uploaded payloads
155155
storage.removeFile(fileUrl)
156-
analytics.log("$name uploaded $fileUrl")
156+
analytics.log("$key uploaded $fileUrl")
157157
} catch (e: HTTPException) {
158-
analytics.log("$name exception while uploading, ${e.message}")
158+
analytics.log("$key exception while uploading, ${e.message}")
159159
if (e.is4xx() && e.responseCode != 429) {
160160
// Simply log and proceed to remove the rejected payloads from the queue.
161161
analytics.log(

core/src/main/java/com/segment/analytics/kotlin/core/Settings.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.segment.analytics.kotlin.core
22

3+
import com.segment.analytics.kotlin.core.platform.DestinationPlugin
34
import com.segment.analytics.kotlin.core.platform.plugins.LogType
45
import com.segment.analytics.kotlin.core.platform.plugins.log
56
import kotlinx.coroutines.launch
@@ -34,6 +35,9 @@ data class Settings(
3435

3536
internal fun Analytics.update(settings: Settings) {
3637
timeline.applyClosure { plugin ->
38+
if (plugin is DestinationPlugin) {
39+
plugin.enabled = settings.isDestinationEnabled(plugin.key)
40+
}
3741
// tell all top level plugins to update.
3842
// For destination plugins they auto-handle propagation to sub-plugins
3943
plugin.update(settings)

core/src/main/java/com/segment/analytics/kotlin/core/platform/Mediator.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.segment.analytics.kotlin.core.GroupEvent
66
import com.segment.analytics.kotlin.core.IdentifyEvent
77
import com.segment.analytics.kotlin.core.ScreenEvent
88
import com.segment.analytics.kotlin.core.TrackEvent
9+
import kotlin.reflect.KClass
910

1011
// Platform abstraction for managing plugins' execution (of a specific type)
1112
// All operations are thread safe via the `synchronized` function
@@ -15,8 +16,8 @@ internal class Mediator(internal val plugins: MutableList<Plugin>) {
1516
plugins.add(plugin)
1617
}
1718

18-
fun remove(pluginName: String) = synchronized(plugins) {
19-
plugins.removeAll { it.name == pluginName }
19+
fun remove(plugin: Plugin) = synchronized(plugins) {
20+
plugins.removeAll { it === plugin } // remove only if reference is the same
2021
}
2122

2223
fun execute(event: BaseEvent): BaseEvent? = synchronized(plugins) {
@@ -62,10 +63,10 @@ internal class Mediator(internal val plugins: MutableList<Plugin>) {
6263
}
6364
}
6465

65-
fun find(pluginName: String): Plugin? = synchronized(plugins) {
66+
fun <T: Plugin> find(pluginClass: KClass<T>): T? = synchronized(plugins) {
6667
plugins.forEach {
67-
if (it.name == pluginName) {
68-
return it
68+
if (it::class == pluginClass) {
69+
return it as T
6970
}
7071
}
7172
return null

0 commit comments

Comments
 (0)