diff --git a/analytics-kotlin-live/build.gradle b/analytics-kotlin-live/build.gradle index 5f7931f..21f8c10 100644 --- a/analytics-kotlin-live/build.gradle +++ b/analytics-kotlin-live/build.gradle @@ -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' @@ -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') \ No newline at end of file diff --git a/analytics-kotlin-live/src/main/java/com/segment/analytics/liveplugins/kotlin/JSAnalytics.kt b/analytics-kotlin-live/src/main/java/com/segment/analytics/liveplugins/kotlin/JSAnalytics.kt index 8438513..49c0ba6 100644 --- a/analytics-kotlin-live/src/main/java/com/segment/analytics/liveplugins/kotlin/JSAnalytics.kt +++ b/analytics-kotlin-live/src/main/java/com/segment/analytics/liveplugins/kotlin/JSAnalytics.kt @@ -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 @@ -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() } } @@ -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 + } } \ No newline at end of file diff --git a/analytics-kotlin-live/src/main/java/com/segment/analytics/liveplugins/kotlin/LivePlugins.kt b/analytics-kotlin-live/src/main/java/com/segment/analytics/liveplugins/kotlin/LivePlugins.kt index 0375760..227f032 100644 --- a/analytics-kotlin-live/src/main/java/com/segment/analytics/liveplugins/kotlin/LivePlugins.kt +++ b/analytics-kotlin-live/src/main/java/com/segment/analytics/liveplugins/kotlin/LivePlugins.kt @@ -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 @@ -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) @@ -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 = listOf() +) : EventPlugin, WaitingPlugin { override val type: Plugin.Type = Plugin.Type.Utility companion object { @@ -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 @@ -61,7 +65,8 @@ class LivePlugins( } override fun setup(analytics: Analytics) { - super.setup(analytics) + super.setup(analytics) + LivePluginsHolder.plugin = WeakReference(this) // if we've already got LivePlugins, we don't wanna do any setup @@ -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) } @@ -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 ?: "") @@ -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( + 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(dataString) + private fun shouldUpdateLivePlugin(livePluginSettings: LivePluginsSettings): Boolean { + val cache = sharedPreferences.getString(SHARED_PREFS_KEY, null) + if (cache != null) { + val cachedLivePluginSettings = Json.decodeFromString(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) { diff --git a/gradle/mvn-publish.gradle b/gradle/mvn-publish.gradle index 83d4beb..6bb0b92 100644 --- a/gradle/mvn-publish.gradle +++ b/gradle/mvn-publish.gradle @@ -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 {