Android SDK Quickstart

Using the Treasure Data Android and Android TV SDK, you can integrate Treasure Data services into standard Android apps and Android TV apps. It is an easy way to import the events on your Android and Android TV applications into Treasure Data.

Prerequisites and Requirements

  • Basic knowledge of Android development
  • Android Pie, or later. Auto tracking supports only Android devices that run on API 28 (Android 9.0) and higher
  • Basic knowledge of Treasure Data
  • Access to the Android SDK Releases
  • Ensure compliance with GDPR

Migration to version 1.0.0

Version 1.0.0 has major changes that are not backward compatible with previous versions. If you are upgrading from version 0.6.0 or earlier, your code will not run correctly without performing the following steps:

  • The API endpoint has changed to the Ingestion endpoint. The default value is [ https://us01.records.in.treasuredata.com ] .
  • The initializeApiEndpoint(String apiEndpoint) API is no longer available, please use initializeSharedInstance(Context context, String apiKey, String apiEndpoint) instead.
  • uuid is now a reserved column name. If you try to add a value to an event's uuid key, you won't see the column show up in the database.
  • Auto tracking of client id by adding td_ip field is no longer supported. Instead, use the new enableAutoTrackingIP and disableAutoTrackingIP APIs.

Installation

The following video demonstrates how to install Android SDK.

Install the Library

Add the Treasure Data library to your project. Examples for Gradle, Maven and using the Jar file are listed below.

GradleMavenJar File
Copy
Copied
// In build.gradle add the following
dependencies {
    implementation 'com.treasuredata:td-android-sdk:1.0.0'
}
Copy
Copied
// In pom.xml add the following
  <dependency>
    <groupId>com.treasuredata</groupId>
    <artifactId>td-android-sdk</artifactId>
    <version>1.0.0</version>
  </dependency>
Copy
Copied
1) Download latest td-android-sdk-x.x.x-shaded.jar package 
    from https://central.sonatype.com/search?q=g:com.treasuredata%20%20a:td-android-sdk&smo=true
2) Add .jar to YOUR_ANDROID_PROJECT/libs folder

This SDK has an example Android application project. The pom.xml would be a good reference.

Enable Required Android Permissions

If it’s not already present, add the INTERNET permission to your AndroidManifest.xml file. The following entry should appear between the <manifest> .. </manifest> tags.

Copy
Copied
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.treasuredata.android.demo"
  android:versionCode="1"
  android:versionName="1.0" >
  ...
 
  <!-- required permission -->
  <uses-permission android:name="android.permission.INTERNET"/>
</manifest>

Learn more from the Android Manifest example.

GDPR - Tracking of Personal Information

ATTENTION

You must review your data collection policy with your company's data privacy officer and legal counsel to determine what if any personal information you should collect. If you decide to enable tracking of individuals, we recommend that you also integrate a consent management system to track individual user opt-ins to tracking.

To comply with data privacy regulations in various domains, and specifically the EU's GDPR, the Treasure Data Android SDK does not collect certain event metadata that is personally identifiable. Specifically, the following information is not collected by default:

  • td_uuid - client's identifier, unique to this installation of this application on this device.

The td_uuid is needed if you want to track individual users and analyze their data within and across user sessions, associate the tracked behavior with a real-world individual, and more.

After you have obtained user consent, you can enable the collection of personal data. For example:

Copy
Copied
td.enableAutoAppendUniqId();

In testing, review the information you are collecting to ensure that you have the personal information you intended and nothing more.

Learn more about UUID for Android SDK.

Basic Use

Initialize the Library

For efficient API calls, we highly recommend initializing a TreasureData shared instance at the onCreate() method of your Application subclass.

Copy
Copied
public class ExampleApp extends Application {

  @Override
  public void onCreate() {

    // Initialize Treasure Data Android SDK
    TreasureData.initializeEncryptionKey("RANDOM_STRING_TO_ENCRYPT_DATA");
    TreasureData.disableLogging();
    TreasureData.initializeSharedInstance(this, "YOUR_WRITE_ONLY_API_KEY", "API_ENDPOINT");
    TreasureData.sharedInstance.setDefaultDatabase("your_application_name");
    TreasureData.sharedInstance.setDefaultTable("your_event_name");
    TreasureData.sharedInstance.enableAutoAppendUniqId();
    TreasureData.sharedInstance.enableAutoAppendModelInformation();
    TreasureData.sharedInstance.enableAutoAppendAppInformation();
    TreasureData.sharedInstance.enableAutoAppendLocaleInformation();
  }
}
Warning

Treasure Data strongly recommends that you use a write-only API key for ingest and import operations and whenever using Treasure Data SDKs

Click here to see how to get a write-only API Key.

  1. Login to the Treasure Data Console and go to the API Key page .
  2. If you dont already have a write-only API key, then create one. From the top right, select Actions > Create API Key .
  3. Name the new API Key.
  4. From the Type drop-down menu, select Write-only .
  5. Select Save .
  6. Copy your new Write-Only API Key and use it authenticate the APIs in your project.

Then, you can use a shared instance from anywhere with the TreasureData.sharedInstance() method.

Copy
Copied
public class ExampleActivity extends Activity {
 
  public void onDataLoadSomethingFinished(long elapsedTime) {
    Map<String, Object> event = new HashMap<String, Object>();
    event.put("data_type", "something");
    event.put("elapsed_time", elapsedTime);
    TreasureData.sharedInstance().addEvent("events", event);
  }
}

Add an Event to Local Buffer

To add an event to a local buffer, you can call addEvent or addEventWithCallback API.

SimpleWith callback
Copy
Copied
View v = findViewById(R.id.button);
 v.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
 
     final Map event = new HashMap<String, Object>();
     event.put("id", v.getId());
     event.put("left", v.getLeft());
     event.put("right", v.getRight());
     event.put("top", v.getTop());
     event.put("bottom", v.getBottom());

     td.addEvent("testdb", "demotbl", event);
  }
});
Copy
Copied
View v = findViewById(R.id.button);
 v.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
 
     final Map event = new HashMap<String, Object>();
     event.put("id", v.getId());
     event.put("left", v.getLeft());
     event.put("right", v.getRight());
     event.put("top", v.getTop());
     event.put("bottom", v.getBottom());
 
     td.addEventWithCallback("testdb", "demotbl", event, new TDCallback() {
       @Override
       public void onSuccess() {
         Log.i("ExampleApp", "success!");
       }
 
       @Override
       public void onError(String errorCode, Exception e) {
         Log.w("ExampleApp", "errorCode: " + errorCode + ", detail: " + e.toString());
       }
     });
  }
});

Specify the database and table to which you want to import the events. The total length of database and table must be shorter than 256 chars. Each table will cache no more than 10000 events.

On top of that, the length of key in event must not exceed 256 chars and the length of value in event must not exceed 10000 chars.

Upload Buffered Events

To upload events buffered events to Treasure Data, use the uploadEvents or uploadEventsWithCallback API.

Your application needs will determine when and how often to upload buffered events. We recommend the following:

  • When the current screen is closing or moving to the background
  • When closing the application
SimpleWith callback
Copy
Copied
findViewById(R.id.upload).setOnTouchListener(new OnTouchListener() {
   @Override
   public boolean onTouch(View view, MotionEvent motionEvent) {
 
     // You can call this API to upload buffered events whenever you want. 
     td.uploadEvents();
 
     return false;
  }
});
Copy
Copied
findViewById(R.id.upload).setOnTouchListener(new OnTouchListener() {
   @Override
   public boolean onTouch(View view, MotionEvent motionEvent) {
 
     // You can call this API to upload buffered events whenever you want.
     td.uploadEventsWithCallback(new TDCallback() {
       @Override
       public void onSuccess() {
         Log.i("ExampleApp", "success!");
       }
 
       @Override
       public void onError(String errorCode, Exception e) {
         Log.w("ExampleApp", "errorCode: " + errorCode + ", detail: " + e.toString());
       }
     });
 
     return false;
  }
});

It depends on the characteristic of your application when to upload and how often to upload buffered events. But we recommend the followings at least as good timings to upload.

When the current screen is closing or moving to background When closing the application The sent events is going to be buffered for a few minutes before they get imported into Treasure Data storage.

Advanced Use

Now that you have the basics down, here are a few advanced methods and practices you can use.

Retry Uploading and Deduplication

The SDK imports events in one style with the combination of these features:

  • This SDK keeps buffered events by adding unique keys and retries to upload them until confirming the events are uploaded and stored on the server-side (at least once)
  • The server side remembers the unique keys of all events within the past 1 hour by default and can prevent duplicate imports.

Deduplication is a best effort system that identifies a duplicate record if a record with the same identifier is seen in the same dataset, within the last hour at most or within the last 4096 records, whichever comes first.

Default Values

Set a default value if you want an event added to a table, a database, or any table or database to automatically set a value for a key. If you have multiple default values set to the same key, the newly added event will have the default value applied and override in the following order:

  1. Default value targeting all tables and databases is applied first.
  2. Default value targeting all tables in a database are applied.
  3. Default value targeting the table to which the event is added will then be applied.
  4. Default value targeting the table and database to which the event is added will then be applied.
  5. Finally, if the event has a value for the key, that value will override all default values.

Set a Default Value

Copy
Copied
TreasureData.sharedInstance().setDefaultValue(null, null, "key", "Value"); // Targeting all databases and tables
TreasureData.sharedInstance().setDefaultValue("database_name", null, "key", "Value"); // Targeting all tables of database "database_name"
TreasureData.sharedInstance().setDefaultValue(null, "table_name", "key", "Value"); // Targeting all tables with "table_name"
TreasureData.sharedInstance().setDefaultValue("database_name", "table_name", "key", "Value"); // Targeting table "table_name" of database "database_name"

Get the Default Value

Copy
Copied
String defaultValue = (String) TreasureData.sharedInstance().getDefaultValue("database_name", "table_name", "key"); // Get default value for key targeting database "database_name" and table "table_name"

Remove the Default Value

Copy
Copied
TreasureData.sharedInstance().removeDefaultValue("database_name", "table_name", "key"); // Only remove default value targeting database "database_name" and table "table_name"

Start and End Session

When you call the startSession method, the SDK generates a session ID that's kept until endSession is called. The session ID outputs as a column name "td_session_id". Also, startSession and endSession methods add an event that includes {"td_session_event":"start" or "end"} .

Copy
Copied
@Override
protected void onStart(Bundle savedInstanceState) {
                :
        TreasureData.sharedInstance().startSession("demotbl");
                :
}
 
@Override
protected void onStop() {
                :
        TreasureData.sharedInstance().endSession("demotbl");
        TreasureData.sharedInstance().uploadEvents();
        // Outputs =>>
        // [{"td_session_id":"cad88260-67b4-0242-1329-2650772a66b1",
        // "td_session_event":"start", "time":1418880000},
        //
        // {"td_session_id":"cad88260-67b4-0242-1329-2650772a66b1",
        // "td_session_event":"end", "time":1418880123}
        // ]
            :
}  

If you want to handle the following case, use a pair of class methods TreasureData.startSession and TreasureData.endSession for global session tracking:

  • The user opens the application and starts session tracking. For example, session#0 .
  • The user moves to the home screen and destroys the Activity
  • The user reopens the application and restarts session tracking within the default 10 seconds. But you want to deal with this new session as the same session as session#0 .
Copy
Copied
@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                :
        TreasureData.setSessionTimeoutMilli(30 * 1000); // Default is 10 seconds
}
 
@Override
protected void onStart() {
                :
TreasureData.startSession(this);
        :
}
 
@Override
protected void onStop() {
:
TreasureData.endSession(this);
TreasureData.sharedInstance().uploadEvents();
:
}

In this case, you can get the current session ID using TreasureData.getSessionId.

Copy
Copied
@Override
protected void onStart() {
                :
        TreasureData.startSession(this);
        Log.i(TAG, "onStart(): Session ID=" + TreasureData.getSessionId(this));
                :
}

Automatically Track App Lifecycle Events

App lifecycle event tracking is optional and not enabled by default. You can track app lifecycle events automatically using : enableAppLifecycleEvent().

App lifecycle events include Application Install, Application Open, Application Update. You can disable the individual core events as the following:

  • Disable Application Install: disableAppInstalledEvent()
  • Disable Application Open: disableAppOpenEvent()
  • Disable Application Update: disableAppUpdatedEvent()

Automatically Track In-App Purchase Events

In-app purchase event tracking is optional and not enabled by default. To track in-app purchase events automatically, add this code: TreasureData.enableInAppPurchaseEvent().

It outputs the following columns:

Column Name Description
td_android_event TD_ANDROID_IN_APP_PURCHASE
td_iap_product_id productId (Purchase)
td_iap_order_id orderId (Purchase)
td_iap_product_price price (SKU detail)
td_iap_quantity 1
td_iap_product_price_amount_micros price_amount_micros (SKU detail)
td_iap_product_currency price_currency_code (SKU detail)
td_iap_purchase_time purchaseTime (Purchase)
td_iap_purchase_token purchaseToken (Purchase)
td_iap_purchase_state purchaseState (Purchase)
td_iap_purchase_developer_payload developerPayload (Purchase)
td_iap_product_type type (SKU detail), inapp for one-time product and subs for subscription
td_iap_product_title title (SKU detail)
td_iap_product_description description (SKU detail)
td_iap_package_name packageName (Purchase)
td_iap_subs_auto_renewing autoRenewing (Purchase)
td_iap_subs_status Auto detection for subscription (New
td_iap_subs_period subscriptionPeriod (SKU detail for subscription)
td_iap_free_trial_period freeTrialPeriod (SKU detail for subscription)
td_iap_intro_price_period introductoryPricePeriod (SKU detail for subscription)
td_iap_intro_price_cycless introductoryPriceCycles (SKU detail for subscription)
td_iap_intro_price_amount_micros introductoryPriceAmountMicro (SKU detail for subscription)

This SDK can track in-app purchase events for Android applications using both Google Play Billing Library and In-app Billing with AIDL. You must add the following ProGuard rule to keep AIDL classes using by the SDK to your project if your application is developed using In-app Billing with AIDL api.

Copy
Copied
-keep class com.android.vending.billing.** { *; }

Opt Out

Depending on the countries where you sell your app (e.g. the EU), you may need to offer the ability for users to opt-out of tracking data inside your app.

  • To turn off auto-tracking application lifecycle events (when application lifecycle event tracking is enabled) : disableAppLifecycleEvent() .
  • To turn off auto-tracking in-app purchase events(when in-app purchase event is enabled) : disableInAppPurchaseEvent() .
  • To turn off custom events (the events you are tracking by addEvent , addEventWithCallback ) : disableCustomEvent . To turn on it again : enableCustomEvent .

You can query the state of tracking events by using: isAppLifecycleEventEnabled(), isInAppPurchaseEventEnabled(), and isCustomEventEnabled(). The states have effects across device reboots, app updates, so you can simply call this once during your application.

Error Codes

When using functions with callbacks, like addEventWithCallback or uploadEventWithCallback it is possible to get a call back TDCallback.onError method with errorCode argument. This argument is useful to know the cause type of error. There are the following error codes.

Error code Description
init_error The initialization failed.
invalid_param The parameter passed to the API was invalid.
invalid_event The event was invalid.
data_conversion Failed to convert the data to and from JSON.
storage_error Failed to read/write data in the storage.
network_error Failed to communicate with the server due to a network problem.
server_response The server returned an error response.

Additional Configuration

Endpoint

The API endpoint (default: [ https://us01.records.in.treasuredata.com ] ) can be changed. For example:

Copy
Copied
td = new TreasureData(this, "your_api_key", "https://specifying-another-endpoint.com");

Encryption Key

If you've set an encryption key via TreasureData.initializeEncryptionKey, the SDK saves the event data as encrypted when called TreasureData#addEvent or TreasureData.addEventWithCallback.

Copy
Copied
    TreasureData.initializeEncryptionKey("hello world");
        :
    td.addEventWithCallback(...)

Default Database

Copy
Copied
  TreasureData.sharedInstance().setDefaultDatabase("default_db");
    :
  TreasureData.sharedInstance().addEvent("demotbl",);

Adding Local Timestamp to Each Event Record Automatically

This option is enabled by default. A local timestamp will be added to the event's time key automatically. If you disableAutoAppendLocalTimestamp without adding time key to the event yourself, the server will add a server side timestamp to time column. You can also auto track local time with a custom column. If so, the time column will have server side timestamp.

Copy
Copied
    // Use local time as `time` column
    TreasureData.sharedInstance().enableAutoAppendLocalTimestamp();

    // Add local time as a customized column name
    TreasureData.sharedInstance().enableAutoAppendLocalTimestamp("custom_time");

    // Disable auto append local time
    TreasureData.sharedInstance().disableAutoAppendLocalTimestamp();

Adding UUID of the Device To Each Event Automatically

UUID of the device will be added to each event automatically if you call TreasureData#enableAutoAppendUniqId(). This value won't change until the application is uninstalled.

Copy
Copied
  td.enableAutoAppendUniqId();
    :
  td.addEvent(...);

It outputs the value as a column name td_uuid.

You can reset the UUID and send forget_device_uuid event with an old UUID using TreasureData#resetUniqId().

Adding a UUID to Each Event Record Automatically

UUID will be added to each event record automatically if you call enableAutoAppendRecordUUID. Each event will have a different UUID.

Copy
Copied
  td.enableAutoAppendRecordUUID();
  // If you want to customize the column name, pass it to the API
  // td.enableAutoAppendRecordUUID("my_record_uuid");
    :
  td.addEvent(...);

It outputs the value as a column name record_uuid by default.

Adding Advertising ID to Each Event Record Automatically

An advertising ID will be added to each event record automatically if you call enableAutoAppendAdvertisingIdentifier. You must install Google Play Service Ads (Gradle com.google.android.gms:play-services-ads) as a dependency for this feature to work. User's must also not turn on Limit Ad Tracking feature in their device, otherwise, Treasure Data will not be able to attach Advertising IDs to the record. Due to the asynchronous nature of getting an Advertising ID, after the enableAutoAppendAdvertisingIdentifier method is called, it may take some time for the Advertising ID to be available. However, Treasure Data does cache the Advertising ID in order to add it to the next event without having to wait for the fetch Advertising ID task to complete.

Copy
Copied
td.enableAutoAppendAdvertisingIdentifier();
// If you want to customize the column name, pass it to the API
// td.enableAutoAppendAdvertisingIdentifier("my_advertising_id_column");
:
td.addEvent(...);

It outputs the value as a column name td_maid by default.

Adding Device Model Information to Each Event Automatically

Device model information will be added to each event automatically if you call TreasureData#enableAutoAppendModelInformation.

Copy
Copied
  td.enableAutoAppendModelInformation();
    :
  td.addEvent(...);

It outputs the following column names and values:

  • td_board : android.os.Build#BOARD
  • td_brand : android.os.Build#BRAND
  • td_device : android.os.Build#DEVICE
  • td_display : android.os.Build#DISPLAY
  • td_model : android.os.Build#MODEL
  • td_os_ver : android.os.Build.VERSION#SDK_INT
  • td_os_type : "Android"

Adding Application Package Version Information to Each Event Automatically

Application package version information will be added to each event automatically if you call TreasureData#enableAutoAppendAppInformation.

Copy
Copied
  td.enableAutoAppendAppInformation();
    :
  td.addEvent(...);

It outputs the following column names and values:

  • td_app_ver : android.content.pm.PackageInfo.versionName (from Context.getPackageManager().getPackageInfo())
  • td_app_ver_num : android.content.pm.PackageInfo.versionCode (from Context.getPackageManager().getPackageInfo())

Adding Locale Configuration Information to Each Event Automatically

Locale configuration information will be added to each event automatically if you call TreasureData#enableAutoAppendLocaleInformation.

Copy
Copied
  td.enableAutoAppendLocaleInformation();
    :
  td.addEvent(...);

It outputs the following column names and values:

  • td_locale_country : java.util.Locale.getCountry() (from Context.getResources().getConfiguration().locale)
  • td_locale_lang : java.util.Locale.getLanguage() (from Context.getResources().getConfiguration().locale)

Auto tracking device IP

Device IP will be added to each event automatically in td_ip column if you call enableAutoTrackingIP. Note that the tracked IP address is the one when you upload the events to Treasure Data, not the one when you add the event.

Copy
Copied
TreasureData.sharedInstance().enableAutoTrackingIP();

To disable auto tracking IP:

Copy
Copied
TreasureData.sharedInstance().disableAutoTrackingIP();

Profiles API

Here is an example of how to look up profiles using the Profiles API.

Copy
Copied
// Set your CDP endpoint to either:
//   https://cdp.in.treasuredata.com        (US)
//   https://cdp-tokyo.in.treasuredata.com  (Tokyo)
//   https://cdp-eu01.in.treasuredata.com   (EU)
//   https://cdp-ap02.in.treasuredata.com   (Seoul)
//   https://cdp-ap03.in.treasuredata.com   (Tokyo)
TreasureData.sharedInstance().setCDPEndpoint("<your_cdp_endpoint>");

TreasureData.sharedInstance().fetchUserSegments(Arrays.asList("<your_profile_api_tokens>"),
                                                Collections.singletonMap("<your_key_column>", "<value>"),
                                                new FetchUserSegmentsCallback() {
                                                    @Override
                                                    public void onSuccess(List<Profile> profiles) {
                                                        System.out.println(profiles);
                                                    }
                                                    @Override
                                                    public void onError(Exception e) {
                                                        System.err.println(e);
                                                    }
                                                });

Enable and Disable Debug Log

javajava
Copy
Copied
  TreasureData.enableLogging();
Copy
Copied
  TreasureData.disableLogging();

Android Version Support

The Android SDK for Arm Treasure Data only supports Android devices running API 28 (Android 9.0) and higher

Codename Version API Tested?
Android 13 11.0 30 Yes
Android 12L 11.0 30 Yes
Android 12 11.0 30 Yes
Android 11 11.0 30 Yes
Android 10 10.0 29 Yes
Pie 9.0 28 Yes

Further Reading

For additional information, refer to the Android SDK Github Repo.