Android v3 (Legacy) - Overview

This developer guide describes how to implement Google Tag Manager in a mobile application.

Introduction

Google Tag Manager enables developers to change configuration values in their mobile applications using the Google Tag Manager interface without having to rebuild and resubmit application binaries to app marketplaces.

This is useful for managing any configuration values or flags in your application that you may need to change in the future, including:

  • Various UI settings and display strings
  • Sizes, locations, or types of ads served in your application
  • Game settings

Configuration values may also be evaluated at runtime using rules, enabling dynamic configurations such as:

  • Using screen size to determine ad banner size
  • Using language and location to configure UI elements

Google TagManager also enables the dynamic implementation of tracking tags and pixels in applications. Developers can push important events into a data layer and decide later which tracking tags or pixels should be fired. TagManager currently supports the following tags:

  • Google Mobile App Analytics
  • Custom Function Call tag

Before you Begin

Before using this getting started guide, you'll need the following:

If you're new to Google Tag Manager, we recommend that you learn more about containers, macros, and rules (Help Center) before continuing this guide.

Getting Started

This section will guide developers through a typical Tag Manager workflow:

  1. Add the Google Tag Manager SDK to your project
  2. Set Default Container Values
  3. Open the Container
  4. Get Configuration Values from the Container
  5. Push Events to the DataLayer
  6. Preview & Publish the Container

1. Adding the Google Tag Manager SDK to Your Project

Before using the Google Tag Manager SDK, you'll need to unzip the SDK package and add the library to the build path of your project and add permissions to your AndroidManifest.xml file.

First, add the Google Tag Manager library to the /libs folder of your project.

Next, update your AndroidManifest.xml file to use the following permissions:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

2. Adding a Default Container File to your Project

Google Tag Manager uses a default container on the first run of your application. The default container will be used until the app is able to retrieve a fresh container over the network.

To download and add a default container binary to your application, follow these steps:

  1. Sign in to the Google Tag Manager web interface.
  2. Select the Version of the container you'd like to download.
  3. Click the Download button to retrieve the container binary.
  4. Add the binary file to the following path: <project-root>/assets/tagmanager/

The default filename should be the container ID (for example GTM-1234). Once you've downloaded the binary file, be sure to remove the version suffix from the filename to ensure you follow the correct naming convention.

Although using the binary file is recommended, if your container does not contain rules or tags, you may choose to use a simple JSON file instead. The file must be located in a new /assets/tagmanager folder of your Android project and should follow this naming convention: <Container_ID>.json. For example, if your container ID is GTM-1234, you should add your default container values to /assets/tagmanager/GTM-1234.json.

3. Opening a Container

Before retrieving values from a container, your application needs to open the container. Opening a container will load it from disk (if available), or will request it from the network (if needed).

The easiest way to open a container on Android is by using ContainerOpener.openContainer(..., Notifier notifier), as in the following example:

import com.google.tagmanager.Container;
import com.google.tagmanager.ContainerOpener;
import com.google.tagmanager.ContainerOpener.OpenType;
import com.google.tagmanager.TagManager;

import android.app.Activity;
import android.os.Bundle;

public class RacingGame {

  // Add your public container ID.
  private static final String CONTAINER_ID = "GTM-YYYY";

  volatile private Container mContainer;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    TagManager mTagManager = TagManager.getInstance(this);

    // The container is returned to containerFuture when available.
    ContainerOpener.openContainer(
        mTagManager,                            // TagManager instance.
        CONTAINER_ID,                           // Tag Manager Container ID.
        OpenType.PREFER_NON_DEFAULT,            // Prefer not to get the default container, but stale is OK.
        null,                                   // Time to wait for saved container to load (ms). Default is 2000ms.
        new ContainerOpener.Notifier() {        // Called when container loads.
          @Override
          public void containerAvailable(Container container) {
            // Handle assignment in callback to avoid blocking main thread.
            mContainer = container;
          }
        }
    );
    // Rest of your onCreate code.
  }
}

In this example, ContainerOpener.openContainer(..., Notifier notifier) is used to request a saved container from local storage. By handling the assignment of mContainer in the containerAvailable callback, we ensure that the main thread is not blocked. If the saved container is older than 12 hours, the call will also schedule a request to asynchronously retrieve a fresh container over the network.

This sample implementation represents the simplest way to open and retrieve values from a container using the ContainerOpener convenience class. For more advanced implementation options, see Advanced Configuration.

4. Getting Configuration Values from the Container

Once the container is open, configuration values may be retrieved using the get<type>Value() methods:

// Retrieving a configuration value from a Tag Manager Container.

// Get the configuration value by key.
String title = mContainer.getStringValue("title_string");

Requests made with a non-existent key will return a default value appropriate to the type requested:

// Empty keys will return a default value depending on the type requested.

// Key does not exist. An empty string is returned.
string subtitle = container.getStringValue("Non-existent-key");
subtitle.equals(""); // Evaluates to true.

5. Pushing Values to the DataLayer

The DataLayer is a map that enables runtime information about your app, such as touch events or screen views, to become available to Tag Manager macros and tags in a container.

For example, by pushing information about screen views into the DataLayer map, you can set up tags in the Tag Manager web interface to fire conversion pixels and tracking calls in response to those screenviews without needing to hard code them into your app.

Events are pushed to the DataLayer using push() and the DataLayer.mapOf() helper method:

//
// MainActivity.java
// Pushing an openScreen event with a screen name into the data layer.
//

import com.google.tagmanager.TagManager;
import com.google.tagmanager.DataLayer;

import android.app.Activity;
import android.os.Bundle;

public MainActivity extends Activity {

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

  }

  // This screen becomes visible when Activity.onStart() is called.
  public void onStart() {
    super.onStart();

    // The container should have already been opened, otherwise events pushed to
    // the DataLayer will not fire tags in that container.
    DataLayer dataLayer = TagManager.getInstance(this).getDataLayer();
    dataLayer.push(DataLayer.mapOf("event",
                                   "openScreen",      // The event type. This value should be used consistently for similar event types.
                                   "screenName",      // Writes a key "screenName" to the dataLayer map.
                                   "Home Screen")     // Writes a value "Home Screen" for the "screenName" key.
    );
  }
  // Rest of the Activity implementation
}

In the web interface, you can now create tags (like Google Analytics tags) to fire for each screen view by creating this rule: {{ event }} equals "openScreen". To pass the screen name to one of these tags, create a data layer macro that references the "screenName" key in the data layer. You can also create a tag (like a Google Ads conversion pixel) to fire only for specific screen views, by creating a rule where {{ event }} equals "openScreen" && {{ screenName }} equals "ConfirmationScreen".

6. Previewing & Publishing a Container

Macro values will always correspond to the current published version. Before publishing the latest version of a container, you can preview your draft container.

To preview a container, generate a preview URL in the Google Tag Manager web interface by selecting the version of the container you'd like to preview, and then selecting Preview. Hang on to this preview URL as you'll need it in later steps.

Preview URLs are available in the preview window of the Tag
           Manager web interface
Figure 1: Getting a preview URL from the Tag Manager web interface.

Next, add the following Activity to your application's AndroidManifest.xml file:

<!-- Google Tag Manager Preview Activity -->
<activity
  android:name="com.google.tagmanager.PreviewActivity"
  android:label="@string/app_name"
  android:noHistory="true" >  <!-- Optional, removes the PreviewActivity from activity stack. -->
  <intent-filter>
    <data android:scheme="tagmanager.c.application_package_name" />
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE"/>
  </intent-filter>
</activity>
  

Open the link on an emulator or physical device to preview the draft container in your app.

When you're ready to make your draft configuration values available to your application, publish the container.

Advanced Configuration

Google Tag Manager for Mobile has a number of advanced configuration options that allow you to select values based on runtime conditions using rules, manually refresh the container, and get additional options for opening containers. The following sections outline several of the most common advanced configurations.

Advanced Options for Opening Containers

The Google Tag Manager SDK provides several methods for opening containers that can give you more control over the loading process:

TagManager.openContainer()

TagManager.openContainer() is the lowest level and most flexible API for opening a container. It returns immediately with a default container and also asynchronously loads a container from disk or the network if no saved container exists, or if the saved container is not fresh (> 12 hours old).

mContainer = tagManager.openContainer(CONTAINER_ID, new Container.Callback() {

  // Called when a refresh is about to begin for the given refresh type.
  @Override
  public void containerRefreshBegin(Container container, RefreshType refreshType) {
    // Notify UI that the Container refresh is beginning.
   }

  // Called when a successful refresh occurred for the given refresh type.
  @Override
  public void containerRefreshSuccess(Container container, RefreshType refreshType]) {
    // Notify UI that Container is ready.
  }

  // Called when a refresh failed for the given refresh type.
  @Override
  public void containerRefreshFailure(Container container,
                                      RefreshType refreshType,
                                      RefreshFailure refreshFailure) {
    // Notify UI that the Container refresh has failed.
  }

Throughout the loading process, TagManager.openContainer() issues several lifecycle callbacks so that your code can find out when the loading request begins, whether and why it fails or succeeds, and whether the container was ultimately loaded from disk or network.

Unless it is acceptable for your application to use the default values, you will need to use these callbacks to know when a saved or network container has loaded. Note that you will be unable to load a saved or network container if this is the first time the app is run and there's no network connection.

TagManager.openContainer() passes the following enum values as arguments to these callbacks:

RefreshType

ValueDescription
Container.Callback.SAVED The refresh request is loading a locally saved container.
Container.Callback.NETWORK The refresh request is loading a container over the network.

RefreshFailure

ValueDescription
Container.Callback.NO_SAVED_CONTAINER There is no saved container available.
Container.Callback.IO_ERROR An I/O error prevented refreshing the container.
Container.Callback.NO_NETWORK There is no network connection available.
Container.Callback.NETWORK_ERROR A network error has occurred.
Container.Callback.SERVER_ERROR An error on the server has occurred.
Container.Callback.UNKNOWN_ERROR An error that can't be categorized has occurred.

Methods for Opening Non-Default and Fresh Containers

ContainerOpener wraps TagManager.openContainer() and provides two convenience methods for opening containers: ContainerOpener.openContainer(..., Notifier notifier) and ContainerOpener.openContainer(..., Long timeoutInMillis).

Each of these methods takes an enumeration requesting either a non-default or fresh container.

OpenType.PREFER_NON_DEFAULT is recommended for most applications and attempts to return the first available non-default container within a given timeout period, either from disk or network, even if that container is greater than 12 hours old. If it returns a stale saved container, it will also make an asynchronous network request for a fresh one. When using OpenType.PREFER_NON_DEFAULT, a default container will be returned if no other container is available, or if the timeout period is exceeded.

OpenType.PREFER_FRESH attempts to return a fresh container from either disk or network within the given timeout period. It returns a saved container if a network connection is unavailable and/or the timeout period is exceeded.

It is not recommended to use OpenType.PREFER_FRESH in places where a longer request time may noticeably affect user experience, such as with UI flags or display strings. You may also use Container.refresh() at any time to force a network container request.

Both of these convenience methods are non-blocking. ContainerOpener.openContainer(..., Long timeoutInMillis) returns a ContainerOpener.ContainerFuture object, whose get method returns a Container as soon as it has loaded (but that will block until then). The ContainerOpener.openContainer(..., Notifier notifier) method takes a single callback, called when the container is available, which can be used to prevent blocking the main thread. Both methods have a default timeout period of 2000 milliseconds.

Evaluating Macros at Runtime using Rules

Containers can evaluate values at runtime using rules. Rules may be based on criteria like device language, platform, or any other macro value. For example, rules can be used to select a localized display string based on the language of the device at runtime. This can be configured by using the following rule:

A rule is used to select display strings based on device language at
            runtime: language equals es. This rule uses the pre-defined language
            macro and a two character ISO 639-1 language code.
Figure 1:Adding a rule to enable a value collection macro only for devices configured to use the Spanish language.

You can then create value collection macros for each language, and add this rule to each macro, inserting the appropriate language code. When this container is published, your application will be able to display localized display strings, depending on the language of the user's device at runtime.

Note that if your default container needs rules, you must use a binary container file as your default container.

Learn more about configuring rules (Help Center).

Binary Default Container Files

Default containers that need rules should use a binary container file instead of a JSON file as the default container. Binary containers offer support for determining macro values at runtime with Google Tag Manager rules, whereas JSON files do not.

Binary container files may be downloaded from the Google Tag Manager web interface and should be added to your project's /assets/tagmanager/ folder and follow this pattern: /assets/tagmanager/GTM-XXXX, where the filename represents your container ID.

In cases where a JSON file as well as a binary container file are present, the SDK will use the binary container file as the default container.

Using Function Call Macros

Function Call Macros are macros that are set to the return value of a specified function in your application. Function Call Macros can be used to incorporate runtime values with your Google Tag Manager rules, such as determine at runtime which price to display to a user based on the configured language and currency of a device.

To configure a function call macro:

  1. Define the function call macro in the Google Tag Manager web interface. Arguments may optionally be configured as key-value pairs.
  2. Register a FunctionCallMacroHandler in your application using Container.registerFunctionCallMacroHandler() and the function name you configured in the Google Tag Manager web interface, overriding its getValue() method:
    /**
     * Registers a function call macro handler.
     *
     * @param functionName The function name field, as defined in the Google Tag
     *     Manager web interface.
     */
    mContainer.registerFunctionCallMacroHandler(functionName, new FunctionCallMacroHandler() {
    
      /**
       * This code will execute when any custom macro's rule(s) evaluate to true.
       * The code should check the functionName and process accordingly.
       *
       * @param functionName Corresponds to the function name field defined
       *     in the Google Tag Manager web interface.
       * @param parameters An optional map of parameters
       *     as defined in the Google Tag Manager web interface.
       */
      @Override
      public Object getValue(String functionName, Map<String, Object> parameters)) {
    
        if (functionName.equals("myConfiguredFunctionName")) {
          // Process and return the calculated value of this macro accordingly.
          return macro_value
        }
        return null;
      }
    });
    

Using Function Call Tags

Function Call Tags enable pre-registered functions to be executed whenever an event is pushed into the data layer and the tag rules evaluate to true.

To configure a function call tag:

  1. Define the function call tag in the Google Tag Manager web interface. Arguments may optionally be configured as key-value pairs.
  2. Register a function call tag handler in your application using Container.registerFunctionCallTagHandler():
    /**
     * Register a function call tag handler.
     *
     * @param functionName The function name, which corresponds to the function name field
     *     Google Tag Manager web interface.
     */
    mContainer.registerFunctionCallTagHandler(functionName, new FunctionCallTagHandler() {
    
      /**
       * This method will be called when any custom tag's rule(s) evaluates to true.
       * The code should check the functionName and process accordingly.
       *
       * @param functionName The functionName passed to the functionCallTagHandler.
       * @param parameters An optional map of parameters as defined in the Google
       *     Tag Manager web interface.
       */
      @Override
      public void execute(String functionName, Map<String, Object> parameters) {
        if (functionName.equals("myConfiguredFunctionName")) {
          // Process accordingly.
        }
      }
    });
    

Setting a Custom Refresh Period

The Google Tag Manager SDK will attempt to retrieve a fresh container if the current container age exceeds 12 hours. To set a custom container refresh period, use Timer , as in the following example:

timer.scheduleTask(new TimerTask() {
  @Override
  public void run() {
    mContainer.refresh();
  }
}, delay, <new_period_in milliseconds>);

Debugging with Logger

The Google Tag Manager SDK prints errors and warnings to logs by default. Enabling more verbose logging can be helpful for debugging and is possible by implementing your own Logger with TagManager.setLogger, as in this example:

TagManager tagManager = TagManager.getInstance(this);
tagManager.setLogger(new Logger() {

  final String TAG = "myGtmLogger";

  // Log output with verbosity level of DEBUG.
  @Override
  public void d(String arg0) {
    Log.d(TAG, arg0);
  }

  // Log exceptions when provided.
  @Override
  public void d(String arg0, Throwable arg1) {
    Log.d(TAG, arg0);
    arg1.printStackTrace();
  }

  // Rest of the unimplemented Logger methods.

});

Or, you can set the LogLevel of the existing Logger by using TagManager.getLogger().setLogLevel(LogLevel) , as in this example:

// Change the LogLevel to INFO to enable logging at INFO and higher levels.
TagManager tagManager = TagManager.getInstance(this);
tagManager.getLogger().setLogLevel(LogLevel.INFO);