diff --git a/README.md b/README.md
index 9e99de6..e7def66 100644
--- a/README.md
+++ b/README.md
@@ -4,20 +4,9 @@ This package allows you to send signals to [TelemetryDeck](https://telemetrydeck
## Installation
-The TelemetryDeck is distributed using [jitpack](https://jitpack.io/), so you'll need to add the jitpack dependency to your `settings.gradle` file:
+### Dependencies
-```groovy
-dependencyResolutionManagement {
- repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
- repositories {
- google()
- mavenCentral()
- maven { url 'https://jitpack.io' } // <-- add this line
- }
-}
-```
-
-After that is done, add the following to your `build.gradle` file, under `dependencies`:
+The TelemetryDeck SDK for Kotlin is available from Maven Central and can be used as a dependency directly in `build.gradle` file:
```groovy
dependencies {
@@ -33,7 +22,7 @@ If needed, update your `gradle.settings` to reference Kotlin version compatible
id "org.jetbrains.kotlin.android" version "1.9.25" apply false
```
-## Permission for internet access
+### Permission for internet access
Sending signals requires access to the internet so the following permission should be added to the app's `AndroidManifest.xml`
@@ -41,6 +30,8 @@ Sending signals requires access to the internet so the following permission shou
```
+## Getting Started
+
### Using the application manifest
The TelemetryDeck can be initialized automatically by adding the application key to the `application` section of the app's `AndroidManifest.xml`:
@@ -92,6 +83,36 @@ To enqueue a signal to be sent by TelemetryDeck at a later time
TelemetryDeck.signal("appLaunchedRegularly")
```
+### Environment Parameters
+
+By default, TelemetryDeck will include the following environment parameters for each outgoing signal
+
+
+| Signal name | Provider |
+|------------------------------------------------|--------------------------------|
+| `TelemetryDeck.Session.started` | `SessionAppProvider` |
+| `TelemetryDeck.AppInfo.buildNumber` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.AppInfo.version` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.AppInfo.versionAndBuildNumber` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.Device.architecture` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.Device.modelName` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.Device.operatingSystem` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.Device.platform` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.Device.systemMajorMinorVersion` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.Device.systemMajorVersion` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.Device.systemVersion` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.Device.brand` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.AppInfo.buildNumber` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.AppInfo.version` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.AppInfo.versionAndBuildNumber` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.RunContext.locale` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.RunContext.targetEnvironment` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.SDK.name` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.SDK.version` | `EnvironmentParameterProvider` |
+| `TelemetryDeck.SDK.nameAndVersion` | `EnvironmentParameterProvider` |
+
+See [Custom Telemetry](#custom-telemetry) on how to implement your own parameter enrichment.
+
## Custom Telemetry
Another way to send signals is to register a custom `TelemetryDeckProvider`.
@@ -186,14 +207,22 @@ val builder = TelemetryDeck.Builder()
Please note that the logger implementation should be thread safe as it may be invoked in different queues and contexts.
-### Migrating providers to 3.0+
+
+
+## Requirements
+
+- Android API 21 or later
+- Kotlin 1.9.25 or later
+
+
+## Migrating providers to 3.0+
If you had TelemetryDeck SDK for Kotlin added to your app, you will notice that `TelemetryManager` and related classes have been deprecated.
You can read more about the motivation behind these changes [here](https://telemetrydeck.com/docs/articles/grand-rename/).
To upgrade, please perform the following changes depending on how you use TelemetryDeck SDK.
-#### Using the application manifest
+### If you're using the application manifest
* Adapt the manifest of your app and rename all keys from `com.telemetrydeck.sdk.*` to `com.telemetrydeck.*` for example:
@@ -211,7 +240,7 @@ After:
* If you were using `send()` to send signals, no further changes are needed!
* If you were using `queue()` to send signals, you will need to rename the method to `TelemetryDeck.signal()`.
-#### Programmatic Usage
+### Programmatic Usage
* In your app sourcecode, rename all uses of `TelemetryManager` to `TelemetryDeck`.
* If you were using `send()` to send signals, no further changes are needed!
@@ -225,7 +254,11 @@ After:
| `EnvironmentMetadataProvider` | `EnvironmentParameterProvider` |
-#### Custom Telemetry
+> [!TIP]
+> You can rename all deprecated classes in your project using the Code Cleanup function in IntelliJ/Android Studio.
+
+
+### Custom Telemetry
Your custom providers must replace `TelemetryProvider` with `TelemetryDeckProvider`.
@@ -240,8 +273,3 @@ You now have access to the entire `TelemetryDeckClient` interface:
* To access the signal cache, use `client.signalCache`
-
-## Requirements
-
-- Android API 21 or later
-- Kotlin 1.9.25 or later
diff --git a/lib/src/main/java/com/telemetrydeck/sdk/TelemetryDeck.kt b/lib/src/main/java/com/telemetrydeck/sdk/TelemetryDeck.kt
index ef0ef15..356d7ea 100644
--- a/lib/src/main/java/com/telemetrydeck/sdk/TelemetryDeck.kt
+++ b/lib/src/main/java/com/telemetrydeck/sdk/TelemetryDeck.kt
@@ -4,7 +4,6 @@ import android.app.Application
import android.content.Context
import android.content.pm.ApplicationInfo
import com.telemetrydeck.sdk.providers.EnvironmentParameterProvider
-import com.telemetrydeck.sdk.providers.SessionActivityProvider
import com.telemetrydeck.sdk.providers.SessionAppProvider
import java.lang.ref.WeakReference
import java.net.URL
diff --git a/lib/src/main/java/com/telemetrydeck/sdk/providers/EnvironmentParameterProvider.kt b/lib/src/main/java/com/telemetrydeck/sdk/providers/EnvironmentParameterProvider.kt
index 0699e53..f4f0542 100644
--- a/lib/src/main/java/com/telemetrydeck/sdk/providers/EnvironmentParameterProvider.kt
+++ b/lib/src/main/java/com/telemetrydeck/sdk/providers/EnvironmentParameterProvider.kt
@@ -6,6 +6,10 @@ import com.telemetrydeck.sdk.BuildConfig
import com.telemetrydeck.sdk.ManifestMetadataReader
import com.telemetrydeck.sdk.TelemetryDeckClient
import com.telemetrydeck.sdk.TelemetryDeckProvider
+import com.telemetrydeck.sdk.signals.AppInfo
+import com.telemetrydeck.sdk.signals.Device
+import com.telemetrydeck.sdk.signals.RunContext
+import com.telemetrydeck.sdk.signals.SDK
import java.lang.ref.WeakReference
import java.util.Locale
@@ -20,6 +24,12 @@ class EnvironmentParameterProvider : TelemetryDeckProvider {
private var enabled: Boolean = true
private var manager: WeakReference? = null
private var metadata = mutableMapOf()
+ // The approach from the SwiftSDK is not compatible here as we need to evaluate for platform capabilities
+ // In case of Kotlin Multiplatform, a per-platform value can be provided
+ // For now, we're defaulting to "Android"
+ private val platform: String = "Android"
+ private val os: String = "Android"
+ private val sdkName: String = "KotlinSDK"
override fun register(ctx: Application?, client: TelemetryDeckClient) {
this.manager = WeakReference(client)
@@ -27,48 +37,66 @@ class EnvironmentParameterProvider : TelemetryDeckProvider {
if (ctx != null) {
val appVersion = ManifestMetadataReader.getAppVersion(ctx)
if (!appVersion.isNullOrEmpty()) {
- metadata["appVersion"] = appVersion
+ metadata[AppInfo.Version.signalName] = appVersion
}
ManifestMetadataReader.getBuildNumber(ctx)?.let { buildNumber ->
- metadata["buildNumber"] = buildNumber.toString()
+ metadata[AppInfo.BuildNumber.signalName] = buildNumber.toString()
+ metadata[AppInfo.VersionAndBuildNumber.signalName] = "$appVersion (build $buildNumber)"
}
} else {
this.manager?.get()?.debugLogger?.error("EnvironmentParameterProvider requires a context but received null. Signals will contain incomplete metadata.")
}
+
+
if (android.os.Build.VERSION.RELEASE.isNullOrEmpty()) {
this.manager?.get()?.debugLogger?.error(
"EnvironmentMetadataProvider found no platform version information (android.os.Build.VERSION.RELEASE). Signal payloads will not be enriched."
)
} else {
+ // Device metadata
+ metadata[Device.Platform.signalName] = platform
val release = android.os.Build.VERSION.RELEASE
val sdkVersion = android.os.Build.VERSION.SDK_INT
- metadata["systemVersion"] = "Android SDK: $sdkVersion ($release)"
+ metadata[Device.SystemVersion.signalName] = "$platform $release (SDK: $sdkVersion)"
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
val versionInfo = VersionInfo.getInstance(release)
- metadata["majorSystemVersion"] = versionInfo.major.toString()
- metadata["majorMinorSystemVersion"] = "${versionInfo.major}.${versionInfo.minor}"
+ metadata[Device.SystemMajorVersion.signalName] = "${versionInfo.major}"
+ metadata[Device.SystemMajorMinorVersion.signalName] = "${versionInfo.major}.${versionInfo.minor}"
} else {
val versionInfo = release.split(".")
- metadata["majorSystemVersion"] = versionInfo.elementAtOrNull(0) ?: "0"
- metadata["majorMinorSystemVersion"] = "${versionInfo.elementAtOrNull(0) ?: "0"}.${versionInfo.elementAtOrNull(1) ?: "0"}"
+ val major = versionInfo.elementAtOrNull(0) ?: "0"
+ val minor = versionInfo.elementAtOrNull(1) ?: "0"
+ metadata[Device.SystemMajorVersion.signalName] = major
+ metadata[Device.SystemMajorMinorVersion.signalName] = "$major.$minor"
}
}
- metadata["locale"] = Locale.getDefault().displayName
if (android.os.Build.BRAND != null) {
- metadata["brand"] = android.os.Build.BRAND
+ metadata[Device.Brand.signalName] = android.os.Build.BRAND
}
if (android.os.Build.DEVICE != null) {
- metadata["targetEnvironment"] = android.os.Build.DEVICE
+ metadata[RunContext.TargetEnvironment.signalName] = android.os.Build.DEVICE
}
if (android.os.Build.MODEL != null && android.os.Build.PRODUCT != null) {
- metadata["modelName"] = "${android.os.Build.MODEL} (${android.os.Build.PRODUCT})"
+ metadata[Device.ModelName.signalName] = "${android.os.Build.MODEL} (${android.os.Build.PRODUCT})"
}
- metadata["architecture"] = System.getProperty("os.arch") ?: ""
- metadata["operatingSystem"] = "Android"
- metadata["telemetryClientVersion"] = BuildConfig.LIBRARY_PACKAGE_NAME
+ metadata[Device.Architecture.signalName] = System.getProperty("os.arch") ?: ""
+ metadata[Device.OperatingSystem.signalName] = os
+
+
+ // SDK Metadata
+ metadata[SDK.Name.signalName] = sdkName
+ // TODO: create a build property to pass the maven coordinates of the library
+ metadata[SDK.Version.signalName] = BuildConfig.LIBRARY_PACKAGE_NAME
+ metadata[SDK.NameAndVersion.signalName] = "$sdkName ${BuildConfig.LIBRARY_PACKAGE_NAME}"
+
+
+ // RunContext Metadata
+ metadata[RunContext.Locale.signalName] = Locale.getDefault().displayName
+
+
this.enabled = true
}
diff --git a/lib/src/main/java/com/telemetrydeck/sdk/providers/SessionAppProvider.kt b/lib/src/main/java/com/telemetrydeck/sdk/providers/SessionAppProvider.kt
index 97a1dc3..f34b216 100644
--- a/lib/src/main/java/com/telemetrydeck/sdk/providers/SessionAppProvider.kt
+++ b/lib/src/main/java/com/telemetrydeck/sdk/providers/SessionAppProvider.kt
@@ -5,9 +5,9 @@ import android.app.Application
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
-import com.telemetrydeck.sdk.SignalType
import com.telemetrydeck.sdk.TelemetryDeckClient
import com.telemetrydeck.sdk.TelemetryDeckProvider
+import com.telemetrydeck.sdk.signals.Session
import java.lang.ref.WeakReference
/**
@@ -28,7 +28,7 @@ class SessionAppProvider: TelemetryDeckProvider, DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
if (manager?.get()?.configuration?.sendNewSessionBeganSignal == true) {
manager?.get()?.signal(
- SignalType.NewSessionBegan
+ Session.Started.signalName
)
}
}
diff --git a/lib/src/main/java/com/telemetrydeck/sdk/signals/AppInfo.kt b/lib/src/main/java/com/telemetrydeck/sdk/signals/AppInfo.kt
new file mode 100644
index 0000000..392ace2
--- /dev/null
+++ b/lib/src/main/java/com/telemetrydeck/sdk/signals/AppInfo.kt
@@ -0,0 +1,8 @@
+package com.telemetrydeck.sdk.signals
+
+internal enum class AppInfo(val signalName: String) {
+ BuildNumber("TelemetryDeck.AppInfo.buildNumber"),
+ Version("TelemetryDeck.AppInfo.version"),
+ VersionAndBuildNumber("TelemetryDeck.AppInfo.versionAndBuildNumber"),
+}
+
diff --git a/lib/src/main/java/com/telemetrydeck/sdk/signals/Device.kt b/lib/src/main/java/com/telemetrydeck/sdk/signals/Device.kt
new file mode 100644
index 0000000..2dd873d
--- /dev/null
+++ b/lib/src/main/java/com/telemetrydeck/sdk/signals/Device.kt
@@ -0,0 +1,19 @@
+package com.telemetrydeck.sdk.signals
+
+
+// TODO: add more device parameters from the Swift SDK:
+//"TelemetryDeck.Device.orientation": Self.orientation,
+//"TelemetryDeck.Device.screenResolutionHeight": Self.screenResolutionHeight,
+//"TelemetryDeck.Device.screenResolutionWidth": Self.screenResolutionWidth,
+//"TelemetryDeck.Device.timeZone": Self.timeZone,
+
+internal enum class Device(val signalName: String) {
+ Architecture("TelemetryDeck.Device.architecture"),
+ ModelName("TelemetryDeck.Device.modelName"),
+ OperatingSystem("TelemetryDeck.Device.operatingSystem"),
+ Platform("TelemetryDeck.Device.platform"),
+ SystemMajorMinorVersion("TelemetryDeck.Device.systemMajorMinorVersion"),
+ SystemMajorVersion("TelemetryDeck.Device.systemMajorVersion"),
+ SystemVersion("TelemetryDeck.Device.systemVersion"),
+ Brand("TelemetryDeck.Device.brand"),
+}
\ No newline at end of file
diff --git a/lib/src/main/java/com/telemetrydeck/sdk/signals/RunContext.kt b/lib/src/main/java/com/telemetrydeck/sdk/signals/RunContext.kt
new file mode 100644
index 0000000..bd3b3e8
--- /dev/null
+++ b/lib/src/main/java/com/telemetrydeck/sdk/signals/RunContext.kt
@@ -0,0 +1,14 @@
+package com.telemetrydeck.sdk.signals
+
+
+//"TelemetryDeck.RunContext.isAppStore": "\(Self.isAppStore)",
+//"TelemetryDeck.RunContext.isDebug": "\(Self.isDebug)",
+//"TelemetryDeck.RunContext.isSimulator": "\(Self.isSimulator)",
+//"TelemetryDeck.RunContext.isTestFlight": "\(Self.isTestFlight)",
+//"TelemetryDeck.RunContext.language": Self.appLanguage,
+//"TelemetryDeck.RunContext.targetEnvironment": Self.targetEnvironment,
+
+internal enum class RunContext(val signalName: String) {
+ Locale("TelemetryDeck.RunContext.locale"),
+ TargetEnvironment("TelemetryDeck.RunContext.targetEnvironment"),
+}
\ No newline at end of file
diff --git a/lib/src/main/java/com/telemetrydeck/sdk/signals/SDK.kt b/lib/src/main/java/com/telemetrydeck/sdk/signals/SDK.kt
new file mode 100644
index 0000000..a0e50d0
--- /dev/null
+++ b/lib/src/main/java/com/telemetrydeck/sdk/signals/SDK.kt
@@ -0,0 +1,7 @@
+package com.telemetrydeck.sdk.signals
+
+internal enum class SDK(val signalName: String) {
+ Name("TelemetryDeck.SDK.name"),
+ Version("TelemetryDeck.SDK.version"),
+ NameAndVersion("TelemetryDeck.SDK.nameAndVersion"),
+}
\ No newline at end of file
diff --git a/lib/src/main/java/com/telemetrydeck/sdk/signals/Session.kt b/lib/src/main/java/com/telemetrydeck/sdk/signals/Session.kt
new file mode 100644
index 0000000..88cbec1
--- /dev/null
+++ b/lib/src/main/java/com/telemetrydeck/sdk/signals/Session.kt
@@ -0,0 +1,5 @@
+package com.telemetrydeck.sdk.signals
+
+internal enum class Session(val signalName: String) {
+ Started("TelemetryDeck.Session.started"),
+}
\ No newline at end of file
diff --git a/lib/src/test/java/com/telemetrydeck/sdk/TelemetryDeckTests.kt b/lib/src/test/java/com/telemetrydeck/sdk/TelemetryDeckTests.kt
index 8396609..60e3660 100644
--- a/lib/src/test/java/com/telemetrydeck/sdk/TelemetryDeckTests.kt
+++ b/lib/src/test/java/com/telemetrydeck/sdk/TelemetryDeckTests.kt
@@ -242,8 +242,8 @@ class TelemetryDeckTests {
.build(null)
sut.signal("type")
- Assert.assertEquals(4, sut.providers.count())
- Assert.assertTrue(sut.providers[3] is TestTelemetryDeckProvider)
+ Assert.assertEquals(3, sut.providers.count())
+ Assert.assertTrue(sut.providers.last() is TestTelemetryDeckProvider)
}
@Test
diff --git a/lib/src/test/java/com/telemetrydeck/sdk/providers/EnvironmentParameterProviderTest.kt b/lib/src/test/java/com/telemetrydeck/sdk/providers/EnvironmentParameterProviderTest.kt
index 37b167d..259bc67 100644
--- a/lib/src/test/java/com/telemetrydeck/sdk/providers/EnvironmentParameterProviderTest.kt
+++ b/lib/src/test/java/com/telemetrydeck/sdk/providers/EnvironmentParameterProviderTest.kt
@@ -22,7 +22,7 @@ class EnvironmentParameterProviderTest {
val queuedSignal = manager.cache?.empty()?.first()
Assert.assertNotNull(queuedSignal)
- Assert.assertEquals(queuedSignal?.payload?.contains("telemetryClientVersion:com.telemetrydeck.sdk"), true)
+ Assert.assertEquals(queuedSignal?.payload?.contains("TelemetryDeck.SDK.version:com.telemetrydeck.sdk"), true)
}
@Test
diff --git a/lib/src/test/java/com/telemetrydeck/sdk/providers/SessionAppProviderTest.kt b/lib/src/test/java/com/telemetrydeck/sdk/providers/SessionAppProviderTest.kt
index cb33700..999cb2d 100644
--- a/lib/src/test/java/com/telemetrydeck/sdk/providers/SessionAppProviderTest.kt
+++ b/lib/src/test/java/com/telemetrydeck/sdk/providers/SessionAppProviderTest.kt
@@ -3,8 +3,8 @@ package com.telemetrydeck.sdk.providers
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.LifecycleOwner
-import com.telemetrydeck.sdk.SignalType
import com.telemetrydeck.sdk.TelemetryDeck
+import com.telemetrydeck.sdk.signals.Session
import org.junit.Assert
import org.junit.Rule
import org.junit.Test
@@ -40,7 +40,7 @@ class SessionAppProviderTest {
sut.onStart(lifecycleOwner)
Assert.assertEquals(1, manager.cache?.count())
- Assert.assertEquals(SignalType.NewSessionBegan.type, manager.cache?.empty()?.get(0)?.type)
+ Assert.assertEquals(Session.Started.signalName, manager.cache?.empty()?.get(0)?.type)
}
@Test
@@ -53,7 +53,7 @@ class SessionAppProviderTest {
sut.onStart(lifecycleOwner)
Assert.assertEquals(1, manager.cache?.count())
- Assert.assertEquals(SignalType.NewSessionBegan.type, manager.cache?.empty()?.get(0)?.type)
+ Assert.assertEquals(Session.Started.signalName, manager.cache?.empty()?.get(0)?.type)
}
@Test