Android (0.5.0)
Tracker
1. Overview
The Snowplow Android Tracker allows you to track Snowplow events from your Android applications and games. It supports applications using the Android SDK 11 and above.
The tracker should be straightforward to use if you are comfortable with Java development; its API is modelled after Snowplow's Python Tracker so any prior experience with that tracker is helpful but not necessary. If you haven't already, have a look at the Android Tracker Setup guide before continuing.
NOTE: The Tracker should only ever be setup as a singleton object. Due to the way it stores and reads information and the creation of persistent background services, creating more than one Tracker can cause a plethora of race conditions.
- Double (or more) sending of events.
- Constant session expiration (as old Tracker services continually fail to see any new events being created).
1.1. Demo App
If you would like to see the Tracker in action you can download our demonstration android app here. You will need to enable installation of applications from unknown sources.
Within the app you will simply need to supply an endpoint and hit start! The application will then send all types of events available to the tracker to this endpoint.
For a walkthrough go here.
1.2. Client Sessions
To activate client sessionization please enter the following builder arguments to your tracker:
Tracker tracker = new Tracker.TrackerBuilder( ... )
.sessionContext(true) // To use the session context
.sessionCheckInterval(10) // Checks every 10 seconds (default is 15)
.foregroundTimeout(300) // Timeout after 5 minutes (default is 10)
.backgroundTimeout(120) // Timeout after 2 minutes (default is 5)
.build();
Once sessionization has been turned on several things will begin to happen:
- A client_session context will be appended to each event that is sent
- A polling check will be started to check whether or not the session has timed out
- You can configure how often to check with the sessionCheckInterval method
- If your app is in the foreground and no events have been sent for the foregroundTimeout period, the session will be updated and a new session started
- There is a separate timeout if your application is detected to be in the background
- Each time the session information is updated it is stored locally in a private file which should persist for the life of the application
- Each time an event is sent from the Tracker, both timeouts for the session are reset
- Session information will survive for the life of the application, i.e. until it is uninstalled from the Android device.
An important note here is that the tracker does not automatically detect if the application is in the background or not from a library standpoint. You will have to update your applications onPause() and onResume() functions to manually flag this change. The following samples can be copied into an application activity to set the background state of the application for the session checker:
@Override
protected void onPause() {
super.onPause();
tracker.getSession().setIsBackground(true);
}
@Override
protected void onResume() {
super.onResume();
tracker.getSession().setIsBackground(false);
}
2 Initialization
Assuming you have completed the Android Tracker Setup for your project, you are now ready to initialize the Android Tracker.
2.1 Importing the module
Import the Android Tracker's classes into your Android code like so:
import com.snowplowanalytics.snowplow.tracker.*;
That's it - you are now ready to initialize a Tracker instance.
2.2 Creating a Tracker
To instantiate a tracker in your code (can be global or local to the process being tracked) simply instantiate the Tracker interface with one of the following:
// Create an Emitter
Emitter e1 = new Emitter
.EmitterBuilder("com.collector.acme", getContext())
.build();
// Make and return the Tracker object
Tracker t1 = new Tracker
.TrackerBuilder(e1, "myNamespace", "myAppId", getContext())
.build();
This is the most basic Tracker creation possible. Note that getContext() is an Android global function. You can expand on this creation with the following builder options:
// Create an Emitter
Emitter e2 = new Emitter
.EmitterBuilder("com.collector.acme", getContext())
.build();
// Create a Tracker with all options
Tracker t2 = new Tracker
.TrackerBuilder(e2, "myNamespace", "myAppId", getContext())
.base64(false) // Optional - defines if we use base64 encoding
.platform(DevicePlatforms.Mobile) // Optional - defines what platform the event will report to be on
.subject(new Subject.SubjectBuilder().build()) // Optional - a subject which contains values appended to every event
.build();
As you can see there is a fair amount of modularity to the Trackers creation.
The below are required arguments for the TrackerBuilder({{ ... }}) segment of the constructor:
| Argument Name | Description | Required? |
|---|---|---|
emitter | The emitter which sends the events | Yes |
namespace | The name of the tracker instance | Yes |
appId | The application ID | Yes |
context | The application context | Yes |
We also have several extra builder options:
| Function | Description | Options | Default |
|---|---|---|---|
subject | The subject that defines a user | Subject, null | null |
platform | The platform that the Tracker is running on | DevicePlatforms.{{ Enum Option }} | DevicePlatforms.Mobile |
base64 | Whether to enable Base64 encoding | True, False | True |
level | The level of logging to do | LogLevel.{{ Enum Option }} | LogLevel.OFF |
sessionContext | Whether to enable sessionization | True, False | False |
foregroundTimeout | The session foreground timeout | Any valid Long | 600 |
backgroundTimeout | The session background timeout | Any valid Long | 300 |
sessionCheckInterval | The session check interval | Any valid Long | 15 |
threadCount | The amount of threads to use | Any valid Integer | 10 threads |
timeUnit | The TimeUnit that time measurements are in | TimeUnit.{{ Enum Option }} | TimeUnit.SECONDS |
2.2.1 Constructor Options Explained
Required
emitter: The pre created Emitter object which is required for all sending and storing of events by the Tracker. See Emitters for information.namespace: The name of this Tracker instance to include with events sent to the collector.appId: The ID of this application to include with events sent to the collector.context: The Android Application context object.
Event Decoration
subject: An optional Subject object which will add extra decoration to events sent from the Tracker.platform: The platform that the Tracker is running on (defaults toMOBILE)base64: Whether to encodeunstructuredevents andcustom contextsin base64 formatting.
Session Parameters
sessionContext: Needs to be set toTrueif you wish to activate any of the Trackers Sessionization functionality.foregroundTimeout: The amount of time that needs to elapse without any events being tracked before the session is incremented (while application is in the foreground).backgroundTimeout: The amount of time that needs to elapse without any events being tracked before the session is incremented (while application is in the background).sessionCheckInterval: How often the Tracker queries the session object to see if it needs to be incremented. It is currently set to 15 seconds.timeUnit: The unit of time that the previous three options are computed on. By default it is inSECONDS, as such to set asessionCheckIntervalof 2 minutes you would need to put in120for that option. Or you could change thetimeUnitto beMINUTESand put a2instead.
Functional Settings
threadCount: The amount of threads that the Tracker will have available to it to process information in. By default we use 10 Threads, however it is recommended to figure out the optimal amount of Threads on a device by device basis as more Threads will have a direct correlation with performance.level: The amount of logging done by the Tracker.
2.3 Tracker Functions
2.3.1 getEmitter
Returns the emitter to which the tracker will send events. See Emitters for more on emitter configuration.
2.3.2 getSubject
Returns the user which the Tracker will track. This must be an instance of the Subject class. You don't need to set this during Tracker construction; you can use the Tracker.setSubject method afterwards. In fact, you don't need to create a subject at all. If you don't, though, your events won't contain user-specific data such as timezone and language.
2.3.3 getNamespace
Returns the namespace argument attached to every event fired by the new tracker. This allows you to later identify which tracker fired which event if you have multiple trackers running.
2.3.4 getAppId
Returns the appId argument that you passed in Tracker construction.
2.3.5 getBase64Encoded
By default, unstructured events and custom contexts are encoded into Base64 to ensure that no data is lost or corrupted. You can turn encoding on or off using the Boolean base64Encoded builder option.
2.3.6 getPlatform
Returns the 'platform' that was set in Tracker construction, the builder allows you to pick from a list of allowed platforms which define what type of device/service the event is being sent from.
2.3.7 getSession
Returns the session object created for the Tracker (if sessionContext was enabled).
2.3.8 getDataCollection
Returns the state of data collection in the Tracker; either True or False.
2.3.9 getLogLevel
Returns the LogLevel being used by the Tracker.
2.3.10 getThreadCount
Returns the amount of threads that the tracker is consuming.
2.3.11 getTrackerVersion
Returns this Trackers version as a String.
2.3.12 Change the tracker's platform with setPlatform
You can change the platform by calling:
tracker.setPlatform(DevicePlatforms.Mobile);
// OR
tracker.setPlatform(DevicePlatforms.Desktop);
// OR
tracker.setPlatform(DevicePlatforms.{{ Valid Enum Option }})
There are several different DevicePlatforms options to choose from.
For a full list of supported platforms, please see the Snowplow Tracker Protocol.
2.3.13 Change the tracker's subject with setSubject
You can change the subject by creating a new Subject object and then calling:
tracker.setSubject(newSubject);
See Adding extra data: the Subject class for more information on the Subject.
2.3.14 Change the tracker's emitter with setEmitter
You can change the emitter by creating a new Emitter object and then calling:
tracker.setEmitter(newEmitter);
2.4 Extra Tracker Functions
These are extra functions for controlling the Tracker. The Tracker is designed to be run without ever using any of these functions however they are there for any special use cases where you need to shutdown or otherwise control the Tracker.
For example if you wish to artificially extend the time a session is active you can simply pauseSessionChecking for an undetermined amount of time. To resume automatic session checking and updating simply run resumeSessionChecking.
2.4.1 resumeSessionChecking
This function resumes a polling session checker service. This will query the Trackers session object at pre-configured intervals to see whether or not the session needs to be updated if it has not been accessed within a certain amount of time.
This function is started if the argument to .sessionContext is True, and will only ever be able to run if this argument is True.
tracker.resumeSessionChecking();
2.4.2 pauseSessionChecking
This functions stops the session checker from running. Essentially preventing the current session from ever timing out. Please note that if the application is restarted this paused state will not persist and checking will begin again.
tracker.pauseSessionChecking();
2.4.3 resumeEventTracking
If event tracking has been switched off this will reinstate the Tracker back to full operation. This means that:
- Events will start being stored in the database again.
- Events will be sent to the collector.
- Session checking will begin to occur again (if enabled)
tracker.resumeEventTracking();
2.4.4 pauseEventTracking
If event tracking is switched on (it is by default), then the Tracker will have all event tracking paused. What this means is that:
- No events will be stored in the database or tracked at all.
- No events will be sent to the collector.
- No session checks will occur.
Essentially the entire Tracker will halt operation until event tracking is turned back on.
tracker.pauseEventTracking();
3. Adding extra data: the Subject class
You may have additional information about your application's environment, current user and so on, which you want to send to Snowplow with each event. The Subject appended to the Tracker allows you to easily add information to each event that is sent from the Tracker.
3.1 Subject setter functions
The Subject class has a set of set...() methods to attach extra data relating to the user to all tracked events:
setUserIdsetScreenResolutionsetViewportsetColorDepthsetTimezonesetLanguagesetIpAddresssetUseragentsetNetworkUserIdsetDomainUserIdsetAdvertisingIDsetCarriersetLocationsetDefaultScreenResolution
Here are some examples:
Subject s1 = new Subject.SubjectBuilder().build();
s1.setUserID("Kevin Gleason");
s1.setLanguage("en-gb");
s1.setScreenResolution(1920, 1080);
After that, you can add your Subject to your Tracker like so:
Tracker t1 = new Tracker
.TrackerBuilder(emitter, "myNamespace", "myAppId")
.subject(s1) // Include your subject here!
.build();
// Or you can set the subject after creation
// This will also override any currently set Subject object
t1.setSubject(s1);
To update the Trackers subject without changing the subject attached already you can use the following:
t1.getSubject().setUserId("Gleason Kevin"); // Because object references are passed by value in Java
3.1.1 Set user ID with setUserId
You can set the user ID to any string:
setUserId(String userId)
Example:
subj.setUserId("alexd");
3.1.2 Set screen resolution with setScreenResolution
If your Java code has access to the device's screen resolution, then you can pass this in to Snowplow too:
setScreenResolution(int width, int height)
Both numbers should be positive integers; note the order is width followed by height. Example:
subj.setScreenResolution(1366, 768);
3.1.3 Set viewport dimensions with setViewport
If your Java code has access to the viewport dimensions, then you can pass this in to Snowplow too:
setViewport(int width, int height)
Both numbers should be positive integers; note the order is width followed by height. Example:
subj.setViewport(300, 200);
3.1.4 Set color depth with setColorDepth
If your Java code has access to the bit depth of the device's color palette for displaying images, then you can pass this in to Snowplow too:
setColorDepth(int depth)
The number should be a positive integer, measured in bits per pixel. Example:
subj.setColorDepth(32);
3.1.5 Set timezone with setTimezone
This method lets you pass a user's timezone in to Snowplow:
setTimezone(String timezone)
The timezone should be a string:
subj.setTimezone("Europe/London");
3.1.6 Set the language with setLanguage
This method lets you pass a user's language in to Snowplow:
setLanguage(String language)
The language should be a string:
subj.setLanguage("en");
3.1.7 setIpAddress
This method lets you pass a user's IP Address in to Snowplow:
setIpAddress(String ipAddress)
The IP address should be a string:
subj.setIpAddress("127.0.0.1");
3.1.8 setUseragent
This method lets you pass a useragent in to Snowplow:
setUseragent(String useragent)
The useragent should be a string:
subj.setUseragent("Agent Smith");
3.1.9 setNetworkUserId
This method lets you pass a Network User ID in to Snowplow:
setNetworkUserId(String networkUserId)
The network user id should be a string:
subj.setNetworkUserId("network-id");
3.1.10 setDomainUserId
This method lets you pass a Domain User ID in to Snowplow:
setDomainUserId(String domainUserId)
The domain user id should be a string:
subj.setDomainUserId("domain-id");
3.1.11 setAdvertisingID
This method lets you set the Advertising ID
setAdvertisingID(Context context)
You will need to pass in the application's context as a parameter.
subj.setAdvertisingID(context);
3.1.12 setCarrier
This method lets you set the mobile carrier.
setCarrier(Context context)
You will need to pass in the application's context as a parameter.
subj.setCarrier(context);
3.1.13 setLocation
This method lets you set the mobile location.
setLocation(Context context)
You will need to pass in the application's context as a parameter.
subj.setLocation(context);
3.1.14 setDefaultScreenResolution
This method lets you set the default screen resolution using the application context.
setDefaultScreenResolution(Context context)
You will need to pass in the application's context as a parameter.
subj.setDefaultScreenResolution(context);