Android Custom Configuration

Using Legacy Gradle Syntax with Heap

All of our quick start examples assume that your application is using the latest Gradle syntax available in Gradle 7.0+ as the Heap Gradle Plugin only supports Android Gradle Plugin 7.2+ which requires Gradle 7.3.3 or higher. However, some applications have lengthy configuration already in place that uses the legacy Gradle syntax which is still valid in newer versions of Gradle. To setup Heap using legacy Gradle syntax, follow the steps below.

  1. In your project-level build.gradle file, add Maven Central as a repository, then add the Heap Gradle Plugin to your classpath.
buildscript {  
  repositories {  
    ...  
    // Add Maven Central as a repository if it isn't already present.  
    mavenCentral()  
  }

  dependencies {  
    ...  
    // IMPORTANT: Ensure that AGP 7.2+ is used. Anything below 7.2 will not work.  
    classpath 'com.android.tools.build:gradle:7.2.0'  
    // Add the Heap Gradle Plugin to the classpath.  
    classpath "io.heap.gradle:heap-plugin:0.3.+"  
  }  
}
  1. At the top of your app-level build.gradle file, apply the Heap Gradle Plugin to enable autocapture of supported UI interactions.
apply plugin: 'com.android.application'  
// Apply the Heap Gradle Plugin. This MUST come after the Android application plugin.  
apply plugin: 'io.heap.gradle'

Automatic Initialization of Autocapture

The simplest way to initialize Heap, as shown in all of our quick start guides, is to call Heap.startRecording when your application launches. However, it’s also possible to enable automatic initialization of Heap using Gradle. This is useful when you have different build types and product flavors and want to customize how Heap is initialized in each of those variants.

  1. Wherever you call Heap.startRecording in your code to start tracking at app startup, remove or comment out those lines. Automatic and manual initialization are mutually exclusive, so you’ll want to ensure that there’s only a single source of initialization in your app.
  2. In your app-level build.gradle file, add an ext block inside of your defaultConfig to set Heap initialization properties for all variants. To enable automatic initialization, set the heapAutoInit flag to true and set heapEnvId to the string representation of your target environment ID.
android {  
  defaultConfig {  
    ...  
    ext {  
      heapAutoInit = true  
      heapEnvId = "YOUR_ENVIRONMENT_ID"  
    }  
  }  
}
android {  
  defaultConfig {  
    ...  
    (this as ExtensionAware).extensions.extraProperties.apply {
      set("heapAutoInit", true)
      set("heapEnvId", "YOUR_ENVIRONMENT_ID")
    }
  }  
}
  1. To customize how Heap is initialized in other build types or product flavors, such as having different environment IDs for debug or release builds, add additional ext blocks to the specific build types you want to customize and override the desired properties. The below example shows how to set a different environment ID for debug builds.
android {  
  defaultConfig {  
    ...  
    // Default properties for all build types and product flavors.  
    ext {  
      heapAutoInit = true  
      heapEnvId = "YOUR_PRODUCTION_ENVIORNMENT_ID"  
    }  
  }  
  buildTypes {  
    debug {  
      // Sending all events from debug mode to a different environment ID  
      // heapAutoInit is still true. Pulled from defaultConfig  
      heapEnvId = "YOUR_DEVELOPMENT_ENVIRONMENT_ID"  
    }  
  }  
}
android {  
  defaultConfig {  
    ...  
    // Default properties for all build types and product flavors.  
    (this as ExtensionAware).extensions.extraProperties.apply {
      set("heapAutoInit", true)
      set("heapEnvId", "YOUR_PRODUCTION_ENVIORNMENT_ID")
    } 
  }  
  buildTypes {  
    getByName("debug") {  
      // Sending all events from debug mode to a different environment ID  
      // heapAutoInit is still true. Pulled from defaultConfig  
      (this as ExtensionAware).extensions.extraProperties.apply {
        set("heapEnvId", "YOUR_DEVELOPMENT_ENVIRONMENT_ID")
      } 
    }  
  }  
}

Below is a full listing of properties supported by the Heap Gradle Plugin for use in automatic initialization.

📘

All property names are case sensitive.

PropertyTypeDefaultDescription
heapAutoInitBooleanfalseBoolean setting to enable initialization configuration at build time.

If this is false, you must initialize Heap programmatically.

If this is true, you must also set heapEnvId to a stringified 53-bit integer.
heapCaptureAdvertiserIdBooleanfalseBoolean setting to enable Advertiser ID capture.
heapDisableTextCaptureBooleanfalseBoolean setting to disable text capture on views.
heapEnabledBooleantrueBoolean setting to enable build-time instrumentation for autocapture.

If this is set to false, UI interactions will not be autocaptured.
heapEnvIdStringnullThe Environment ID to use for initialization configuration at build time.

This setting only takes effect if heapAutoInit is set to true. It must be set to the 53-bit stringified integer Env ID that you wish to send data to.

Setting heapEnvId to an invalid or empty string when heapAutoInit is set to true will result in Heap failing to initialize at run-time. Likewise, failure to set heapEnvId or setting heapEnvId to null when heapAutoInit is true will result in Heap failing to initialize at run-time.

Disable Autocapture

If you want to use Heap, but don’t want to automatically capture user interactions, follow these steps to disable autocapture.

Option 1

The quickest way to disable autocapture without making large changes to your app is to tell the Heap Gradle Plugin to not instrument your code for autocapture.

To do this, add the following block of code to your app-level build.gradle file:

android {  
  defaultConfig {  
    ...  
    // Add this block. If an ext block already exists, simply add the below property.  
    // If the property already exists, make sure it's set to false.  
    ext {  
      heapEnabled = false  
    }  
  }  
}
android {  
  defaultConfig {  
    ...  
    // Add this block. If an ext block already exists, simply add the below property.  
    // If the property already exists, make sure it's set to false.  
    (this as ExtensionAware).extensions.extraProperties.apply {
      set("heapEnabled", false)
    }
  }  
}

Option 2

The second option is to strip out the Heap Gradle Plugin and related autocapture dependency, leaving only the Heap Android Core SDK remaining.

In the app-level build.gradle file, remove the Heap Gradle Plugin.

plugins {  
  id 'com.android.application'  
  // Remove this line.  
  id 'io.heap.gradle' version '0.3.+'  
}
plugins {  
  id("com.android.application")
  // Remove this line.  
  id("io.heap.gradle") version "0.3.+"
}

Further down in the same file, remove the Android View Autocapture SDK and add the Android Core SDK if you haven’t already.

dependencies {  
  // Add this line if it doesn't exist.  
  implementation 'io.heap.core:heap-android-core:0.6.+'  
  // Remove this line.  
  implementation 'io.heap.autocapture:heap-autocapture-view:0.6.+'  
}
dependencies {  
  // Add this line if it doesn't exist.  
  implementation("io.heap.core:heap-android-core:0.6.+")
  // Remove this line.  
  implementation("io.heap.autocapture:heap-autocapture-view:0.6.+")
}

Be sure to clean up any references to ViewAutocaptureSDK in your code, then sync Gradle and rebuild your project. If you’re using automatic initialization, you’ll also want to remove any Heap specific properties from your app-level build.gradle file and be sure to add a startRecording call into your app to enable manual event tracking with Heap.

Add Custom Object Data to Event Properties

Heap already accepts number, boolean, and string data as values for event properties, but there might be times where you want to include custom objects as property values. While all JVM objects have a toString method, this is often used for custom logging or display purposes, which might not be the exact data that you want to track. To prevent alterations to your existing implementations, we’ve introduced a new interface, HeapProperty, that your objects can implement to be used as event property values.

An example implementation might look something like this:

data class Book(  
  val title: String,  
  val author: String,  
  val year: Int  
): HeapProperty {  

  // Existing toString implementation used for display.  
  override fun toString(): String {  
    return "$title by $author"  
  }

  // Only tracking the book title as an event property.  
  override fun toHeapPropertyValue(): String {  
    return title  
  }  
}
public class Book implements HeapProperty {
  private String title;
  private String author;
  private int year;
  
  // Existing toString implementation used for display.
  @Override
	public String toString() {  
    return title + " by " + author;
  }
  
  // Only tracking the book title as an event property.  
  @Override
  public String toHeapPropertyValue() {
    return title;
  }
}

After implementing the HeapProperty interface, objects of this class can now be passed into track calls as a custom property value. While objects of this type can also be used with the addEventProperties API, it’s important to note that the properties are stored as strings behind the scenes and will not update if the object is updated.

Customizing SDK Logs

Setting the Log Level

The Heap Android SDKs output logs at industry-standard log levels based on the severity and usefulness of the log message being printed. You can customize how much is logged to the console (Logcat, in this case) by setting the log level like so:

import io.heap.core.Heap  
import io.heap.core.logs.LogLevel  
...  
Heap.setLogLevel(LogLevel.DEBUG)
import io.heap.core.Heap;
import io.heap.core.logs.LogLevel;
...  
Heap.setLogLevel(LogLevel.DEBUG);

Heap can be customized to print logs at the following log levels:

  • LogLevel.NONE: Heap will not print any log messages.
  • LogLevel.ERROR: Heap will only print the most critical log messages, such as when the SDK encounters an error and needs to shut down.
  • LogLevel.WARN: Heap will print warning messages for recoverable errors, such as when unexpected data types are passed into the SDK or the network is unreachable. Also includes from ERROR logs.
  • LogLevel.INFO: Heap will print messages that are useful in a production environment, such as when recording starts/stops, when a batch of events is successfully sent, or when a new session has begun.
    This level is recommended for production environments so that developers can see Heap lifecycle messages in their own logging environment. Also includes ERROR and WARN logs.
  • LogLevel.DEBUG: Heap will print messages that the implementing developer may find helpful. Messages may include things such as invalid environment ID value, truncated event names, or attempting to track an event before recording has started.
    This level is recommended for implementing developers during the development process to help with debugging normal installation and tracking issues. Also includes ERROR, WARN, and INFO logs.
  • LogLevel.TRACE: Heap will print messages that help the Heap team diagnose SDK issues. Heap support may ask the implementing developers to enable this log level to gain better insight into issues developers may have encountered when implementing the Heap SDK.
    Full event details are also printed at this level.
    This level is recommended when gathering information to send to Heap support personnel. Heap support may also ask that this level be turned on to help debug installation and tracking issues that require extra investigation. Also includes ERROR, WARN, INFO, and DEBUG logs.

Routing Logs to Custom Destinations

In addition to customizing how much is printed by setting the log level, you can also customize where logs are printed by setting a custom log channel. By default, all logs are printed to Logcat with the same output level as the Heap log level name (the only difference being TRACE is printed to Log.v). If you’re using a logging library like Timber or Arbor and want to send all logs through those channels instead, simply make a new LogChannel and pass it to Heap like so:

import io.heap.core.Heap  
import io.heap.core.logs.LogChannel  
import io.heap.core.logs.LogLevel

class TimberLogChannel : LogChannel {

  // Only one method to override.  
  override fun printLog(  
    logLevel: LogLevel,  
    message: String,  
    source: String?,  
    throwable: Throwable?  
  ) {
    // Send Heap logs to different locations based on LogLevel.
    when(logLevel) {
      LogLevel.TRACE -> Timber.v(throwable, message)
      LogLevel.DEBUG -> Timber.d(throwable, message)
      LogLevel.INFO -> Timber.i(throwable, message)
      LogLevel.WARN -> Timber.w(throwable, message)
      LogLevel.ERROR -> Timber.e(throwable, message)
      LogLevel.NONE -> {
        // Print nothing.
      }
    }
  }  
}
import io.heap.core.Heap;
import io.heap.core.logs.LogChannel;
import io.heap.core.logs.LogLevel;

public class TimberLogChannel implements LogChannel {

  @Override
  public void printLog(
    @NonNull LogLevel logLevel,
    @NonNull String message,
    @Nullable String source,
    @Nullable Throwable throwable
  ) {
    switch(logLevel) {
      case LogLevel.TRACE: { Timber.v(throwable, message); } break;
      case LogLevel.DEBUG: { Timber.d(throwable, message); } break;
      case LogLevel.INFO: { Timber.i(throwable, message); } break;
      case LogLevel.WARN: { Timber.w(throwable, message); } break;
      case LogLevel.ERROR: { Timber.e(throwable, message); } break;
      case LogLevel.NONE: { /* Print nothing. */ }
    }
  } 
}

Capture Advertiser and Vendor ID

You are able to capture the Android advertiser ID starting in Android Core 0.1.0 simply by setting the configuration option, captureAdvertiserId, to true. Setting this option causes Heap to attempt to retrieve the Google Play advertiser ID and send as part of event payloads.

Starting in Android Core 0.5.0, this behavior has been updated to allow selection of either the Google Play or Amazon advertiser IDs. Additionally, you are now able to capture the Android vendor ID using Google's App Set ID for apps distributed through Google Play.

To enable advertiser or vendor ID capture, first start by setting the required initialization option.

Heap.startRecording(
  context, 
  "YOUR_APP_ID",
  Options(
    captureAdvertiserId = true,
    captureVendorId = true
  )
)
Heap.startRecording(
  context, 
  "YOUR_APP_ID",
  new Options.Builder()
  	.setShouldCaptureAdvertiserId(true)
  	.setShouldCaptureVendorId(true)
  	.build()
)

Next, you'll need to add an Advertiser ID Provider or Vendor ID Provider to your application. These come in the form of an additional artifact that contains all of the required code and dependencies for the given identifier that you want to capture.

dependencies {
  implementation 'io.heap.core:heap-android-core:0.7.4'
 
  // Only include one advertiser ID provider per app config. (Version should match Core)
  // Advertiser ID Providers:
  implementation 'io.heap.core.identifier:ad-id-google:0.7.4'
  implementation 'io.heap.core.identifier:ad-id-amazon:0.7.4'
  
  // Vendor ID Providers:
  implementation 'io.heap.core.identifier:vendor-id-google:0.7.4'
}

That's it! If your setup is correct, you'll see a log message when running your app that says "Heap vendor ID provider found" or "Heap advertiser ID provider found." If you see a message that no provider was found or more than one provider was found, be sure to check that you've cleaned and rebuilt and that you've only included one advertiser or vendor ID provider per app configuration.

Overriding Target Text Capture

When Heap generates an autocapture event, the SDK uses a set of rules to determine the target text that should be associated with the event. In most cases this is either the text assigned to the UI component or the text of the closest parent or child component. However, there are some cases where you might want to have a strong guarantee that the target text for event matches a specific value. This can be useful if your interaction target is a layout or a recycled component in a list or grid. For this, you can override the target text for a view.

📘

This functionality is available starting in version 0.7.2 of the Heap Android View Autocapture SDK.

fun setupClickableView(title: String) {
  val clickTarget = findViewById<LinearLayout>(R.id.some_clickable_layout)
  ViewAutocaptureSDK.overrideTargetText(clickTarget, title)
}
public void setupClickableView(String title) {
  LinearLayout clickTarget = findViewById(R.id.some_clickable_layout);
  ViewAutocaptureSDK.overrideTargetText(clickTarget, title);
}