Android Advanced Features

Learn more about advanced Android features.

Overview

Add advanced features to your app, such as event tracking, location reporting, data opt-outs, push notification support, and support for Play Store privacy compliance.

The SDK also supports PII Encryption at rest and in transit, ensuring that sensitive user data such as Email, Identity, Name, and Phone is securely stored and transmitted over the network, offering end-to-end data protection.

Opt Out

From CleverTap Android SDK 3.1.9 onwards, in compliance with GDPR, we provide the following method using which the app can stop sending events to CleverTap.

val cleverTap = CleverTapAPI.getDefaultInstance(this)
cleverTap.setOptOut(true)
CleverTapAPI cleverTap = CleverTapAPI.getDefaultInstance(this);
cleverTap.setOptOut(true);

From CleverTap Android SDK 7.5.0 onwards, the setOptOut() method supports an enhanced signature that allows apps to stop tracking events while sending generic, non-personalized communications, in compliance with GDPR guidelines.

val cleverTap = CleverTapAPI.getDefaultInstance(this)
// Only stop tracking, allow generic comms
cleverTap.setOptOut(true, true)
CleverTapAPI cleverTap = CleverTapAPI.getDefaultInstance(this);
// Only stop tracking, allow generic comms
cleverTap.setOptOut(true, true);

If the user wants to opt in again to share their data, you call the same method like this.

val cleverTap = CleverTapAPI.getDefaultInstance(this)
cleverTap.setOptOut(false)
CleverTapAPI cleverTap = CleverTapAPI.getDefaultInstance(this);
cleverTap.setOptOut(false);

By default, the SDK will send data to CleverTap, and the opt-out will be set to false. It would be a good practice to capture the opt-out flag of the user and set it whenever the app launches.

Enable Device Networking Info Reporting

From CleverTap Android SDK 3.1.9 onwards, in compliance with GDPR, the CleverTap Android SDK will not capture any kind of personal information like WiFi, Bluetooth, Network Information and user IP information. To enable the capturing of all this information, you can call the following method:

val cleverTap = CleverTapAPI.getDefaultInstance(this)
cleverTap.enableDeviceNetworkInfoReporting(true)
CleverTapAPI cleverTap = CleverTapAPI.getDefaultInstance(this);
cleverTap.enableDeviceNetworkInfoReporting(true);

To disable Device Network information to be sent to CleverTap you can use the same method as follows.

val cleverTap = CleverTapAPI.getDefaultInstance(this)
cleverTap.enableDeviceNetworkInfoReporting(false)
CleverTapAPI cleverTap = CleverTapAPI.getDefaultInstance(this);
cleverTap.enableDeviceNetworkInfoReporting(false);

By default, CleverTap does not collect device network information.

Set Offline

CleverTap Android SDK provides a method to set the user as offline. Setting the user offline means that no events/profile information will be sent to CleverTap. You can set the user as offline using the following method

val cleverTap = CleverTapAPI.getDefaultInstance(this)
cleverTap.setOffline(true)
CleverTapAPI cleverTap = CleverTapAPI.getDefaultInstance(this);
cleverTap.setOffline(true);

You can set the user back online using the following method

val cleverTap = CleverTapAPI.getDefaultInstance(this)
cleverTap.setOffline(false)
CleverTapAPI cleverTap = CleverTapAPI.getDefaultInstance(this);
cleverTap.setOffline(false);

Encryption of PII Data

PII data is stored across the SDK and could contain sensitive information. From CleverTap SDK v5.2.0 onwards, you can enable encryption for PII data such as Email, Identity, Name, Phone, etc.

Currently, two levels of encryption are supported: None(0) and Medium(1). The encryption level is None by default.

  • None: All stored data is in plaintext
  • Medium: PII data is encrypted completely

The only way to set the encryption level for the default instance is from the AndroidManifest.xml.

Add the following to the AndroidManifest.xml file:

<meta-data
    android:name="CLEVERTAP_ENCRYPTION_LEVEL"
    android:value="1" />

Different instances can have different encryption levels. To set an encryption level for an additional instance:

CleverTapInstanceConfig clevertapAdditionalInstanceConfig = CleverTapInstanceConfig.createInstance(
    applicationContext,
    "ADDITIONAL_CLEVERTAP_ACCOUNT_ID",
    "ADDITIONAL_CLEVERTAP_ACCOUNT_TOKEN"
)

clevertapAdditionalInstanceConfig.setEncryptionLevel(CryptHandler.EncryptionLevel.MEDIUM)
CleverTapAPI clevertapAdditionalInstance = CleverTapAPI.instanceWithConfig(applicationContext ,clevertapAdditionalInstanceConfig)

Encryption in Transit

Encryption in Transit ensures that sensitive personal data, such as Email, Identity, Name, Phone, etc., is encrypted before being sent over the network. This protects user data during transmission and adds an extra layer of security beyond at-rest encryption.

From CleverTap Android SDK 7.5.0 onwards, this feature is supported natively, with encryption and decryption handled automatically by the SDK.

๐Ÿ“˜

Private Beta

This feature is currently released in Private Beta. To enable it, contact CleverTap Support. Ensure it is activated for your account before implementing it in the SDK.

Encryption Scope

Encryption in transit applies to all event data.

Prerequisites for Encryption In Transit

To use this feature, ensure the following conditions are met:

  1. Reach out to your account manager to enable the encryption feature on your account.
  2. Set the string key CleverTapEncryptionInTransitEnabled to 1 in your appโ€™s AndroidManifest.xml.

Encryption Specifications

The following table outlines the encryption specifications used by the CleverTap SDK:

ParameterValue
AlgorithmAES-256 (symmetric)
IV Size12 bytes (96 bits)
EncodingBase64 for all encrypted content
Key ManagementBase64 direct (v0), RSA planned (v1)

Error Scenarios

The SDK returns the following error codes when encryption in transit fails:

Error CodeScenarioError Message
402Encryption feature is not enabled."Encryption In Transit disabled. Retry with plain text"
419Encryption header missing."Encryption In Transit request failed, retry with plain text"
400Malformed request."Invalid JSON payload"

Referral Tracking

From CleverTap SDK 3.6.4 onwards, add the following Gradle dependency to capture UTM details, app-install time, referrer click time, and other metrics provided by Google Install Referrer Library.

implementation 'com.android.installreferrer:installreferrer:2.2'

Debugging

Follow the steps for debugging your app:

  1. By default, CleverTap logs are set to CleverTap.Loglevel.INFO. We recommend that you set the SDK to VERBOSE mode to log warnings or other important messages to the Android logging system during development. This can be done by setting the debug level to CleverTap.Loglevel.VERBOSE. If you want to disable CleverTap logs for the production environment, you can set the debug level to CleverTap.Loglevel.OFF.
CleverTapAPI.setDebugLevel(CleverTapAPI.LogLevel.INFO) //Default Log level

CleverTapAPI.setDebugLevel(CleverTapAPI.LogLevel.DEBUG) //Set Log level to DEBUG log warnings or other important messages

CleverTapAPI.setDebugLevel(CleverTapAPI.LogLevel.VERBOSE) //Set Log level to VERBOSE

CleverTapAPI.setDebugLevel(CleverTapAPI.LogLevel.OFF) //Switch off logs for Production environment}
CleverTapAPI.setDebugLevel(CleverTapAPI.LogLevel.INFO);    //Default Log level

CleverTapAPI.setDebugLevel(CleverTapAPI.LogLevel.DEBUG);   //Set Log level to DEBUG log warnings or other important messages

CleverTapAPI.setDebugLevel(CleverTapAPI.LogLevel.VERBOSE);     //Set Log level to VERBOSE

CleverTapAPI.setDebugLevel(CleverTapAPI.LogLevel.OFF); //Switch off logs for Production environment
  1. After setting the debug level to CleverTap.Loglevel.VERBOSE, search for Clevertap. The logcat displays the handshakes between CleverTap and your app.
  2. Copy the CleverTap ID from the logs.
  3. Open the CleverTap dashboard.
  4. Navigate to Segments> Find People > search By Identity.
1205

Find People by Identity

Changing Account Credentials

If youโ€™d not want to insert your account credentials in your appโ€™s AndroidManifest.xml, or would like to change your account ID programmatically, you need to create a custom Application class (if you donโ€™t have one already) with the following content.

import android.app.Application
import com.clevertap.android.sdk.ActivityLifecycleCallback
import com.clevertap.android.sdk.CleverTapAPI

class MyApplication:Application() {
  override fun onCreate() {
    CleverTapAPI.changeCredentials("Your account ID here", "Your account token here")
    ActivityLifecycleCallback.register(this) // Must be called before super.onCreate()
    super.onCreate()
  }
}
import android.app.Application;
import com.clevertap.android.sdk.ActivityLifecycleCallback;
import com.clevertap.android.sdk.CleverTapAPI;

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        CleverTapAPI.changeCredentials("Your account ID here", "Your account token here");
        ActivityLifecycleCallback.register(this); // Must be called before super.onCreate()
        super.onCreate();
    }
}

If youโ€™ve just created this subclass of Application, update your AndroidManifest.xml to specify your subclass.

<application
    android:label="@string/app_name"
    android:icon="@drawable/ic_launcher"
    android:name=".MyApplication">

If you have used this method, to set your CleverTap Account ID and Token, please do not add these values to your manifest file.

Manually Updating User Location

The application is responsible for requesting the userโ€™s permission to use location. If this permission is granted, location can be passed to CleverTap.

The App can pass the location to the SDK using setLocation.

val cleverTapAPI = CleverTapAPI.getDefaultInstance(getApplicationContext())
cleverTapAPI.setLocation(location) //android.location.Location}
CleverTapAPI cleverTapAPI = CleverTapAPI.getDefaultInstance(getApplicationContext());
cleverTapAPI.setLocation(location); //android.location.Location

Using Your Existing Activity Lifecycle Listener

If youโ€™d like to use your own activity lifecycle listener, please update it to incorporate the following code.

registerActivityLifecycleCallbacks(object : android.app.Application.ActivityLifecycleCallbacks {
            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                CleverTapAPI.setAppForeground(true)
                try
                {
                    CleverTapAPI.getDefaultInstance(applicationContext)?.pushNotificationClickedEvent(activity.intent.extras)
                }
                catch (t:Throwable) {
                    // Ignore
                }
                try
                {
                    val intent = activity.intent
                    val data = intent.data
                    CleverTapAPI.getDefaultInstance(applicationContext)?.pushDeepLink(data)
                }
                catch (t:Throwable) {
                    // Ignore
                }
            }
            override fun onActivityStarted(activity: Activity) {
            }
            override fun onActivityResumed(activity: Activity) {
                try
                {
                    CleverTapAPI.onActivityResumed(activity)
                }
                catch (t:Throwable) {
                    // Ignore
                }
            }
            override fun onActivityPaused(activity: Activity) {
                try
                {
                    CleverTapAPI.onActivityPaused()
                }
                catch (t:Throwable) {
                    // Ignore
                }
            }
            override fun onActivityStopped(activity: Activity) {
            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle){
            }
            override fun onActivityDestroyed(activity: Activity) {
            }
        })
application.registerActivityLifecycleCallbacks(
        new android.app.Application.ActivityLifecycleCallbacks() {
        
            @Override
            public void onActivityCreated(Activity activity, Bundle bundle) {
                CleverTapAPI.setAppForeground(true);
                try {
                    CleverTapAPI.getDefaultInstance(application).pushNotificationClickedEvent(activity.getIntent().getExtras());
                } catch (Throwable t) {
                    // Ignore
                }
                try {
                    Intent intent = activity.getIntent();
                    Uri data = intent.getData();
                    CleverTapAPI.getDefaultInstance(application).pushDeepLink(data);
                } catch (Throwable t) {
                    // Ignore
                }
            }
            
            @Override
            public void onActivityStarted(Activity activity) {
            }
            
            @Override
            public void onActivityResumed(Activity activity) {
                try {
                    CleverTapAPI.getDefaultInstance(application).onActivityResumed(activity);
                } catch (Throwable t) {
                    // Ignore
                }
            }
            
            @Override
            public void onActivityPaused(Activity activity) {
                try {
                    CleverTapAPI.getDefaultInstance(application).onActivityPaused();
                } catch (Throwable t) {
                    // Ignore
                }
            }
            
            @Override
            public void onActivityStopped(Activity activity) {
            }
            
            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
            }
            
            @Override
            public void onActivityDestroyed(Activity activity) {
            }
        }
);

Update on Google Play Store privacy requirements

Refer to Google play store privacy requirements.


Whatโ€™s Next