The hassle-free way to add Segment analytics to your kotlin app (Android/JVM).
NOTE: This project is currently in the Pilot phase and is covered by Segment's First Access & Beta Preview Terms. We encourage you
to try out this new library. Please provide feedback via Github issues/PRs, and feel free to submit pull requests. This library will eventually
supplant our analytics-android
library.
NOTE: This document serves as an explanation of usage of this analytics-kotlin
library for pure Java codebase. For the sample usages in Kotlin and more detailed architectural explanation, please refer to our main README.md doc.
For our pilot phase, we will be using jitpack to distribute the library
Android
In your app's build.gradle file add the following
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.segmentio.analytics-kotlin:android:+'
}
JVM
In your app's build.gradle file add the following
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.segmentio.analytics-kotlin:core:+'
}
Ensure that you add these permissions to your AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
Our library provides multiple initialisation techniques for the analytics client. The analytics client manages all your tracking events.
Android
Analytics analytics = AndroidAnalyticsKt.Analytics(BuildConfig.SEGMENT_WRITE_KEY, getApplicationContext(), configuration -> Unit.INSTANCE);
However, if you are in pure Java codebase, some of the functions in Analytics
is not compatible. We provide a wrapper class JavaAnalytics
to make all the functions available to Java.
JavaAnalytics analyticsCompat = new JavaAnalytics(analytics);
Generic
JavaAnalytics analytics = new JavaAnalytics(
new ConfigurationBuilder(BuildConfig.SEGMENT_WRITE_KEY).build()
);
Here, ConfigurationBuilder
implements a builder pattern to help instantiates a Configuration
object in Java, it can also be used in Android project.
When creating a new client, you can pass several options which can be found below.
Android
AndroidAnalyticsKt.Analytics(BuildConfig.SEGMENT_WRITE_KEY, getApplicationContext(), configuration -> {
configuration.setFlushAt(1);
configuration.setCollectDeviceId(true);
configuration.setTrackApplicationLifecycleEvents(true);
configuration.setTrackDeepLinks(true);
//...other config options
return Unit.INSTANCE;
});
JVM
JavaAnalytics analytics = new JavaAnalytics(
new ConfigurationBuilder(BuildConfig.SEGMENT_WRITE_KEY)
.setFlushAt(10)
.setCollectDeviceId(true)
.setTrackApplicationLifecycleEvents(true)
.setTrackDeepLinks(true) //...other config options
.build()
);
The track method is how you record any actions your users perform, along with any properties that describe the action.
Example usage:
analytics.track("View Product", Builders.buildJsonObject(o -> {
o.put("productId", 123)
.put("productName", "Striped trousers");
}));
Here Builders
is a utility class that has a series of convinent functions that helps build a Kotlin JsonObject.
You can also let your classes implement JsonSerializable
to avoid buiding up a JsonObject
every time.
class YourJsonSerializable implements JsonSerializable {
public JsonObject serialize() {
return Builders.buildJsonObject(o -> {
o.put("productId", 123)
.put("productName", "Striped trousers");
}));
}
}
analytics.track("View Product", new YourJsonSerializable());
For implementations supporting a minimum API version below 24, the buildJsonObjectFunc
function will need to be used.
analytics.track("View Product", Builders.buildJsonObjectFunc(o -> {
o.put("productId", 123)
.put("productName", "Striped trousers");
return Unit.INSTANCE;
}));
The identify call lets you tie a user to their actions and record traits about them. This includes a unique user ID and any optional traits you know about them like their email, name, etc. The traits option can include any information you might want to tie to the user, but when using any of the reserved user traits, you should make sure to only use them for their intended meaning.
Example Usage:
analytics.identify("user-123", Builders.buildJsonObject(o -> {
o.put("username", "MisterWhiskers")
.put("email", "[email protected]")
.put("plan", "premium");
}));
// or
analytics.identify("user-123", new YourJsonSerializable());
The screen call lets you record whenever a user sees a screen in your mobile app, along with any properties about the screen.
Example Usage:
analytics.screen("ScreenName", Builders.buildJsonObject(o -> {
o.put("productSlug", "example-product-123");
}));
// or
analytics.screen("ScreenName", new YourJsonSerializable());
You can also opt-into auto screen tracking by adding this plugin
The group API call is how you associate an individual user with a group—be it a company, organization, account, project, team or whatever other crazy name you came up with for the same concept! This includes a unique group ID and any optional group traits you know about them like the company name industry, number of employees, etc. The traits option can include any information you might want to tie to the group, but when using any of the reserved group traits, you should make sure to only use them for their intended meaning.
Example Usage:
analytics.group("user-123", Builders.buildJsonObject(o -> {
o.put("username", "MisterWhiskers")
.put("email", "[email protected]")
.put("plan", "premium");
}));
// or
analytics.group("user-123", new YourJsonSerializable());
The alias method is used to merge two user identities, effectively connecting two sets of user data as one. This is an advanced method, but it is required to manage user identities successfully in some of our integrations. Method signature:
fun alias(newId: String)
Example Usage:
analytics.alias("newId")
add API allows you to add a plugin to the analytics timeline
Example Usage:
analytics.add(new SomePlugin());
SomePlugin
is your customized Plugin
. See Plugin Architecture for details of plugin customization
find a registered plugin from the analytics timeline
Example Usage:
SomePlugin somePlugin = analytics.find(SomePlugin.class);
remove a registered plugin from the analytics timeline
Example Usage:
analytics.remove(somePlugin);
Our new plugin architecture enables you to modify/augment how the analytics client works completely. From modifying event payloads to changing analytics functionality, Plugins are the easiest way to get things done Plugins are run through a timeline, which executes plugins in order of insertion based on their types. We have the following [types]
Before
Executed before event processing beginsEnrichment
Executed as the first level of event processingDestination
Executed as events begin to pass off to destinationsAfter
Executed after all event processing is completed. This can be used to perform cleanup operations, etcUtility
Executed only when called manually, such as Logging
We have 3 types of basic plugins that you can use as a foundation for modifying functionality
Plugin
The most trivial plugin interface that will act on any event payload going through the timeline. For example if you wanted to add something to the context object of any event payload as an enrichment.
class SomePlugin implements Plugin {
private Analytics analytics;
@Override
public void update(@NonNull Settings settings, @NonNull UpdateType type) {
// stub method
}
@Nullable
@Override
public BaseEvent execute(@NonNull BaseEvent event) {
EventTransformer.putInContext(event, "foo", "bar");
return event;
}
@Override
public void setup(@NonNull Analytics analytics) {
this.analytics = analytics;
}
@NonNull
@Override
public Plugin.Type getType() {
return Plugin.Type.Enrichment;
}
@NonNull
@Override
public Analytics getAnalytics() {
return analytics;
}
@Override
public void setAnalytics(@NonNull Analytics analytics) {
setup(analytics);
}
}
EventPlugin
A plugin interface that will act only on specific event types.
static class SomePlugin implements EventPlugin {
//...Plugin methods
@Nullable
@Override
public BaseEvent track(@NonNull TrackEvent payload) {
// code to modify track event
return payload;
}
@Nullable
@Override
public BaseEvent identify(@NonNull IdentifyEvent payload) {
// code to modify identify event
return playload;
}
@Nullable
@Override
public BaseEvent screen(@NonNull ScreenEvent payload) {
// code to modify screen event
return payload;
}
@Nullable
@Override
public BaseEvent group(@NonNull GroupEvent payload) {
// code to modify group event
return payload;
}
@Nullable
@Override
public BaseEvent alias(@NonNull AliasEvent payload) {
// code to modify alias event
return payload;
}
}
DestinationPlugin
A plugin interface most commonly used for device-mode destinations. This plugin contains an internal timeline that follows the same process as the analytics timeline, allowing you to modify/augment how events reach the particular destination. For example if you wanted to implement a device-mode destination plugin for Amplitude
static class AmplitudePlugin extends DestinationPlugin {
private Amplitude amplitudeSDK;
public AmplitudePlugin() {
amplitudeSDK = Amplitude.getInstance();
amplitudeSDK.initialize(applicationContext, "API_KEY");
}
@Nullable
@Override
public BaseEvent track(@NonNull TrackEvent payload) {
// code to react to event with amplitudeSDK
return payload;
}
@Nullable
@Override
public BaseEvent identify(@NonNull IdentifyEvent payload) {
// code to react to event with amplitudeSDK
return payload;
}
@Nullable
@Override
public BaseEvent screen(@NonNull ScreenEvent payload) {
// code to react to event with amplitudeSDK
return payload;
}
@Nullable
@Override
public BaseEvent group(@NonNull GroupEvent payload) {
// code to react to event with amplitudeSDK
return payload;
}
@Nullable
@Override
public BaseEvent alias(@NonNull AliasEvent payload) {
// code to react to event with amplitudeSDK
return payload;
}
@NonNull
@Override
public String getKey() {
return "Amplitude";
}
}
setup(Analytics)
Use this function to setup your plugin. This will be implicitly called once the plugin is registeredupdate(Settings, UpdateType)
Use this function to react to any settings updates. This will be implicitly called when settings are updated. TheUpdateType
is used to indicate whether the settings change is for initialization or refreshment, and you can use it to decide whether to update your plugins accordingly. You can force a settings update by callinganalytics.checkSettings()
- AndroidLifecycle hooks
Plugins can also hook into
AndroidLifecycle
functions by implementing an interface. These functions will get called implicitly as the lifecycle events are processed. DestinationPlugin
timeline The destination plugin contains an internal timeline that follows the same process as the analytics timeline, allowing you to modify/augment how events reach the particular destination.
See the contributing guide to learn how to contribute to the repository and the development workflow.
Before contributing, please also see our code of conduct.
MIT License
Copyright (c) 2021 Segment
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.