Analytics-Kotlin Migration Guide
Setting up an Analytics-Android Source
This guide assumes you already have an Analytics-Android Source in your Segment workspace. If you need to create a new one, refer to the source Overview.
If you're using a previous Segment mobile library such as Analytics-Android, follow these steps to migrate to the Analytics-Kotlin library. Analytics-Kotlin is designed to work with your Java codebase as well.
- Import Analytics-Kotlin.
- Upgrade your Destinations.
- Advanced: Upgrade your Middleware.
- Upgrade Notes.
In your top-level build.gradle:
1repositories {2mavenCentral()3}
In your app module's build.gradle:
1dependencies {2implementation 'com.segment.analytics.kotlin:android:<latest_version>'3}
You have now added Analytics-Kotlin to your project. You can remove the Analytics-Android SDK from your app.
1val analytics = Analytics("YOUR_WRITE_KEY", context) {2trackApplicationLifecycleEvents = true3}
You need to update the imports for Analytics-Kotlin.
Before example:
1import com.segment.analytics.Analytics;2import com.segment.analytics.Middleware;
After example:
1import com.segment.analytics.kotlin.core.Analytics;2import com.segment.analytics.kotlin.android.AndroidAnalyticsKt; // Only for calling from Android3import com.segment.analytics.kotlin.core.compat.JavaAnalytics; // Only for calling from Java4import com.segment.analytics.kotlin.core.platform.Plugin; // Replaces Middleware
Info
Analytics-Kotlin supports running multiple instances of the analytics object, so it does not assume a singleton. However, if you're migrating from Analytics-Android and all your track calls are routed to the Analytics.shared() singleton, you can these calls to your new Analytics-Kotlin object.
Add this extension to your code to ensure that tracking calls written for Analytics-Android work with Analytics-Kotlin.
12// Application's onCreate3...45sharedAnalytics = Analytics(...)...67fun Analytics.with {8// TODO: Finish this9return MyApplication.sharedAnalytics; // or whatever variable name you're using10}
If your app uses Segment to route data to Destinations via Segment-cloud (i.e. Cloud-mode destinations), you can skip this step. Analytics-Kotlin treats Device-mode Destinations as plugins, and simplifies the process in integrating them into your app. Analytics-Kotlin supports these Device-Mode Destinations with more to come.
implementation '<owner>:<project>:<version>'
Import the plugin:
import com.example.SomeDestinationPlugin
Add the pluging to the Analytics Instance:
analytics.add(new SomeDestinationPlugin());
Your events will now begin to flow to the added destination in Device-Mode.
Middlewares are a powerful mechanism that can augment events collected by the Analytics Android (Classic) SDK. A middleware is a simple function that is invoked by the Segment SDK and can be used to monitor, modify, augment or reject events. Analytics-Kotlin replaces the concept of middlewares with Enrichment Plugins to give you even more control over your event data. Refer to the Plugin Architecture Overview for more information.
Before example:
1builder2.useSourceMiddleware(new Middleware() {3@Override4public void intercept(Chain chain) {5// Get the payload.6BasePayload payload = chain.payload();78// Set the device year class on the context object.9int year = YearClass.get(getApplicationContext());10Map<String, Object> context = new LinkedHashMap<>(payload.context());11context.put("device_year_class", year);1213// Build our new payload.14BasePayload newPayload = payload.toBuilder()15.context(context)16.build();1718// Continue with the new payload.19chain.proceed(newPayload);20}21})
After example:
1analytics.add(new Plugin() {2private Analytics analytics;34@Override5public BaseEvent execute(@NonNull BaseEvent event) {6// Set the device year class on the context object.7int year = YearClass.get(getApplicationContext());8EventTransformer.putInContext(event, "device_year_class", year);9return event;10}1112@Override13public void setup(@NonNull Analytics analytics) {14setAnalytics(analytics);15}1617@NonNull18@Override19public Type getType() {20return Plugin.Type.Enrichment;21}2223@NonNull24@Override25public Analytics getAnalytics() {26return analytics;27}2829@Override30public void setAnalytics(@NonNull Analytics analytics) {31this.analytics = analytics;32}33});
If you don't need to transform all of your Segment calls, and only want to transform the calls going to specific, device-mode destinations, use Destination plugins.
Before example:
1builder2.useDestinationMiddleware("Segment.io", new Middleware() {3@Override4public void intercept(Chain chain) {5// Get the payload.6BasePayload payload = chain.payload();78// Set the device year class on the context object.9int year = YearClass.get(getApplicationContext());10Map<String, Object> context = new LinkedHashMap<>(payload.context());11context.put("device_year_class", year);1213// Build our new payload.14BasePayload newPayload = payload.toBuilder()15.context(context)16.build();1718// Continue with the new payload.19chain.proceed(newPayload);20}21})
After example:
1SegmentDestination segmentDestination = analytics.find(SegmentDestination.class);23segmentDestination.add(new Plugin() {4private Analytics analytics;56@Override7public BaseEvent execute(@NonNull BaseEvent event) {8// Set the device year class on the context object.9int year = YearClass.get(getApplicationContext());10EventTransformer.putInContext(event, "device_year_class", year);11return event;12}1314@Override15public void setup(@NonNull Analytics analytics) {16setAnalytics(analytics);17}1819@NonNull20@Override21public Type getType() {22return Plugin.Type.Enrichment;23}2425@NonNull26@Override27public Analytics getAnalytics() {28return analytics;29}3031@Override32public void setAnalytics(@NonNull Analytics analytics) {33this.analytics = analytics;34}35});
Call Identify as a one-off after migrating to Kotlin
To preserve the userId for users identified prior to your migration to Kotlin, you must make a one-off Identify call. This is due to a storage format change between the Analytics-Android and the Analytics-Kotlin libraries.
The following option was renamed in Analytics-Kotlin:
| Before | After |
|---|---|
| context | Name changed to application |
| defaultAPIHost | Name changed to apiHost |
| defaultProjectSettings | Name changed to defaultSettings |
| experimentalUseNewLifecycleMethods | Name changed to useLifecycleObserver |
The following option was added in Analytics-Kotlin:
| Added option | Details |
|---|---|
| autoAddSegmentDestination | The analytics client automatically adds the Segment Destination. Set this to false, if you want to customize the initialization of the Segment Destination, such as, add destination middleware). |
The following option was removed in Analytics-Kotlin:
| Removed option | Details |
|---|---|
| defaultOptions | Removed in favor of a plugin that adds the default data to the event payloads. Segment doesn't provide a plugin example since it's dependent on your needs. |
| recordScreenViews | Removed in favor of the AndroidRecordScreenPlugin that provides the same functionality. |
| trackAttributionData | This feature no longer exists. |
Properties have been replaced by JsonElement. Since Properties are essentially a Map<String, Object> we provide the ability to pass a map into our core tracking methods:
1Map<String, Object> map = new HashMap<>();2map.put("feature", "chat");3Map<String, Object> miniMap = new HashMap<>();4miniMap.put("colorChoice", "green");5map.put("prefs", miniMap);6analytics.track("UseFeature", map);;
Options are not supported and should be converted into plugins.
To prevent sending unwanted or unnecessary PII, traits collected in analytics.identify() events are no longer automatically attached to analytics.track() events. To achieve this, you can write a before plugin:
1import com.segment.analytics.kotlin.core.Analytics2import com.segment.analytics.kotlin.core.Plugin3import com.segment.analytics.kotlin.core.PluginType4import com.segment.analytics.kotlin.core.platform.Plugin5import com.segment.analytics.kotlin.core.events.RawEvent67class InjectTraits : Plugin {89override val type: PluginType = PluginType.Enrichment10var analytics: Analytics? = null1112override fun <T : RawEvent> execute(event: T?): T? {13if (event?.type == "identify") {14return event15}1617var workingEvent = event18val context = event?.context?.toMutableMap()1920if (context != null) {21context["traits"] = analytics?.traits()2223workingEvent?.context = context24}25return workingEvent26}27}
Once you're up and running, you can take advantage of Analytics-Kotlin's additional features, like Destination Filters, Functions, and Typewriter support.