Skip to content

Commit 8d75069

Browse files
authored
Implement waiting plugin (#23)
* update dependencies version * implement WaitingPlugin * add context as the last paramter * bug fix * add exception handler * add support to local js * add source and javadoc for maven local
1 parent 91e8bf7 commit 8d75069

File tree

4 files changed

+121
-39
lines changed

4 files changed

+121
-39
lines changed

analytics-kotlin-live/build.gradle

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ android {
3333

3434
dependencies {
3535
// Segment
36-
implementation 'com.segment.analytics.kotlin:substrata:1.1.0'
37-
implementation 'com.segment.analytics.kotlin:android:1.20.0'
36+
implementation 'com.segment.analytics.kotlin:substrata:1.1.2'
37+
implementation 'com.segment.analytics.kotlin:android:1.21.0'
3838

3939
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1'
4040
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1'
@@ -45,5 +45,29 @@ dependencies {
4545
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
4646
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
4747
}
48+
task sourcesJar(type: Jar) {
49+
archiveClassifier.set('sources')
50+
from android.sourceSets.main.java.srcDirs
51+
}
52+
53+
task javadoc(type: Javadoc) {
54+
configurations.implementation.setCanBeResolved(true)
55+
56+
failOnError false
57+
source = android.sourceSets.main.java.sourceFiles
58+
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
59+
classpath += configurations.implementation
60+
}
4861

62+
// build a jar with javadoc
63+
task javadocJar(type: Jar, dependsOn: javadoc) {
64+
archiveClassifier.set('javadoc')
65+
from javadoc.destinationDir
66+
}
67+
68+
// Attach Javadocs and Sources jar
69+
artifacts {
70+
archives sourcesJar
71+
archives javadocJar
72+
}
4973
apply from: rootProject.file('gradle/mvn-publish.gradle')

analytics-kotlin-live/src/main/java/com/segment/analytics/liveplugins/kotlin/JSAnalytics.kt

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ import com.segment.analytics.kotlin.core.Analytics
66
import com.segment.analytics.kotlin.core.BaseEvent
77
import com.segment.analytics.kotlin.core.platform.Plugin
88
import com.segment.analytics.kotlin.core.utilities.putInContext
9+
import com.segment.analytics.kotlin.core.utilities.updateJsonObject
910
import com.segment.analytics.substrata.kotlin.JSObject
1011
import com.segment.analytics.substrata.kotlin.JSScope
1112
import com.segment.analytics.substrata.kotlin.JsonElementConverter
13+
import kotlinx.serialization.json.JsonElement
14+
import kotlinx.serialization.json.JsonObject
1215
import kotlinx.serialization.json.buildJsonObject
1316
import kotlinx.serialization.json.put
1417
import java.lang.ref.WeakReference
@@ -75,49 +78,77 @@ class JSAnalytics {
7578

7679
fun track(event: String, properties: JSObject) {
7780
analytics.track(event, JsonElementConverter.read(properties)) {
78-
it?.insertEventOrigin()
81+
it?.insertContext()
82+
}
83+
}
84+
85+
fun track(event: String, properties: JSObject, enrichments: JSObject) {
86+
val jsonElement = JsonElementConverter.read(enrichments)
87+
analytics.track(event, JsonElementConverter.read(properties)) {
88+
it?.insertContext(jsonElement)
7989
}
8090
}
8191

8292
fun identify(userId: String) {
8393
analytics.identify(userId) {
84-
it?.insertEventOrigin()
94+
it?.insertContext()
8595
}
8696
}
8797

8898
fun identify(userId: String, traits: JSObject) {
8999
analytics.identify(userId, JsonElementConverter.read(traits)) {
90-
it?.insertEventOrigin()
100+
it?.insertContext()
101+
}
102+
}
103+
104+
fun identify(userId: String, traits: JSObject, enrichments: JSObject) {
105+
val jsonElement = JsonElementConverter.read(enrichments)
106+
analytics.identify(userId, JsonElementConverter.read(traits)) {
107+
it?.insertContext(jsonElement)
91108
}
92109
}
93110

94111
fun screen(title: String, category: String) {
95112
analytics.screen(title, category) {
96-
it?.insertEventOrigin()
113+
it?.insertContext()
97114
}
98115
}
99116

100117
fun screen(title: String, category: String, properties: JSObject) {
101118
analytics.screen(title, JsonElementConverter.read(properties), category) {
102-
it?.insertEventOrigin()
119+
it?.insertContext()
120+
}
121+
}
122+
123+
fun screen(title: String, category: String, properties: JSObject, enrichments: JSObject) {
124+
val jsonElement = JsonElementConverter.read(enrichments)
125+
analytics.screen(title, JsonElementConverter.read(properties), category) {
126+
it?.insertContext(jsonElement)
103127
}
104128
}
105129

106130
fun group(groupId: String) {
107131
analytics.group(groupId) {
108-
it?.insertEventOrigin()
132+
it?.insertContext()
109133
}
110134
}
111135

112136
fun group(groupId: String, traits: JSObject) {
113137
analytics.group(groupId, JsonElementConverter.read(traits)) {
114-
it?.insertEventOrigin()
138+
it?.insertContext()
139+
}
140+
}
141+
142+
fun group(groupId: String, traits: JSObject, enrichments: JSObject) {
143+
val jsonElement = JsonElementConverter.read(enrichments)
144+
analytics.group(groupId, JsonElementConverter.read(traits)) {
145+
it?.insertContext(jsonElement)
115146
}
116147
}
117148

118149
fun alias(newId: String) {
119150
analytics.alias(newId) {
120-
it?.insertEventOrigin()
151+
it?.insertContext()
121152
}
122153
}
123154

@@ -157,6 +188,17 @@ class JSAnalytics {
157188
private fun BaseEvent.insertEventOrigin() : BaseEvent {
158189
return putInContext("__eventOrigin", buildJsonObject {
159190
put("type", "js")
191+
put("version", "")
160192
})
161193
}
194+
195+
private fun BaseEvent.insertContext(enrichments: JsonElement? = null) : BaseEvent {
196+
val modified = insertEventOrigin()
197+
if (enrichments is JsonObject) {
198+
modified.context = updateJsonObject(modified.context) {
199+
it.putAll(enrichments)
200+
}
201+
}
202+
return modified
203+
}
162204
}

analytics-kotlin-live/src/main/java/com/segment/analytics/liveplugins/kotlin/LivePlugins.kt

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.Context
44
import android.content.SharedPreferences
55
import com.segment.analytics.kotlin.core.Analytics
66
import com.segment.analytics.kotlin.core.Settings
7+
import com.segment.analytics.kotlin.core.WaitingPlugin
78
import com.segment.analytics.kotlin.core.emptyJsonObject
89
import com.segment.analytics.kotlin.core.platform.EventPlugin
910
import com.segment.analytics.kotlin.core.platform.Plugin
@@ -20,6 +21,9 @@ import java.io.InputStream
2021
import java.lang.ref.WeakReference
2122
import java.util.concurrent.CopyOnWriteArrayList
2223
import kotlin.coroutines.CoroutineContext
24+
import androidx.core.content.edit
25+
import com.segment.analytics.substrata.kotlin.JSExceptionHandler
26+
import kotlinx.serialization.json.decodeFromJsonElement
2327

2428
interface LivePluginsDependent {
2529
fun prepare(engine: JSScope)
@@ -34,8 +38,10 @@ data class LivePluginsSettings(
3438

3539
class LivePlugins(
3640
private val fallbackFile: InputStream? = null,
37-
private val forceFallbackFile: Boolean = false
38-
) : EventPlugin {
41+
private val forceFallbackFile: Boolean = false,
42+
exceptionHandler: JSExceptionHandler? = null,
43+
private val localJS: List<InputStream> = listOf()
44+
) : EventPlugin, WaitingPlugin {
3945
override val type: Plugin.Type = Plugin.Type.Utility
4046

4147
companion object {
@@ -47,9 +53,7 @@ class LivePlugins(
4753

4854
private lateinit var sharedPreferences: SharedPreferences
4955

50-
val engine = JSScope {
51-
it.printStackTrace()
52-
}
56+
val engine = JSScope(exceptionHandler = exceptionHandler)
5357

5458
private lateinit var livePluginFile: File
5559

@@ -61,7 +65,8 @@ class LivePlugins(
6165
}
6266

6367
override fun setup(analytics: Analytics) {
64-
super.setup(analytics)
68+
super<WaitingPlugin>.setup(analytics)
69+
6570
LivePluginsHolder.plugin = WeakReference(this)
6671

6772
// if we've already got LivePlugins, we don't wanna do any setup
@@ -100,13 +105,7 @@ class LivePlugins(
100105

101106
loaded = true
102107

103-
if (settings.edgeFunction != emptyJsonObject) {
104-
val livePluginsData = LenientJson.decodeFromJsonElement(
105-
LivePluginsSettings.serializer(),
106-
settings.edgeFunction
107-
)
108-
setLivePluginData(livePluginsData)
109-
}
108+
updateLivePlugin(settings)
110109
loadLivePlugin(livePluginFile)
111110
}
112111

@@ -137,6 +136,10 @@ class LivePlugins(
137136
d.prepare(engine)
138137
}
139138
engine.launch (global = true) {
139+
for (js in localJS) {
140+
loadBundle(js)
141+
}
142+
140143
loadBundle(file.inputStream()) { error ->
141144
if (error != null) {
142145
analytics.log(error.message ?: "")
@@ -145,34 +148,43 @@ class LivePlugins(
145148
d.readyToStart()
146149
}
147150
}
151+
152+
resume()
148153
}
149154
}
150155
}
151156

152-
private fun setLivePluginData(data: LivePluginsSettings) {
153-
currentData().let { currData ->
154-
val newVersion = data.version
155-
val currVersion = currData.version
156-
157-
if (newVersion > currVersion) {
158-
updateLivePluginsConfig(data)
157+
private fun updateLivePlugin(settings: Settings) {
158+
if (settings.edgeFunction != emptyJsonObject) {
159+
LenientJson.decodeFromJsonElement<LivePluginsSettings>(
160+
settings.edgeFunction
161+
).also {
162+
if (shouldUpdateLivePlugin(it)) {
163+
performLivePluginUpdate(it)
164+
}
159165
}
160-
} ?: updateLivePluginsConfig(data)
166+
}
161167
}
162168

163-
private fun currentData(): LivePluginsSettings {
164-
var currentData = LivePluginsSettings() // Default to an "empty" settings with version -1
165-
val dataString = sharedPreferences.getString(SHARED_PREFS_KEY, null)
166-
if (dataString != null) {
167-
currentData = Json.decodeFromString<LivePluginsSettings>(dataString)
169+
private fun shouldUpdateLivePlugin(livePluginSettings: LivePluginsSettings): Boolean {
170+
val cache = sharedPreferences.getString(SHARED_PREFS_KEY, null)
171+
if (cache != null) {
172+
val cachedLivePluginSettings = Json.decodeFromString<LivePluginsSettings>(cache)
173+
if (livePluginSettings.version > cachedLivePluginSettings.version) {
174+
return true
175+
}
176+
else {
177+
return false
178+
}
168179
}
169-
return currentData
180+
181+
return true
170182
}
171183

172-
private fun updateLivePluginsConfig(data: LivePluginsSettings) {
184+
private fun performLivePluginUpdate(data: LivePluginsSettings) {
173185
val urlString = data.downloadURL
174186

175-
sharedPreferences.edit().putString(SHARED_PREFS_KEY, Json.encodeToString(data)).apply()
187+
sharedPreferences.edit { putString(SHARED_PREFS_KEY, Json.encodeToString(data)) }
176188

177189
with(analytics) {
178190
analyticsScope.launch(fileIODispatcher as CoroutineContext) {

gradle/mvn-publish.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ publishing {
1212
version getVersionName()
1313

1414
artifact("$projectDir/build/outputs/aar/${project.getName()}-release.aar")
15+
if (gradle.startParameter.taskNames.any { it.contains('publishToMavenLocal') }) {
16+
artifact sourcesJar
17+
artifact javadocJar
18+
}
1519

1620
// Self-explanatory metadata for the most part
1721
pom {

0 commit comments

Comments
 (0)