Google Analytics SDK v4 with libGDX

Introduction

Google discourages the use of the legacy Analytics SDK in new projects. Instead the want you to use Android Native Application Tracking as provided by Google Play Services. Some documentation is provided to get you started. We want to implement Analytics in a libGDX project. This is how we did it for our simple game Cave Fizzer.

Create a property

Start by creating a new property fro your app in Google Analytics. You may already have one if you have set up AdMob before. You’ll need the tracking ID in your app.

Add the Google Play Services library

Start the Android SDK manager and make sure you have the latest version of Google Play services installed. Locate the google-play-services_lib project and copy it to wherever you want to keep your library projects. Import it into Eclipse (File->Import->Android->Existing Projects into Workspace). Check the ‘Is library’ box for this project (Properties->Android->Library). Add the library to your game’s Android project (Properties->Android->Library).

Update the manifest

You need to have these permissions in AndroidManifest.xml:

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

Set the minSdkVersion to 9.

Add this element to application:

<meta-data
    android:name="com.google.android.gms.analytics.globalConfigResource"
    android:resource="@xml/global_tracker" />

Create the tracker configuration files

In res/xml, create the following files. Insert your tracking ID and modify the screen names the screen names to your needs. In global_tracker.xml these are custom names that you’ll send to Analytics from within your app.

global_tracker.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 
    <integer name="ga_sessionTimeout">300</integer>
 
    <!-- Enable automatic Activity measurement -->
    <bool name="ga_autoActivityTracking">true</bool>
 
    <!-- Percentage of events to include in reports -->
    <string name="ga_sampleFrequency">100.0</string>
 
    <!-- catch and report uncaught exceptions from the app -->
    <bool name="ga_reportUncaughtExceptions">true</bool>
 
    <!-- How long a session exists before giving up -->
    <integer name="ga_sessionTimeout">-1</integer>
 
    <!-- the Local LogLevel for Analytics -->
    <string name="ga_logLevel">verbose</string>
 
    <!-- how often the dispatcher should fire -->
    <integer name="ga_dispatchPeriod">30</integer>
 
    <!-- Treat events as test events and don't send to google -->
    <bool name="ga_dryRun">false</bool>
 
    <!-- The screen names that will appear in reports -->
    <screenName name="de.nitri.cavefizzer.Intro">Cave Fizzer Intro</screenName>
    <screenName name="de.nitri.cavefizzer.GameOver">Cave Fizzer Game Over</screenName>
 
    <!-- The following value should be replaced with correct property id. -->
    <string name="ga_trackingId">UA-00000000-00</string>
 
</resources>

app_tracker.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="TypographyDashes">
 
    <!-- The apps Analytics Tracking Id -->
    <string name="ga_trackingId">UA-00000000-00</string>
 
    <!-- Percentage of events to include in reports -->
    <string name="ga_sampleFrequency">100.0</string>
 
    <!-- Enable automatic Activity measurement -->
    <bool name="ga_autoActivityTracking">true</bool>
 
    <!-- catch and report uncaught exceptions from the app -->
    <bool name="ga_reportUncaughtExceptions">true</bool>
 
    <!-- How long a session exists before giving up -->
    <integer name="ga_sessionTimeout">-1</integer>
 
    <screenName name="de.nitri.caveFizzer.android.AndroidLauncher">Android Launcher</screenName>
 
</resources>

ecommerce_tracker.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="ga_sessionTimeout">60</integer>
    <!--  The following value should be replaced with correct property id. -->
    <string name="ga_trackingId">UA-00000000-0</string>
</resources>

Extend the Application class to provide a tracker getter

Create a class that extends Application in your Android project. The method getTracker() provides the appropriate tracker type when requested. (I had to import the R file because the application package is de.nitri.cavefizzer, whereas the Android sources reside in de.nitri.cavefizzer.android.)

MyApplication.java:

package de.nitri.cavefizzer.android;
 
import java.util.HashMap;
 
import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.Tracker;
 
import de.nitri.cavefizzer.R;
 
import android.app.Application;
 
public class MyApplication extends Application {
 
	private static final String PROPERTY_ID = "UA-00000000-00";
 
	/**
	 * Enum used to identify the tracker that needs to be used for tracking.
	 * 
	 * A single tracker is usually enough for most purposes. In case you do need
	 * multiple trackers, storing them all in Application object helps ensure
	 * that they are created only once per application instance.
	 */
	public enum TrackerName {
		APP_TRACKER, // Tracker used only in this app.
		GLOBAL_TRACKER, // Tracker used by all the apps from a company. eg:
						// roll-up tracking.
		ECOMMERCE_TRACKER, // Tracker used by all ecommerce transactions from a
							// company.
	}
 
	HashMap<TrackerName, Tracker> mTrackers = new HashMap<TrackerName, Tracker>();
 
	synchronized Tracker getTracker(TrackerName trackerId) {
		if (!mTrackers.containsKey(trackerId)) {
 
			GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
 
			Tracker t = (trackerId == TrackerName.APP_TRACKER) ? analytics
					.newTracker(R.xml.app_tracker)
					: (trackerId == TrackerName.GLOBAL_TRACKER) ? analytics
							.newTracker(R.xml.global_tracker) : analytics
							.newTracker(R.xml.ecommerce_tracker);
			mTrackers.put(trackerId, t);
		}
		return mTrackers.get(trackerId);
	}
 
}

Now we can retrieve a MyApplication instance and get a tracker in onCreate():

myApplication = (MyApplication) getApplication();
tracker = myApplication.getTracker(TrackerName.APP_TRACKER);
globalTracker = myApplication.getTracker(TrackerName.GLOBAL_TRACKER);

Furthermore, we have to start and stop reporting activity:

	@Override
	public void onStart() {
		super.onStart();
		GoogleAnalytics.getInstance(this).reportActivityStart(this);
		// ...
	}
 
	@Override
	public void onStop() {
		super.onStop();
		// ...
		GoogleAnalytics.getInstance(this).reportActivityStop(this);
	}

Send screen names

Create an ActionResolver Interface in your core project.

ActionResolver.java:

package de.nitri.cavefizzer;
 
public interface ActionResolver {
	// ...
	public void setTrackerScreenName(String path);
 
}

Have the AndroidLauncher implement it:

public class AndroidLauncher extends AndroidApplication implements
		GameHelperListener, ActionResolver {
 
	// ...
 
	@Override
	public void setTrackerScreenName(String path) {
		// Set screen name.
		// Where path is a String representing the screen name.
		globalTracker.setScreenName(path);
		globalTracker.send(new HitBuilders.AppViewBuilder().build());
	}
}

The ActionResolver is passed to the main constructor in the core project:

initialize(new CaveFizzer(this), config);

Or if the game has a separate View:

View gameView = initializeForView(new CaveFizzer(this), config);
public CaveFizzer(ActionResolver actionResolver) {
	this.actionResolver = actionResolver;
}

You may want to create a dummy resolver in your desktop project:
ActionResolverDesktop.java:

package de.nitri.cavefizzer.desktop;
 
import de.nitri.cavefizzer.ActionResolver;
 
public class ActionResolverDesktop implements ActionResolver {	
 
	// ...
 
	@Override
	public void setTrackerScreenName(String path) {		
	}
}

Finally we can send the screen names from our core application:

actionResolver.setTrackerScreenName("de.nitri.cavefizzer.Intro");
actionResolver.setTrackerScreenName("de.nitri.cavefizzer.GameOver");

Run your Android app and check the logcat to see what actually happens:

./adb logcat | grep GAV4

4 thoughts on “Google Analytics SDK v4 with libGDX

  1. Hi there, where do we implement the following code?

    myApplication = (MyApplication) getApplication();
    tracker = myApplication.getTracker(TrackerName.APP_TRACKER);
    globalTracker = myApplication.getTracker(TrackerName.GLOBAL_TRACKER);

    I used it in the onCreate of my Android Launcher, however I receive an error saying cannot cast Android Application to MyApplication

    1. onCreate should be fine. Please add this attribute to the application tag in AndroidManifest.xml (with your android package name):

      android:name=”my.package.android.MyApplication”

      If you haven’t changed the package name in the manifest tag (e.g. from my.package.android to my.package) this will do:

      android:name=”.MyApplication”

  2. Thanks for your article! Are you sharing the source code of CaveFizzer or at least the part correlated with Google Analytics (including files the resources are referring to like: de.nitri.caveFizzer.android.AndroidLauncher)?

Leave a Reply