Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
4 changes: 2 additions & 2 deletions analytics-kotlin-live/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ android {

dependencies {
// Segment
implementation 'com.segment.analytics.kotlin:substrata:1.1.0'
implementation 'com.segment.analytics.kotlin:android:1.20.0'
implementation 'com.segment.analytics.kotlin:substrata:1.1.1'
implementation 'com.segment.analytics.kotlin:android:1.21.0'

implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import com.segment.analytics.kotlin.core.Analytics
import com.segment.analytics.kotlin.core.BaseEvent
import com.segment.analytics.kotlin.core.platform.Plugin
import com.segment.analytics.kotlin.core.utilities.putInContext
import com.segment.analytics.kotlin.core.utilities.updateJsonObject
import com.segment.analytics.substrata.kotlin.JSObject
import com.segment.analytics.substrata.kotlin.JSScope
import com.segment.analytics.substrata.kotlin.JsonElementConverter
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import java.lang.ref.WeakReference
Expand Down Expand Up @@ -75,49 +78,77 @@ class JSAnalytics {

fun track(event: String, properties: JSObject) {
analytics.track(event, JsonElementConverter.read(properties)) {
it?.insertEventOrigin()
it?.insertContext()
}
}

fun track(event: String, properties: JSObject, enrichments: JSObject) {
val jsonElement = JsonElementConverter.read(enrichments)
analytics.track(event, JsonElementConverter.read(properties)) {
it?.insertContext(jsonElement)
}
}

fun identify(userId: String) {
analytics.identify(userId) {
it?.insertEventOrigin()
it?.insertContext()
}
}

fun identify(userId: String, traits: JSObject) {
analytics.identify(userId, JsonElementConverter.read(traits)) {
it?.insertEventOrigin()
it?.insertContext()
}
}

fun identify(userId: String, traits: JSObject, enrichments: JSObject) {
val jsonElement = JsonElementConverter.read(enrichments)
analytics.identify(userId, JsonElementConverter.read(traits)) {
it?.insertContext(jsonElement)
}
}

fun screen(title: String, category: String) {
analytics.screen(title, category) {
it?.insertEventOrigin()
it?.insertContext()
}
}

fun screen(title: String, category: String, properties: JSObject) {
analytics.screen(title, JsonElementConverter.read(properties), category) {
it?.insertEventOrigin()
it?.insertContext()
}
}

fun screen(title: String, category: String, properties: JSObject, enrichments: JSObject) {
val jsonElement = JsonElementConverter.read(enrichments)
analytics.screen(title, JsonElementConverter.read(properties), category) {
it?.insertContext(jsonElement)
}
}

fun group(groupId: String) {
analytics.group(groupId) {
it?.insertEventOrigin()
it?.insertContext()
}
}

fun group(groupId: String, traits: JSObject) {
analytics.group(groupId, JsonElementConverter.read(traits)) {
it?.insertEventOrigin()
it?.insertContext()
}
}

fun group(groupId: String, traits: JSObject, enrichments: JSObject) {
val jsonElement = JsonElementConverter.read(enrichments)
analytics.group(groupId, JsonElementConverter.read(traits)) {
it?.insertContext(jsonElement)
}
}

fun alias(newId: String) {
analytics.alias(newId) {
it?.insertEventOrigin()
it?.insertContext()
}
}

Expand Down Expand Up @@ -157,6 +188,17 @@ class JSAnalytics {
private fun BaseEvent.insertEventOrigin() : BaseEvent {
return putInContext("__eventOrigin", buildJsonObject {
put("type", "js")
put("version", "")
})
}

private fun BaseEvent.insertContext(enrichments: JsonElement? = null) : BaseEvent {
val modified = insertEventOrigin()
if (enrichments is JsonObject) {
modified.context = updateJsonObject(modified.context) {
it.putAll(enrichments)
}
}
return modified
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import android.content.SharedPreferences
import com.segment.analytics.kotlin.core.Analytics
import com.segment.analytics.kotlin.core.Settings
import com.segment.analytics.kotlin.core.WaitingPlugin
import com.segment.analytics.kotlin.core.emptyJsonObject
import com.segment.analytics.kotlin.core.platform.EventPlugin
import com.segment.analytics.kotlin.core.platform.Plugin
Expand All @@ -20,6 +21,9 @@ import java.io.InputStream
import java.lang.ref.WeakReference
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.coroutines.CoroutineContext
import androidx.core.content.edit
import com.segment.analytics.substrata.kotlin.JSExceptionHandler
import kotlinx.serialization.json.decodeFromJsonElement

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

class LivePlugins(
private val fallbackFile: InputStream? = null,
private val forceFallbackFile: Boolean = false
) : EventPlugin {
private val forceFallbackFile: Boolean = false,
exceptionHandler: JSExceptionHandler? = null,
private val localJS: List<InputStream> = listOf()
) : EventPlugin, WaitingPlugin {
override val type: Plugin.Type = Plugin.Type.Utility

companion object {
Expand All @@ -47,9 +53,7 @@ class LivePlugins(

private lateinit var sharedPreferences: SharedPreferences

val engine = JSScope {
it.printStackTrace()
}
val engine = JSScope(exceptionHandler = exceptionHandler)

private lateinit var livePluginFile: File

Expand All @@ -61,7 +65,8 @@ class LivePlugins(
}

override fun setup(analytics: Analytics) {
super.setup(analytics)
super<WaitingPlugin>.setup(analytics)

LivePluginsHolder.plugin = WeakReference(this)

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

loaded = true

if (settings.edgeFunction != emptyJsonObject) {
val livePluginsData = LenientJson.decodeFromJsonElement(
LivePluginsSettings.serializer(),
settings.edgeFunction
)
setLivePluginData(livePluginsData)
}
updateLivePlugin(settings)
loadLivePlugin(livePluginFile)
}

Expand Down Expand Up @@ -137,6 +136,10 @@ class LivePlugins(
d.prepare(engine)
}
engine.launch (global = true) {
for (js in localJS) {
loadBundle(js)
}

loadBundle(file.inputStream()) { error ->
if (error != null) {
analytics.log(error.message ?: "")
Expand All @@ -145,34 +148,43 @@ class LivePlugins(
d.readyToStart()
}
}

resume()
}
}
}

private fun setLivePluginData(data: LivePluginsSettings) {
currentData().let { currData ->
val newVersion = data.version
val currVersion = currData.version

if (newVersion > currVersion) {
updateLivePluginsConfig(data)
private fun updateLivePlugin(settings: Settings) {
if (settings.edgeFunction != emptyJsonObject) {
LenientJson.decodeFromJsonElement<LivePluginsSettings>(
settings.edgeFunction
).also {
if (shouldUpdateLivePlugin(it)) {
performLivePluginUpdate(it)
}
}
} ?: updateLivePluginsConfig(data)
}
}

private fun currentData(): LivePluginsSettings {
var currentData = LivePluginsSettings() // Default to an "empty" settings with version -1
val dataString = sharedPreferences.getString(SHARED_PREFS_KEY, null)
if (dataString != null) {
currentData = Json.decodeFromString<LivePluginsSettings>(dataString)
private fun shouldUpdateLivePlugin(livePluginSettings: LivePluginsSettings): Boolean {
val cache = sharedPreferences.getString(SHARED_PREFS_KEY, null)
if (cache != null) {
val cachedLivePluginSettings = Json.decodeFromString<LivePluginsSettings>(cache)
if (livePluginSettings.version > cachedLivePluginSettings.version) {
return true
}
else {
return false
}
}
return currentData

return true
}

private fun updateLivePluginsConfig(data: LivePluginsSettings) {
private fun performLivePluginUpdate(data: LivePluginsSettings) {
val urlString = data.downloadURL

sharedPreferences.edit().putString(SHARED_PREFS_KEY, Json.encodeToString(data)).apply()
sharedPreferences.edit { putString(SHARED_PREFS_KEY, Json.encodeToString(data)) }

with(analytics) {
analyticsScope.launch(fileIODispatcher as CoroutineContext) {
Expand Down