Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
28 changes: 26 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.2'
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 All @@ -45,5 +45,29 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
task sourcesJar(type: Jar) {
archiveClassifier.set('sources')
from android.sourceSets.main.java.srcDirs
}

task javadoc(type: Javadoc) {
configurations.implementation.setCanBeResolved(true)

failOnError false
source = android.sourceSets.main.java.sourceFiles
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
classpath += configurations.implementation
}

// build a jar with javadoc
task javadocJar(type: Jar, dependsOn: javadoc) {
archiveClassifier.set('javadoc')
from javadoc.destinationDir
}

// Attach Javadocs and Sources jar
artifacts {
archives sourcesJar
archives javadocJar
}
apply from: rootProject.file('gradle/mvn-publish.gradle')
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
4 changes: 4 additions & 0 deletions gradle/mvn-publish.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ publishing {
version getVersionName()

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

// Self-explanatory metadata for the most part
pom {
Expand Down