Android SDK
Deprecation Notice
This is a deprecation notice for our mobile SDKs email identification functionality. Identifying users using their user email will no longer be supported as a valid identifier for the Android and iOS SDKs.
Users currently identified by their email will not be affected. However, we recommend identifying all users with a unique user ID. Please note that users will still be associated with their email, which can be used for filtering and audience segmentation.
You can get started with using Taplytics on Android in minutes. Just follow the steps below:
Installation
Android Studio
- In your moduleβs build.gradle, add the url to the SDK.
NOTE: In newer applications, this must also be added to your project's settings.gradle
repositories {
maven { url "https://github.com/taplytics/Taplytics-Android-SDK/raw/master/AndroidStudio/" }
}
repositories {
maven { url "https://github.com/taplytics/Taplytics-Android-SDK/raw/master/AndroidStudio/" }
}
- In your moduleβs build.gradle dependencies (not your project's build.gradle), compile Taplytics and its dependencies.
Note: users that are planning to use the mParticle and Taplytics integration should use RetroFit2 instead of Volley.
dependencies {
//Dependencies for Taplytics
implementation 'com.taplytics.sdk:taplytics:+@aar'
//socket.io connections only made on debug devices.
//To make live changes on a release build, remove the debugImplementation flag
debugImplementation ('io.socket:socket.io-client:1.0.1') {
exclude group: 'org.json', module: 'json'
}
//NOTE: You can use either Volley or Retrofit2. Do not use both if you do not have to.
//Volley
implementation 'com.android.volley:volley:+'
//Retrofit2
implementation 'com.squareup.retrofit2:retrofit:+'
}
dependencies {
//Dependencies for Taplytics
implementation 'com.taplytics.sdk:taplytics:+@aar'
//socket.io connections only made on debug devices.
//To make live changes on a release build, remove the debugImplementation flag
debugImplementation ('io.socket:socket.io-client:1.0.1') {
exclude group: 'org.json', module: 'json'
}
//NOTE: You can use either Volley or Retrofit2. Do not use both if you do not have to.
//Volley
implementation 'com.android.volley:volley:+'
//Retrofit2
implementation 'com.squareup.retrofit2:retrofit:+'
}
Import Taplytics as an AAR
If you'd like to manually add Taplytics to your build, you may download the .aar
file and add it to your Android project.
Find the latest Android SDK here: https://github.com/taplytics/Taplytics-Android-SDK/tree/master/AndroidStudio/com/taplytics/sdk/taplytics
Import the .aar
file to Android Studio and add or ensure the following dependencies are included in your app's build.gradle
file.
dependencies {
//Dependencies for Taplytics
implementation files('libs/taplytics-3.0.0.aar') // replace 3.0.0 with your version
//socket.io connections only made on debug devices.
//To make live changes on a release build, remove the debugImplementation flag
debugImplementation ('io.socket:socket.io-client:1.0.1') {
exclude group: 'org.json', module: 'json'
}
//NOTE: You can use either Volley or Retrofit2. Do not use both if you do not have to.
//Volley
implementation 'com.android.volley:volley:+'
//Retrofit2
implementation 'com.squareup.retrofit2:retrofit:+'
}
Click here to read more about the recent socket dependency changes.
- Override your Applicationβs onCreate() method (not your main activity) and call Taplytics.startTaplytics(). If you don't have an Application class, create one. It should look like this:
import com.taplytics.sdk.Taplytics;
public class ExampleApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Taplytics.startTaplytics(this, "YOUR TAPLYTICS SDK KEY");
}
}
import com.taplytics.sdk.Taplytics
class ExampleApplication : Application() {
override fun onCreate() {
super.onCreate()
Taplytics.startTaplytics(this, "YOUR TAPLYTICS SDK KEY")
}
}
- Now, add the proper permissions, and the Application class to your appβs AndroidManifest.xml in the Application tag.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".ExampleApplication"
...
- To be able to connect to Taplytics on a release build, add the following intent-filter tag to the end of your MAIN activity:
First, get your Taplytics URL Scheme from your Project's Settings:
Then, add it to your manifest in its own intent filter (do not merge with another intent filter).
...
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="YOUR URL SCHEME"/>
</intent-filter>
</activity>
Install with Segment
The Taplytics SDK can also be installed via Segment. You can find install instructions here.
Install with mParticle
Check the Taplytics integration for the mParticle Android SDK docs here.
Initialization
Initialize the Taplytics SDK by adding the following line of code with your SDK key to your Main Application class. Taplytics can also be started with a few options to help you use it during development. See the start options section for more details.
First, the base method:
Taplytics.startTaplytics(this, "Your SDK Key");
Taplytics.startTaplytics(this, "Your SDK Key");
Or, add a map of options.
HashMap<String, Object> options = new HashMap<>();
options.put("optionName", optionValue);
Taplytics.startTaplytics(this, "Your SDK Key", options);
val options: HashMap<String, Any> = HashMap()
options["optionName"] = optionValue
Taplytics.startTaplytics(this, "Your SDK Key", options)
Important Notes
It is highly recommended to initialize Taplytics in the Applicationβs onCreate()
for several reasons.
- Taplytics uses the information on how your app was launched to support some of our core features. ie. View construction/data for the Visual Editor
- Taplytics should also be started as early as possible to allow time for Taplytics to fetch our config and present the correct experiment and feature data before the first activity starts.
- Taplytics uses the application start as a signal for when the App has been activated. We use this data to accurately track sessions and activity.
Threading
Taplytics will create its own threadpool and operate off the main thread except when making visual modifications as this must occur on the UI thread.
Caching & SDK Timeouts
Built into each Taplytics client-side SDK is a caching system that saves experiment and feature flag values locally on each session. These values are saved locally for several reasons, but the two primary ones are:
- To keep the user experience consistent when Taplyticsβ servers are unreachable for any reason
- To minimize outbound requests to Taplytics, allowing configuration data to be used throughout a session if successfully loaded and saved
The Taplytics SDK also enables you to configure the request timeout, which specifies the time within which the Taplytics SDK must return a response. By default, the timeout value is set to 4000ms on all client-side SDKs. If the default timeout value is not appropriate for your application, you can adjust the timeout for your specific requirements within the starting parameters.
If a response isnβt returned within the time specified, the request ends. The Taplytics SDK will either return the last cached value saved within your device, or if there was no previously cached value, the SDK will use variable default values.
Whichever is used, cached values or defaults, the SDK will use those values for the remainder of the session. Updated values from our SDK will still attempt to download on timeouts in the background and will be cached and ready to use on the next session if any retry is successful.
Example:
HashMap<String, Object> options = new HashMap<>();
options.put("optionName", optionValue);
Taplytics.startTaplytics(Context, "SDK_KEY", options, TimeoutInMillis)
val options: HashMap<String, Any> = HashMap()
options["optionName"] = optionValue
Taplytics.startTaplytics(Context, "SDK_KEY", options, TimeoutInMillis)
Start Options
Customize the startup process and enable extra features that the Taplytics Android SDK provides.
Option Name | Values | Default | Explanation |
---|---|---|---|
liveUpdate | boolean: true/false | set by build (enabled in debug) | Disable live update to remove the border, and activity refreshing in your debug builds to test the functionality of your applications as if they were in release mode. Note that this functionality is always disabled by default in release builds. Setting liveUpdate to true on a release build will override this and force the application into debug mode. |
shakeMenu | boolean: true/false | set by build (enabled in debug) | In your debug builds, disable the quick menu that appears when you shake your device. This menu is never present in release builds. |
aggressive | boolean | false | Taplytics has the option to allow for aggressive visual changes. This means that if text or visibility is changed within your app by code outside of Taplytics, Taplytics will force the values to remain what has been set on the dashboard. |
sessionMinutes | int > 0 | 10 | If you do your own analytics alongside Taplytics, it helps to define your sessions to be the same length to reconcile your data. Set this to be the same timing interval that your app counts sessions. |
turnMenu | boolean: true/false | false | If you are doing visual testing on an emulator, or UI automation, many emulators do not have the ability to shake the device. So, to pop up the Taplytics menu on such devices, set turnMenu to true, and simply rotate the device from portrait/landscape twice in a row within 30 seconds and this menu will show. |
disableBorders | boolean: true/false | set by build (enabled in debug) | This will entirely disable the informational borders Taplytics applies during debug mode testing. Useful to disable for UI testing. Note that this border will NOT show in release mode regardless of setting (except for on previously paired phones). |
testExperiments | HashMap | null | See Testing Specific Experiments. |
retrofit | boolean: true/false | set by build (true if only retrofit present) | Taplytics will default to using Volley if it is present. In the event that you have both enabled, you can use this flag to force the library to use retrofit instead. |
trackingId | string | null | To separate all users devices, Taplytics will use device identifiers by default as an identification tool. However, clients are able to provide their own tracking IDs to Taplytics for user devices, such as google advertising IDs. If this option is used, Taplytics will not collect any device identifiers. |
logging | boolean: true/false | false | This will provide more verbose logging from Taplytics to help with debugging. |
userBucketing | boolean: true/false | false | This will turn on user based bucketing logic for your SDK, creating an anonymous user_id if one is not provided. Otherwise it will take the saved user_id from the device that was saved using setUserAttributes . For more information please view this doc first. |
Example:
HashMap<String, Object> options = new HashMap<>();
options.put("shakeMenu", false);
options.put("sessionMinutes", 30);
options.put("logging", true);
Taplytics.startTaplytics(Context, "SDK_KEY", options)
val options: HashMap<String, Any> = HashMap()
options["shakeMenu"] = false
options["sessionMinutes"] = 30
options["logging"] = true
Taplytics.startTaplytics(Context, "SDK_KEY", options)
The Border / Shake Menu
When paired to the Taplytics dashboard on a debug build or through Advanced Pairing, a border will show around your app window. This shows which experiment and variation you are currently viewing.
You can long-press on the top of the border to switch experiments, shake your device and pick from the menu, or select an experiment from the Taplytics website to view the Visual changes made to the app.
When paired to the Taplytics dashboard, the Shake Menu appears whenever you shake the device. Alternatively, you can also use the Taplytics.showMenu()
function to display the Shake Menu as well. This is useful if you're testing on environments that can't be shook or rotated.
Note: The border and shake menu will NOT normally appear on release builds.
Advanced Device Pairing
Link a device (even in release mode) to Taplytics.
NOTE: This is used only for deeplink pairing
Retrieve deeplink through Taplytics deeplink intercepted via either email or SMS device pairing. It contains your Taplytics URL scheme and device token. If you wish to intercept the deeplink and then pair the device yourself in your application's code, call this method in your app's LAUNCH activity or MAIN activity, like so:
private void handleDeepLink(Intent intent) {
String tlDeeplink = intent.getDataString(); //example deep link: 'tl-506f596f://e10651f9ef6b'
if (tlDeeplink == null) {
// No deeplink found
return;
}
Taplytics.deviceLink(tlDeeplink);
}
private fun handleDeepLink(intent:Intent) {
val tlDeeplink = intent.getDataString() //example deep link: 'tl-506f596f://e10651f9ef6b'
if (tlDeeplink == null)
{
return // No deeplink found
}
Taplytics.deviceLink(tlDeeplink)
}
Additionally, if you are using singleTop activities, you MUST handle the incoming intents in your activity like so:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// this handles the intents in the case where your main activity has already been created
handleDeepLink(intent);
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
// this handles the intents in the case where your main activity has already been created
handleDeepLink(intent)
}
Do not forget to get your Taplytics URL Scheme from your Project's Settings:
Then, add it to your manifest in its own intent filter:
...
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="YOUR URL SCHEME"/>
</intent-filter>
</activity>
NOTE: The socketIO dependency must be present in the release build (ie not set to debugImplementation
) to pair with a release build.
Setting User Attributes
It's possible to send custom user attributes to Taplytics using a JSONObject of user info.
The possible fields are:
Parameter | Type |
---|---|
String | |
user_id | String |
firstname | String |
lastname | String |
name | String |
age | Number |
gender | String |
You can also add anything else you would like to this JSONObject and it will also be passed to Taplytics.
An example with custom data:
JSONObject attributes = new JSONObject();
attributes.put("email", "[email protected]");
attributes.put("name", "John Doe");
attributes.put("age", 25);
attributes.put("gender", "male");
attributes.put("avatarUrl", "https://someurl.com/someavatar.png");
attributes.put("someCustomAttribute", 50);
attributes.put("paidSubscriber", true);
attributes.put("subscriptionPlan", "yearly");
Taplytics.setUserAttributes(attributes);
val attributes = JSONObject()
attributes.put("email", "[email protected]")
attributes.put("name", "John Doe")
attributes.put("age", 25)
attributes.put("gender", "male")
attributes.put("avatarUrl", "https://someurl.com/someavatar.png")
attributes.put("someCustomAttribute", 50)
attributes.put("paidSubscriber", true)
attributes.put("subscriptionPlan", "yearly")
Taplytics.setUserAttributes(attributes)
You can also attach a callback to notify you when user attributes has finished calling:
Taplytics.setUserAttributes(attributes, new TaplyticsSetUserAttributesListener() {
@Override
public void finishedSettingUserAttributes() {
// Finished setting user attributes
}
});
Taplytics.setUserAttributes(attributes) {
// Finished setting user attributes
}
User Attributes on First Launch
User Attributes set before startTaplytics
is called will be used for experiment segmentation on the first session of your app. Any attributes that are set after startTaplytics
is called will not be used for experiment segmentation until the next session of your app.
// These custom data values will be used for segmentation on the first session of the app.
JSONObject attributes = new JSONObject();
attributes.put("example", 1);
Taplytics.setUserAttributes(attributes);
Taplytics.startTaplytics(this, SDK_KEY)
// These custom data values will only take effect on the second session of the app.
JSONObject attributes = new JSONObject();
attributes.put("example", 0);
Taplytics.setUserAttributes(attributes);
// These custom data values will be used for segmentation on the first session of the app.
val attributes = JSONObject()
attributes.put("example", 1);
Taplytics.setUserAttributes(attributes)
Taplytics.startTaplytics(this, SDK_KEY)
// These custom data values will only take effect on the second session of the app.
val attributes = JSONObject()
attributes.put("example", 0);
Taplytics.setUserAttributes(attributes)
Retrieving Session Info
Taplytics also offers a method to retrieve select information of what you know about a session at a given time. This method returns the user's Taplytics identifier (appUser_id
) and current session id (session_id
)
Taplytics.getSessionInfo(new SessionInfoRetrievedListener() {
@Override
public void sessionInfoRetrieved(HashMap sessionInfo) {
//Use your Hashmap of Session Info
}
@Override
public void onError(HashMap sessionInfo) {
// Handle Error
}
});
Taplytics.getSessionInfo(object : SessionInfoRetrievedListener {
override fun sessionInfoRetrieved(sessionInfo: HashMap<*, *>?) {
//Use your Hashmap of Session Info
}
override fun onError(sessionInfo: HashMap<*, *>?) {
// Handle Error
}
})
Resetting User Attributes or Logging out a User
Once a user logs out of your app, their User Attributes are no longer valid. You can reset their data by calling resetAppUser
. Make sure you do not set any new user attributes until you receive the callback.
Taplytics.resetAppUser(new TaplyticsResetUserListener() {
@Override
public void finishedResettingUser() {
//Finished User Reset
}
});
Taplytics.resetAppUser {
//Finished User Reset
}
User Opt-In / Opt-Out
Using the User Opt-In / Opt-Out APIs allows you to simplify the process to get user consent for analytics tracking and experimentation. Calling optOutUserTracking
will disable all Taplytics analytics tracking and experiments, and calling optInUserTracking
will re-enable all Taplytics analytics tracking and experiments. You can retrieve the current status using: hasUserOptedOutTracking
.
// Opt In
Taplytics.optInUserTracking(this);
// Opt Out
Taplytics.optOutUserTracking(this);
// Check if user has opted out
Taplytics.hasUserOptedOutTracking(this, new TaplyticsHasUserOptedOutListener() {
@Override
public void hasUserOptedOutTracking(boolean hasOptedOut) {
// use hasOptedOut:
// true: user has opted out
// false: user has opted in
}
});
// Opt In
Taplytics.optInUserTracking(this)
// Opt Out
Taplytics.optOutUserTracking(this)
// Check if user has opted out
Taplytics.hasUserOptedOutTracking(this) { hasOptedOut ->
// use hasOptedOut:
// true: user has opted out
// false: user has opted in
}
Device Identifiers
You may notice upon submitting your App to the Play Store that a warning for Sending Device Identifiers is issued and originated from Taplytics. This is only a warning and is used to notify users that the device identifier is being used by Taplytics. No action is needed at this time and Taplytics will be phasing out the device identifier in the future.
Taplytics uses the unique device identifiers to ensure that we can track a user's device consistently on the Taplytics dashboard. Additionally, Taplytics uses this ID as the main source of bucketing a user. This is a standard use case for device identifiers as outlined [here] (https://developer.android.com/training/articles/user-data-ids#common-use-cases).
Tracking Events
Automatic Events
Some events are automatically tracked by Taplytics and will appear on your dashboard. These events are:
- App Start
- Activity and/or Fragment load
- Activity and/or Fragment destroy
- Activity pause
- App background
- IP location tracking
- Viewpager changes
App terminate is also tracked, but this is only true when your MAIN activity is at the bottom of your activity stack, and the user exits the app from that activity.
No changes are needed in your code for this event tracking to occur.
Receiving External Analytics
Taplytics has support for external events that come from many of your favourite analytics tools. To learn more about our integrations and what's available, visit our 3rd Party Integrations page.
Many of our integrations work out of the box and will automatically logs events to both Taplytics and your Analytics sources.
Custom Events
To log your own events, simply call:
Taplytics.logEvent("Your Event Name");
Taplytics.logEvent("Your Event Name")
You can also log events with numerical values:
Number num = 0;
Taplytics.logEvent("Your Event Name", num);
val num: Number = 0
Taplytics.logEvent("Your Event Name", num)
And with custom object data:
Number num = 0;
JSONObject customInfo = new JSONObject();
customInfo.put("some title", someValue)
Taplytics.logEvent("Your Event Name", num, customInfo);
val num = 0
val customInfo = JSONObject()
customInfo.put("some title", someValue)
Taplytics.logEvent("Your Event Name", num, customInfo)
Revenue Logging
It's also possible to log revenue.
Revenue logging is the same as event logging, only call logRevenue
:
Number someRevenue = 10000000;
Taplytics.logRevenue("Revenue Name", someRevenue);
val someRevenue = 10000000
Taplytics.logRevenue("Revenue Name", someRevenue)
And similarly, with custom object data:
Number someRevenue = 10000000;
JSONObject customInfo = new JSONObject();
customInfo.put("some rag", someValue)
Taplytics.logRevenue("Revenue Name", someRevenue, customInfo);
val someRevenue = 10000000
val customInfo = JSONObject()
customInfo.put("some rag", someValue)
Taplytics.logRevenue("Revenue Name", someRevenue, customInfo)
Disabling Automatic Tracking
You can disable automatic tracking for any of the options below by adding them to the disable
array and including the array into your start options.
To disable IP Location tracking, head over to the Settings page on the Taplytics dashboard and select the checkbox to disable IP tracking.
ENUM | Description |
---|---|
delayload | Option to delay the loading of your main activity while Taplytics gets initial view changes ready |
shakemenu | A debug menu, exposing some useful items like the push token retrieval and the ability to test experiments and feature flags |
events | All Event tracking |
viewtracking | View related tracking |
analytics | Analytics event tracking |
external | External Analytics event tracking |
Google Analytics event tracking | |
mixpanel | Mixpanel Analytics event tracking |
flurry | Flurry Analytics event tracking |
adobe | Adobe Analytics event tracking |
localytics | Localytics Analytics event tracking |
amplitude | Amplitude Analytics event tracking |
segment | Segment Analytics event tracking |
recyclerviews | Recyclerviews tracking for Visual Editor |
listviews | Listviews tracking for Visual Editor |
For Example:
ArrayList<String> disabledFunctionality = new ArrayList<String>()
disabledFunctionality.add("google");
disabledFunctionality.add("shakemenu");
startOptions.put("disable", disabledFunctionality);
val disabledFunctionality = listOf("google", "shakemenu")
startOptions["disable"] = disabledFunctionality)
Experiments
Creating experiments is easy using Taplytics. You can either use our visual editor or create code-based experiments. You can find documentation on how to do this below.
Visual Editing
You don't have to do anything else! Once you've installed the SDK and initialized Taplytics, you can use the Taplytics dashboard to make all your visual changes. See the docs on visual editing here.
Visual Editing Support on Android
Visual Editing for native Android apps is supported on all versions of Android other than Android X. Due to changes in how Android creates visual elements in Android X visual editing is not supported at this time.
Dynamic Variables & Code Blocks
To see and modify these variables or blocks on the dashboard, the app must be launched and this code containing the variable or block must be navigated to at least once.
The code below is used to send the information of the variable or block to Taplytics, so it will appear on the dashboard.
Dynamic Variables
Taplytics variables are values in your app that are controlled by experiments. Changing the values can update the content or functionality of your app. Variables are reusable between experiments and operate in one of two modes: synchronous or asynchronous.
Synchronous
Synchronous variables are guaranteed to have the same value for the entire session and will have that value immediately after construction.
Due to the synchronous nature of the variable, if it is used before the experiments have been loaded, its value will be the default value rather than the value set for that experiment. This could taint the results of the experiment. In order to prevent this you can ensure that the experiments are loaded before using the variable. This can be done with either the delayLoad
functionality, the TaplyticsExperimentsLoadedListener
parameter in your startTaplytics
call, or the getRunningExperimentsAndVariations
call.
Synchronous variables take two parameters in its constructor:
- Variable name (String)
- Default Value
The type of the variable is defined in the first diamond brackets, and can be a String
, Number
, Boolean
or JSON
.
For example, using a variable of type String
:
TaplyticsVar<String> stringVar = new TaplyticsVar<String>("some name", "default value");
val stringVar = TaplyticsVar("some name", "default value")
Then when you wish to get the value for the variable, simply call get()
on the Taplytics variable:
String value = stringVar.get();
val value = stringVar.get()
Asynchronous
Asynchronous variables take care of insuring that the experiments have been loaded before returning a value. This removes any danger of tainting the results of your experiment with bad data. What comes with the insurance of using the correct value is the possibility that the value will not be set immediately. If the variable is constructed before the experiments are loaded, you won't have the correct value until the experiments have finished loading. If the experiments fail to load, then you will be given the default value, as specified in the variables constructor. For the best results with asynchronous varaibles make sure that they are constructed after the StartTaplytics call in your app's lifecycle.
Asynchronous variables take three parameters in its constructor:
- Variable name (String)
- Default Value
- TaplyticsVarListener
Just as for synchronous variables the type of the variable is defined in the first diamond brackets, and can be a String
, Number
, Boolean
or JSON
.
For example, using a variable of type Number
:
TaplyticsVar<Number> codeVar = new TaplyticsVar<>("name", 5, new TaplyticsVarListener() {
@Override
public void variableUpdated(Object value) {
// Do something with the value
}
});
val codeVar: TaplyticsVar<Int> =
TaplyticsVar<Int>("name", 5, TaplyticsVarListener {
// Do something with the value
})
When the variable's value has been updated, the listener will be called with that updated value. You can specify what you want to do with the variable inside the variableUpdated
method.
Note: Default values for dynamic variables cannot be NULL. NULL values may cause default to trigger in all scenarios
Testing Dynamic Variables
When testing dynamic variables in live update mode you can change the values on the fly via the Taplytics interface and you can switch variations with the shake menu on the device.
Important Note: When testing synchronous dynamic variables you must call the constructor again to see the new value, as there are no callbacks which occur when the variable is updated with a new value.
This can be achieved by using an experiments updated listener. Here is an example for updating a TextView:
Taplytics.setTaplyticsExperimentsUpdatedListener(new TaplyticsExperimentsUpdatedListener() {
@Override
public void onExperimentUpdate() {
final TaplyticsVar<String> stringVar = new TaplyticsVar<String>("stringVar", "defaultValue");
updateText(stringVar.get());
}
});
Taplytics.setTaplyticsExperimentsUpdatedListener {
val stringVar = TaplyticsVar("stringVar", "defaultValue")
updateText(stringVar.get())
}
List Current Variables
If you would like to see which variables are currently available within the session, there exists a getAllVariables
method which will return an Array of VariableInfo
object.
Warning - Debug Use Only
This method is for debugging purposes only. Please do not use this method as a means to retrieve variable values for use.
Example:
Taplytics.getAllVariables(new TaplyticsAllVarsListener() {
@Override
public void currentVars(Array<VariableInfo> variables) {
// TODO: Do something with the array.
}
});
Taplytics.getAllVariables {
// TODO: Do something with the array.
}
The VariableInfo object contains the following properties:
class VariableInfo {
name: String;
value: object;
variableType: String;
_id: String;
}
NOTE: This function runs asynchronously, as it waits for the updated properties to load from Taplytics servers.
Code Blocks
Similar to Dynamic Variables, Taplytics has an option for 'Code Blocks'. Code blocks are linked to Experiments through the Taplytics website very much the same way that Dynamic Variables are, and will be executed based on the configuration of the experiment through the Taplytics website. A Code Block is a callback that can be enabled or disabled depending on the variation. If enabled, the code within the callback will be executed. If disabled, the variation will not get the callback.
A Code Block can be used alongside as many other Code Blocks as you would like to determine a combination that yields the best results. Perhaps there are three different Code Blocks on one activity. This means there could be 8 different combinations of Code Blocks being enabled / disabled on that activity if you'd like.
For example:
Taplytics.runCodeBlock("name", new CodeBlockListener() {
@Override
public void run() {
// Put your code here!
}
});
Taplytics.runCodeBlock("name") {
// Put your code here!
}
By default, a code block will not run unless enabled on the Taplytics Dashboard. It must be enabled for a Variation before it will run.
Testing Specific Experiments
To test/QA specific experiment and variation combinations, add a map to the Taplytics start options containing the experiments and variations you wish to test. The keys should be the experiment names, and values of variation names (or baseline).
For example:
HashMap<String, Object> startOptions = new HashMap<>();
HashMap testExperiments = new HashMap();
testExperiments.put("Big Experiment", "Variation 2");
startOptions.put("testExperiments", testExperiments);
Taplytics.startTaplytics(this, SDK_KEY, startOptions);
val startOptions: HashMap<String, Any> = HashMap()
val testExperiments = HashMap<Any, Any>()
testExperiments["Big Experiment"] = "Variation 2"
startOptions["testExperiments"] = testExperiments
Taplytics.startTaplytics(this, SDK_KEY, startOptions)
List Running Experiments
If you would like to see which variations and experiments are running on a given device, there exists a getRunningExperimentsAndVariations(TaplyticsRunningExperimentsListener listener)
function which provides a callback with a map of the current experiments and their running variation. An example:
Taplytics.getRunningExperimentsAndVariations(new TaplyticsRunningExperimentsListener() {
@Override
public void runningExperimentsAndVariation(Map<String, String> experimentsAndVariations) {
// TODO: Do something with the map.
}
});
Taplytics.getRunningExperimentsAndVariations {
// TODO: Do something with the map.
}
NOTE: This function runs asynchronously, as it waits for the updated properties to load from Taplytics' servers before returning the running experiments.
If you want to see when the experiments have been loaded by Taplytics, you can add a TaplyticsExperimentLoadedListener
to your startTaplytics
call. For example:
Taplytics.startTaplytics(this, "YOUR SDK KEY", null, new TaplyticsExperimentsLoadedListener() {
@Override
public void loaded() {
//TODO: Do something now that experiments are loaded
}
});
Taplytics.startTaplytics(
this,
"YOUR SDK KEY",
null
) {
//TODO: Do something now that experiments are loaded
}
Feature Flags
Taplytics feature flags operate in synchronous mode. Synchronous feature flags are guaranteed to have the same value for the entire session and will have that value immediately after construction.
Due to the synchronous nature of feature flags, if it is used before the feature flags have been loaded from Taplytics servers (for example on the first launch of your app), it will default to as if the feature flag is not present. In order to prevent this you can ensure that the feature flag is loaded before using the feature flag. This can be done with either the delayLoad
functionality, the TaplyticsExperimentsLoadedListener
parameter in your startTaplytics
call, or the getRunningExperimentsAndVariations
call:
if (Taplytics.featureFlagEnabled("featureFlagKey")) {
//Put feature code here, or launch feature from here
}
if (Taplytics.featureFlagEnabled("featureFlagKey")) {
//Put feature code here, or launch feature from here
}
Setting a Default value
In the event that Taplytics was unable to load, Taplytics will by default return FALSE when using featureFlagEnabled. To prevent this behavour and instead default a feature to being ON in cases of no network, pass in the desired default behavior.
WARNING: Setting the Feature Flag default to true
means that users will always receive the Feature Flag, even when it has been disabled.
if (Taplytics.featureFlagEnabled("featureFlagKey", true)) {
//Put feature code here, or launch feature from here
}
if (Taplytics.featureFlagEnabled("featureFlagKey", true)) {
//Put feature code here, or launch feature from here
}
Running Feature Flags
If you would like to see which feature flags are running on a given device, there exists a getRunningFeatureFlags(TaplyticsRunningFeatureFlagsListener listener)
function which provides a callback with a map of the current feature flags. An example:
Taplytics.getRunningFeatureFlags(new TaplyticsRunningFeatureFlagsListener() {
@Override
public void runningFeatureFlags(Map<String, String> featureFlags) {
// TODO: Do something with the map.
}
});
Taplytics.getRunningFeatureFlags {
// TODO: Do something with the map.
}
Dialogs
Taplytics supports editing elements on dialogFragments (not dialogs). To do this properly, you must use a fragmentTransaction to add the fragment to the backstack. The tag used here should be the same as the tag used to show the fragment, like so:
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.show(someDialog);
fragmentTransaction.addToBackStack("fragment_some_dialog");
someDialog.show(fragmentTransaction, "fragment_some_dialog");
val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.show(someDialog)
fragmentTransaction.addToBackStack("fragment_some_dialog")
someDialog.show(fragmentTransaction, "fragment_some_dialog")
Taplytics tracks the appearance/disappearance of the dialog via the backstack manager, which is why it needs to be sent there. The tag is necessary to confirm that the visual edits are being applied to the correct fragment.
This only works with dialogFragments as normal Dialogs do not have any unique identifying tags.
NOTE: dialogFragments exist on an entirely different view hierarchy than traditional view elements. They exist within their own window
and have an entirely different viewRoot than the rest of your application. This makes changes on dialogs very difficult, and this feature is not 100% guaranteed to work for all dialogs.
Delay Load
Taplytics has the option to delay the loading of your main activity while Taplytics gets initial view changes ready. Keep in mind that this initial load will only take some time the very first time, after that, these changes will be saved to disk and will likely not need a delay.
There are two methods to do this, use both at the start of your java onCreate()
after java setContentView()
:
Delay Load With Image
In this instance, Taplytics takes care of the loading for you. Taplytics creates a splash screen with the provided image. The image will fade automatically after the given time, or when Taplytics has successfully loaded visual changes on the provided activity.
Method: Taplytics.delayLoad(Activity activity, Drawable image, int maxTime)
and Taplytics.delayLoad(Activity activity, Drawable image, int maxTime, int minTime)
- Activity: the activity (typically main activity) that will be covered in a splash image.
- Image: A Drawable image that will be the splash screen.
- maxTime: Regardless of the results of Taplytics, the image will fade after this time. Milliseconds.
- minTime: Sometimes Taplytics loads things really fast, and this might make the image show only for a short amount of time. To keep this from happening, there is an optional minimum time option. Regardless of Taplytics loading experiments, the
delayLoad
won't finish until after this minimum time. Milliseconds.
Example:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
Taplytics.delayLoad(this, getResources().getDrawable(R.drawable.image5), 2000);
...
override fun onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_layout);
Taplytics.delayLoad(this, getResources().getDrawable(R.drawable.image5), 2000);
...
With a 1 second minimum time
Taplytics.delayLoad(this, getResources().getDrawable(R.drawable.image5), 2000, 1000);
...
Taplytics.delayLoad(this, getResources().getDrawable(R.drawable.image5), 2000, 1000);
...
Delay Load with Callbacks
In this instance, Taplytics provides callbacks when the delay load should begin, and when the delay load ends. The callback will also return after the provided timeout time has been reached. This provides you the ability to show a splashscreen that is more than just a simple image.
Method: Taplytics.delayLoad(int maxTime, TaplyticsDelayLoadListener listener)
and Taplytics.delayLoad(int maxTime, int minTime, TaplyticsDelayLoadListener listener)
- maxTime: Regardless of the results of Taplytics, this callback will be triggered if this time is reached.
- minTime: Sometimes Taplytics loads things really fast, and this might make the behavior of the callback undesirable. To keep this from happening, there is an optional minimum time option. Regardless of Taplytics loading experiments, the
delayLoad
won't finish until after this minimum time. - Listener: This listener will provide the necessary callbacks.
Example:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
Taplytics.delayLoad(2000, new TaplyticsDelayLoadListener() {
@Override
public void startDelay() {
//Start delaying!
}
@Override
public void delayComplete() {
//Loading completed, or the given time has been reached. Insert your code here.
}
});
...
protected fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_layout)
Taplytics.delayLoad(2000, object : TaplyticsDelayLoadListener {
override fun startDelay() {
//Start delaying!
}
override fun delayComplete() {
//Loading completed, or the given time has been reached. Insert your code here.
}
})
...
}
With a 1 second minimum time:
Taplytics.delayLoad(2000, 1000, ...
Taplytics.delayLoad(2000, 1000, ...
Sessions
By default, Taplytics defines a session as when a user is using the app with less than 10 minutes of inactivity. If the app has been backgrounded for 10 minutes, the next time the user opens the app it will be considered a new session. Similarly, if the app is entirely force closed, the next time the app is opened, it will be considered a new session.
StartNewSession
To manually force a new user session (ex: A user has logged in / out), there exists Taplytics.startNewSession
If there is an internet connection, a new session will be created, and new experiments/variations will be fetched from Taplytics if they exist.
It can be used as follows:
Taplytics.startNewSession(new TaplyticsNewSessionListener() {
@Override
public void onNewSession() {
// New session here! Only returns if successful.
}
public void onError() {
// No new session here! Only returns if unsuccessful.
}
});
Taplytics.startNewSession(object : TaplyticsNewSessionListener {
override fun onNewSession() {
// New session here! Only returns if successful.
}
override fun onError() {
// No new session here! Only returns if unsuccessful.
}
})
Session Listener
To keep track of when Taplytics defines a new session, use a TaplyticsNewSessionListener
as follows.
Taplytics.setTaplyticsNewSessionListener(new TaplyticsNewSessionListener() {
@Override
public void onNewSession() {
//We are in a new session
}
public void onError() {
//We are not in a new session
}
});
Taplytics.setTaplyticsNewSessionListener(object : TaplyticsNewSessionListener {
override fun onNewSession() {
//We are in a new session
}
override fun onError() {
//We are not in a new session
}
})
Note that this is NOT called the first time Taplytics loads, only on subsequent sessions
Push Notifications
Setting up Push Notifications using Taplytics is simple. Follow the steps below to get started.
Note: Google has changed the way push notifications work from using GCM to FCM, migrate ASAP!
1. Setup
Set up your Firebase certificate on Taplytics by following these docs.
Android Studio
Follow these instructions to add firebase to your project. Then, add the following to your dependencies in your build.gradle
:
implementation 'com.google.firebase:firebase-messaging:17.+'
implementation 'com.google.firebase:firebase-core:16.0.8'
On firebase-messaging versions above 22.0.0, include the firebase-iid dependency.
implementation 'com.google.firebase:firebase-messaging:22.0.0'
implementation 'com.google.firebase:firebase-iid:21.1.0'
Add the following to the end of your build.gradle
file if you haven't already:
apply plugin: 'com.google.gms.google-services'
Android Manifest
If you wish to use Push Notifications on Taplytics, you must add the following to your AndroidManifest.xml
file under the application tag:
<service
android:name="com.taplytics.sdk.fcm.TLFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Other notes
- Keep in mind Firebase is supported only in API level 14 and up
- Minimum version of firebase-messaging support is
17.0.0
- Minimum version of firebase-core support is
16.0.8
- Minimum version of Taplytics Android SDK is
2.1.0
In order to set the notification icon you must add a meta-tag to your manifest specifying the drawable you want to use as the icon:
<meta-data android:name="com.taplytics.sdk.notification_icon"
android:resource="@drawable/notification_icon"/>
If this isn't set the application's icon will be used instead.
2. Receiving Push Notifications
To send your users Push Notifications, we'll need you to upload your Google Cloud Messaging credentials. Please follow this guide to do so.
Activity Routing
By default, when a notification sent by Taplytics is clicked, it will open up the main activity of the application. However, you may want to route your users to a different Activity. This can be done on the Taplytics Push page.
Simply add a custom data value to the push with the key tl_activity
and with the full (including package name) class name of your activity. For example:
Push Title
By default, the title of a push notification will be the application name.
Currently, the best way to change the title of a push notification is to add a tl_title
custom key. For Example:
Getting the Push Token
Sometimes, it can be useful to have the actual token generated by GCM, to target pushes at specific users.
To get this token, use the following method:
Taplytics.setTaplyticsPushTokenListener(new TaplyticsPushTokenListener() {
@Override
public void pushTokenReceived(String token) {
//Do something with the push token here.
}
});
Taplytics.setTaplyticsPushTokenListener {
//Do something with the push token here.
}
3. Rich Push Notifications
Implementing rich push notification support can help improve user engagement with your push notifications with image content attached. We currently support JPEG and PNG images sent from the Taplytics dashboard or API.
Android will automatically crop all images to be a 2:1 aspect ratio, scaling if necessary.
The max image size that can be uploaded is 10mb. Note that images are not downscaled and if an image is sent, the full file size of the crop will be used.
Here is an example of a push notification with an image:
4. Custom Data and Tracking Push Interactions
Taplytics has changed as of version 1.9 and push notifications are easier than ever:
To retrieve custom data set in the Taplytics dashboard, as well as to track push interactions (receive, open, dismiss), simply extend the TLBroadcastReceiver and override the function that you need. Then, replace the TLGcmBroadcastReceiver
in your manifest with that one!
Below is an example receiver that explains exactly how this is done. You can put this class directly in your app and start tracking push notifications right away. By default, taplytics will open the LAUNCH activity of your app, but this can be changed by not calling the super (see example below).
Note that Taplytics automatically tracks the following, however if you would like to do so for internal reasons, this is how.
/**
* Example receiver to take action with push notifications.
*
* Make sure to add this to your manifest (see the docs)
*
* Overriding any of these is entirely optional.
*
* By default, taplytics will open the launch activity of your
* app when a push notification is clicked.
*
*/
public class MyBroadcastReceiver extends TLGcmBroadcastReceiver {
@Override
public void pushOpened(Context context, Intent intent) {
//A user clicked on the notification! Do whatever you want here!
/* If you call through to the super,
Taplytics will launch your app's LAUNCH activity.
This is optional. */
super.pushOpened(context, intent);
}
@Override
public void pushDismissed(Context context, Intent intent) {
//The push has been dismissed :(
}
@Override
public void pushReceived(Context context, Intent intent) {
//The push was received, but not opened yet!
/*
If you add the custom data of tl_silent = true to the push notification,
there will be no push notification presented to the user. However, this will
still be triggered, meaning you can use this to remotely trigger something
within the application!
*/
}
}
/**
* Example receiver to take action with push notifications.
*
* Make sure to add this to your manifest (see the docs)
*
* Overriding any of these is entirely optional.
*
* By default, taplytics will open the launch activity of your
* app when a push notification is clicked.
*
*/
class MyBroadcastReceiver : TLGcmBroadcastReceiver() {
override fun pushOpened(context: Context?, intent: Intent?) {
//A user clicked on the notification! Do whatever you want here!
/* If you call through to the super,
Taplytics will launch your app's LAUNCH activity.
This is optional. */
super.pushOpened(context, intent)
}
override fun pushDismissed(context: Context?, intent: Intent?) {
//The push has been dismissed :(
}
override fun pushReceived(context: Context?, intent: Intent?) {
//The push was received, but not opened yet!
/*
If you add the custom data of tl_silent = true to the push notification,
there will be no push notification presented to the user. However, this will
still be triggered, meaning you can use this to remotely trigger something
within the application!
*/
}
}
And then in your manifest:
<receiver
android:name=".MyBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
<intent-filter>
<action android:name="taplytics.push.OPEN" />
<action android:name="taplytics.push.DISMISS" />
</intent-filter>
</receiver>
If you are handling push notifications with custom payloads, the custom data key/values will be added to the custom_keys
object as seen below in an example push payload:
{
"data": {
"message": "Test Push",
"tl_id": "",
"custom_keys": {
"custom_data_key": "custom_data_value"
},
"image_url": ""
}
}
5. Special Push Options (title, priority, icon)
The dashboard allows for custom data to be entered into your push notifications. However there are some options that can be added to the custom data for special functionality.
Name | Values | Explanation |
---|---|---|
tl_title | String | This changes the TITLE of the push notification. By default, it is your application's name. But with this option you can change the title to be anything. |
tl_priority | integer | Set the priority of the push notification. For more info see the section 'Correctly set and manage notification priority' here. The value set must be the integer that is associated with the priorities, which can be found here. |
tl_image_icon | boolean | Will not show a preview image as the notification icon when set to false. Defaults to true. |
tl_large_icon | boolean | Will show the app icon in the notification when set to true. Defaults to false. |
6. Manual Token Registration (Optional)
If you already have a system to receive Firebase push tokens, you can use TLFirebaseMessagingServiceLite
instead of TLFirebaseMessagingService
. Instead of overriding onNewToken
and saving the token to our system automatically, all TLFirebaseMessagingServiceLite
does is process the push notification.
Include the start option manualPushToken and set it to true
to bypass saving the token automatically.
options.put("manualPushToken", true);
Taplytics.startTaplytics(this, "YOUR_SDK_KEY", options);
options["manualPushToken"] = true
Taplytics.startTaplytics(this, "YOUR_SDK_KEY", options)
You then must use Taplytics.savePushToken("PUSH_TOKEN")
to enable push notifications through Taplytics.
7. Tracking Self Built Notifications
You may be using Taplytics simply to send push notifications. If you already have a system to build notifications, then extending the Taplytics BroadcastReceiver will cause you to see duplicates.
To avoid this problem, first, do not call super.onReceive()
where super would be the TLGCMBroadcastReceiver
.
Now, Taplytics will not have any push notification tracking if you do this.
To mitigate this, you must use the Taplytics functions provided. In each function, you must pass in the tl_id in the notification attempt.
Push Open
Taplytics.trackPushOpen("tl_id",customKeys);
Where tl_id is retrieved from the notification intent. CustomKeys is the metadata passed into the notification. It is optional/nullable
Push Dismissed
Taplytics.trackPushDismissed("tl_id",customKeys);
Where tl_id is retrieved from the notification intent. CustomKeys is the metadata passed into the notification. It is optional/nullable
Push Received
Taplytics.trackPushReceived("tl_id",customKeys);
Where tl_id is retrieved from the notification intent. CustomKeys is the metadata passed into the notification. It is optional/nullable
8. Troubleshooting
Using the shake menu, you can copy the token to your clipboard, force to save the token to Taplytics, or renew the token.
Taplytics.showMenu(); // Shows the shake menu, exposing some useful items like the push token
Sockets
Usage
Sockets are used in the Taplytics SDK to establish a two way connection to Taplytics' servers. This connection is used for editing experiments, both for visual experiments and dynamic variables. However it is only used in the development versions of the app, or devices which have been explicitly paired with Taplytics using a pairing email or text message.
Inclusion in release builds - as of 1.7.0
Due to experiment editing for the most part being done on internal dev builds sockets are not necessary on release versions of the app. In order to account for this Taplytics does not require the socket dependency for release builds. So instead of using the standard compile
directive when adding the socket dependency the debugImplementation
directive can be used instead.
Please note that this will not allow pairing of live versions of the app using text message or email pairing.
debugImplementation ('io.socket:socket.io-client:1.0.1') {
// excluding org.json which is provided by Android
exclude group: 'org.json', module: 'json'
}
I'm getting a popup saying update my sockets!
There was a recent change (1.7.0) in the package name of the socket library used by Taplytics. Given that the library has continued to improve over time Taplytics makes use of this new library. Unfortunately this means that the dependency that was being used before is no longer valid.
There is a quick change that will fix this issue, simple change:
implementation("com.github.nkzawa:socket.io-client:+") {
exclude group: 'org.json'
}
implementation("com.github.nkzawa:engine.io-client:+") {
exclude group: 'org.json'
}
to:
debugImplementation('io.socket:socket.io-client:1.0.1') {
// excluding org.json which is provided by Android
exclude group: 'org.json', module: 'json'
}
as mentioned above you can use debugImplementation
instead of implementation
if you don't want to include socket-io
in the release version of your app.
Updated almost 2 years ago