Table of Contents
Overview
Use Blue Triangle's Native App Real User Monitoring Module to collect end user experience data for measuring application speed, responsiveness, errors conditions, and network calls.
All package information is available on the Public GitHub repository page available here.
Releases are available both on GitHub as well as on Jitpack.
Installation
Add the Maven repository to the project's build.gradle
file:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Add the package dependency to your application's build.gradle
file:
dependencies {
...
implementation 'com.github.blue-triangle-tech:btt-android-sdk:2.8.0'
}
Using the Analytics Library
Initializing the Tracker
The Tracker
is a singleton instance that is responsible for sending timers to Blue Triangle. Before any timers can be tracked, the Tracker
needs to be initialized.
The best place to do this in the Android Application
. In the Application
, the tracker can be initialized via the init
static methods.
If a site ID is not set during the initialization, it will attempt to look up the site ID via the application's meta data (as well as fallback to the deprecated String resource lookup). If a tracker URL is not provided, the default tracker URL will be used.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<meta-data android:name="com.blue-triangle.site-id" android:value="SITE_ID_HERE" />
</application>
</manifest>
// init with all defaults, use site ID from meta data
Tracker.init(getApplicationContext());
// init with given site ID
Tracker.init(getApplicationContext(), "BTT_SITE_ID");
// init with given site ID and tracker URL
Tracker.init(getApplicationContext(), "BTT_SITE_ID", "https://webhook.site/5afd62e7-acde-4cf3-825c-c40c491b0714");
Configuration
The tracker's configuration can be updated via BlueTriangleConfiguration
object returned by tracker.getConfiguration()
after the tracker is initialized.
The tracker's configuration can also be set using metadata tags in the application's AndroidManifest.xml
file.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<meta-data android:name="com.blue-triangle.site-id" android:value="SITE_ID_HERE" />
<meta-data android:name="com.blue-triangle.debug" android:value="true" />
<meta-data android:name="com.blue-triangle.debug.level" android:value="2" />
<meta-data android:name="com.blue-triangle.performance-monitor.enable" android:value="true" />
<meta-data android:name="com.blue-triangle.track-crashes.enable" android:value="true" />
<meta-data android:name="com.blue-triangle.sample-rate.network" android:value="1.0" />
</application>
</manifest>
The current available meta data configuration names:
com.blue-triangle.site-id
configures the tracker's site ID.com.blue-triangle.debug
enables or disables debug logging.com.blue-triangle.debug.level
allows setting the debug logging level using the int value for Android's log levels.com.blue-triangle.cache.max-items
sets the max number of timers and crashes to cache and retry in the event the timers cannot be sent to the server. Set this to 0 to disable this feature.com.blue-triangle.cache.max-retry-attempts
sets the max number of times a timer can be re-tried.com.blue-triangle.performance-monitor.enable
enables or disables tracking of memory and CPU usage.com.blue-triangle.performance-monitor.interval-ms
adjusts the interval in milliseconds of how often memory and CPU measurements are taken.com.blue-triangle.track-crashes.enable
enable or disable collecting and sending crash reports to the server.com.blue-triangle.sample-rate.network
percentage of sessions for which network calls will be captured. A value of 0.05 means that 5% of session's network requests will be tracked. A value of 0.0 means that no network requests will be captured for the session, a value of 1.0 will track all network requests for a session.com.blue-triangle.screen-tracking.enable
set to true to enable the automatic capture of screen load times using the automated screen tracking feature.
Manual Timers
Timers are simple data objects that contain the associated times, fields related to the timer instance, and methods to start, mark interactive, and end a timer. Fields associated with the timer such as page name, traffic segment, brand value, etc. can be set on the timer via convenience constructors and methods. Associated fields can be set anytime during the lifetime of the timer until submitted to the Tracker.
// create and start a timer
final Timer timer = newTimer("Page Name", "Traffic Segment Name").start();
// do work
// optionally, mark the timer as interactive
timer.interactive();
// maybe set a field
timer.setCartValue(99.99);
// do some more work
// end the timer and submit
timer.end().submit();
// or end the timer, set fields such as brand value, and finally submit the timer
timer.end();
timer.setBrandValue(99.99);
timer.submit();
Timers implement Parcelable
to allow timers to be passed via Bundle
such as between activities in an Intent
.
// MainActivity.java
final Timer timer = newTimer("Next Page", "Android Traffic").start();
final Intent intent = newIntent(this, NextActivity.class);
intent.putExtra(Timer.EXTRA_TIMER, timer);
startActivity(intent);
// NextActivity.java
final Timer timer = getIntent().getParcelableExtra(Timer.EXTRA_TIMER);
timer.end().submit();
When a timer is submitted to the tracker, the tracker sets any global fields such as site ID, session ID, and user ID. Additional global fields may be set as needed and applied to all timers. The timer's fields are then converted to JSON and sent via HTTP POST to the configured tracker URL.
Automatic Screen Tracking
Screen Tracking is a feature that allows you to capture the performance timings of screens in your application. This feature allows for an automatic instrumentation of the SDK into your application, and will capture the load time for each screen. This information is useful for performance analysis and optimizing the user experience.
To enable Screen Tracking in your Android app, a setting can be enabled programmatically in the SDK configuration, or with a setting in the Android Manifest file.
Initializing Screen Tracking
Create an Application class and initialize the Tracker with BlueTriangleConfiguration
object with the isScreenTrackingEnabled
property set to true.
Kotlin
class MyApplication : Application() { override fun onCreate() { super.onCreate() val configuration = BlueTriangleConfiguration() configuration.isScreenTrackingEnabled = true; Tracker.init(this, configuration) } }
Java
class MyApplication extends Application { @Override public void onCreate() { BlueTriangleConfiguration configuration = new BlueTriangleConfiguration(); configuration.setScreenTrackingEnabled(true); Tracker.init(this, configuration); } }
Alternatively, you can enable Screen Tracking by adding a metadata tag to your AndroidManifest.xml file:
-
Open your AndroidManifest.xml file.
-
Add the following metadata tag under the application element:
<application ...> <meta-data android:name="com.blue-triangle.screen-tracking.enable" android:value="true" /> ... </application>
This metadata tag with a value of true
enables the Screen Tracking feature for your app.
Tracking Activities and Fragments
Screen Tracking automatically tracks activities and fragments by calculating the time between the onCreate
and onStart
callbacks for loading time and the duration between onResume
and onPause
callbacks for view time. The starting time of the timer depends on whether the activity or fragment has been cached from a previous load, in which case the timer will begin from the onStart
to the onResume
No additional steps are required for tracking these components.
Tracking Composables
Jetpack Compose, the modern UI toolkit for building Android applications, introduced a new approach to managing lifecycles compared to the traditional Activity and Fragment lifecycle model.
In the traditional Android framework, Activities and Fragments have a well-defined lifecycle with specific callback methods that allow developers to track and manage the lifecycle state transitions. This model provides global lifecycle tracking, where the framework invokes lifecycle callbacks on the corresponding components.
While Compose does provide lifecycle-related APIs, such as LaunchedEffect and DisposableEffect, they are scoped to the specific composable and are not globally trackable like the Activity and Fragment lifecycles. Composables can have their own internal state and lifecycle logic, but they are not part of a global lifecycle system.
This shift in lifecycle management makes it impossible to globally track each composable's lifecycle. Moreover, it's not possible to know which composable is supposed to represent a screen and not merely a UI component.
To track composables, in each composable that represents a screen, add the BttTimerEffect side effect. This effect measures the load time and view time of the composable.
@Composable fun LoginScreen() { BttTimerEffect("LoginScreen") // Pass the screen name as a parameter val username = remember { mutableStateOf("") } val password = remember { mutableStateOf("") } Column( modifier = Modifier .fillMaxSize() .padding(horizontal = 32.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Title(text = "Login") UsernameInputField(username = username.value, onUsernameChange = { username.value = it }) PasswordInputField(password = password.value, onPasswordChange = { password.value = it }) LoginButton(onClick = { /* Handle login button click */ }) ForgotPasswordButton(onClick = { /* Handle forgot password button click */ }) } }
Pass a unique screen name as a parameter to the BttTimerEffect side effect. This name identifies the specific composable as a screen for tracking purposes.
Limitations
Screen tracking won't work in Android Dialogs as these components have different lifecycles and behavior compared to activities, fragments, and composables. However, you can manually start and stop timers to calculate timings for dialogs. Here's an example:
Kotlin
class MyDialog : Dialog(context) { private var timer: Timer? = null override fun show() { timer = Timer("Dialog Screen") timer?.start() super.show() } override fun dismiss() { timer?.end()?.submit() super.dismiss() } }
Java
class MyDialog extends Dialog { private Timer timer = null Dialog(Context context) { super(context); } @Override public void show() { timer = new Timer("Dialog Screen") timer.start() super.show() } @Override public void dismiss() { timer.end().submit() super.dismiss() } }
Network Capture
The tracker now also supports capturing network requests. This can be done automatically using OkHttp Interceptors or manually. Check the application's AndroidManifest.xml file for the metadata configuration 'com.blue-triangle.sample-rate.network'
The recommended setting is 1.0 to capture all network requests.
OkHttp Support
OkHttp support is provided in an additional library that can be included via the following dependency:
dependencies {
...
implementation 'com.github.blue-triangle-tech:btt-android-sdk:2.7.3'
implementation 'com.github.blue-triangle-tech:btt-android-sdk-okhttp:2.7.3'
}
Once included, theBlueTriangleOkHttpInterceptor
becomes available to add as an interceptor to the OkHttp client.
val okHttpClient =OkHttpClient.Builder()
.addInterceptor(BlueTriangleOkHttpInterceptor(Tracker.instance!!.configuration))
.build()
The BlueTriangleOkHttpInterceptor
will automatically handle capturing network requests and submitting them to the tracker.
Manual Network Capture
For other network capture requirements, captured requests can be manually created and submitted to the tracker.
// create a captured request objectval capturedRequest =CapturedRequest()
// set the URL which also sets the host, domain, and file parameters that could be set otherwise
capturedRequest.url ="https://bluetriangle.com/platform/business-analytics/"
// start timing the request
capturedRequest.start()
// make the network request// end timing the request
capturedRequest.stop()
// (Optional) set encoded body size based on response content length header
capturedRequest.encodedBodySize =12341
// (Optional) set based on response content type
capturedRequest.requestType =RequestType.html
// submit the captured request to the tracker
instanceTracker.instance?.submitCapturedRequest(capturedRequest)
Caching
To support offline usage tracking, timer and crash reports that cannot be sent immediately will be cached in the application's cache directory and retried when a successful submission of a timer occurs.
The max number of timer and crashes to cache can be configured and this feature can be completely disabled by setting the max cache items configuration to 0. The default is 100.
If the cache becomes full, the cache will be rotated to remove the oldest item and insert the newest item.
Also the max number of retry attempts can be configured per timer/crash report as well. If the max number of retries is exceeded, the timer/crash is dropped. The default is 3 tries.
Comments
0 comments
Please sign in to leave a comment.