Android
If your app is in test mode, you MUST use a test user. These are defined in "Test Devices" on the dashboard.
If you are experiencing issues or need assistance, please reach out to developers@tapresearch.com
Installation
Example apps are available here
Minimum SDK version: 23
Add the following to your build.gradle file
Add the following to your app-level build.gradle
file:
repositories {
maven { url "https://artifactory.tools.tapresearch.io/artifactory/tapresearch-android-sdk/" }
...
}
And then add the following to your dependencies section of your settings.gradle
file
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url "https://artifactory.tools.tapresearch.io/artifactory/tapresearch-android-sdk/" }
}
}
3.2.8+*:
Required for you to import the following dependencies.
If you're using a kotlin project, add the following to your build.gradle
file
The latest version available via artifactory can be seen here
If you're using a java project, add the following to your build.gradle
file
implementation 'com.tapresearch:tapsdk:3.2.8' // replace + with latest version
implementation 'androidx.lifecycle:lifecycle-process:2.6.1'
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3'
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
// used for custom params
implementation 'com.google.code.gson:gson:2.8.0'
Or if you're using a kotlin project
implementation("com.tapresearch:tapsdk:3.2.8")
implementation("androidx.lifecycle:lifecycle-process:2.6.1")
implementation("androidx.core:core-ktx:1.10.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
implementation("com.google.android.gms:play-services-ads-identifier:18.0.1")
// used for custom params
implementation("com.google.code.gson:gson:2.8.0")
Integration
Callbacks
There are a few callbacks that you will need to provide to the SDK upon initialization.
Override | Description | Required? |
---|---|---|
rewardCallback (TRRewardCallback ) | The callback hit every time a reward is received for your users. | No |
errorCallback (TRErrorCallback ) | The error message channel. Used if the SDK experiences an issue. | Yes |
sdkReadyCallback (TRSdkReadyCallback ) | Lets you know when the SDK is done booting. | No |
contentCallback (TRContentCallback ) | Lets you know when the content (survey wall, banner, interstitial, etc) is shown or dismissed. | No |
Reward callback (TRRewardCallback
): This is called when the user completes a survey and is passed an array of TRReward
's.
If you are using in-app callbacks to return rewards, you'll need to have this set up before initialization.
The SDK will respond with a TRReward object that contains the reward amount and currency code.
Error callback (TRErrorCallback
): This is called when there is an error and is passed an instance of TRError
.
sdkReadyCallback (TRSdkReadyCallback
): (optional) This is called when the SDK is ready to show content. This is a good time to show content.
contentCallback (TRContentCallback
): (optional) This is called when the content is shown or dismissed. This is a good time to log analytics.
SDK Initialization
You will need to initialize the SDK with both a user identifier and an api token.
The user identifier is a unique identifier for the user taking the survey.
Only initialize our sdk if the user identifier is known, do NOT initialize with an anonymous user identifier.
We suggest initializing the TapResearch SDK as early in the boot process as possible (once the user identifier is available). The demo app initializes in the onCreate
method of the MainActivity
.
Similarly, there is a callback for when the SDK is ready. This is called when the SDK has finished initializing and is ready to show content. We suggest showing content only when the SDK is ready.
Optionally, you may pass an initOptions parameter through initialization for additional configuration. See example below and Initializations Options.
If user attributes are known at SDK initialization, it is preferable to pass them through initOptions
compared to using sendUserAttributes
. This will result in quicker load times for targeted content.
- Kotlin
- Java
val myUserIdentifier = "public-demo-test-user"
val myApiToken = getString(R.string.api_token)
Log.d("MainActivity", "API Token: $myApiToken")
Log.d("MainActivity", "User identifier: $myUserIdentifier")
TapResearch.initialize(
apiToken = getString(R.string.api_token),
userIdentifier = myUserIdentifier,
activity = this@MainActivity,
rewardCallback = object : TRRewardCallback {
override fun onTapResearchDidReceiveRewards(rewards: MutableList<TRReward>) {
showRewardToast(rewards)
}
},
errorCallback = object : TRErrorCallback {
override fun onTapResearchDidError(trError: TRError) {
showErrorToast(trError)
}
},
sdkReadyCallback = object : TRSdkReadyCallback {
override fun onTapResearchSdkReady() {
Log.d(LOG_TAG, "SDK is ready")
// now that the SDK is ready, we can show content
}
},
// this is optional
initOptions =
TapInitOptions(
userAttributes =
hashMapOf(
"is_vip" to 1,
"something_else" to 2,
),
clearPreviousAttributes = true,
),
)
// Your api token will likely be hardcoded in your app, but for the sake of this example
String myUserIdentifier = "public-demo-test-user";
TapResearch.INSTANCE.initialize(myApiToken, myUserIdentifier,
MainActivity.this,
new TRRewardCallback() {
@Override
public void onTapResearchDidReceiveRewards(List<TRReward> rewards) {
showRewardToast(rewards);
}
},
new TRErrorCallback() {
@Override
public void onTapResearchDidError(TRError trError) {
showErrorToast(trError);
}
},
new TRSdkReadyCallback() {
@Override
public void onTapResearchSdkReady() {
Log.d(LOG_TAG, "SDK is ready");
// now that the SDK is ready, we can show content and send user attributes
sendUserAttributes();
// showContent();
}
}
);
Checking if SDK is ready to use
In addition to waiting for the sdkReadyCallback
via initialize
(which is our recommended method),
you can also determine if the SDK is ready to use by checking isReady
- Kotlin
- Java
TapResearch.isReady()
// Example
if (TapResearch.isReady() == false) {
...
} else {
...
}
TapResearch.INSTANCE.isReady()
// Example
if (TapResearch.INSTANCE.isReady() == false) {
...
} else {
...
}
Reward callback setup additional information
The reward callback can be set via initialize
.
It is required for apps using in-app callbacks for rewards.
Here we are just defining something that you are able to do with the rewards that are returned.
- Kotlin
- Java
// this can be set via initialize
rewardCallback = { rewards -> showRewardToast(rewards) }
private fun showRewardToast(rewards: MutableList<TRReward>) {
var rewardCount = 0
for (reward: TRReward in rewards) {
reward.rewardAmount?.let { rewardCount += it }
}
val currencyName = rewards.first().currencyName
val eventType = rewards.first().payoutEventType
Toast.makeText(
this@MainActivity,
"Congrats! You've earned $rewardCount $currencyName. Event type is $eventType",
Toast.LENGTH_LONG,
).show()
}
private void showRewardToast(List<TRReward> rewards) {
int rewardCount = 0;
for (TRReward reward : rewards) {
if (reward.getRewardAmount() != null) {
rewardCount += reward.getRewardAmount();
}
}
String currencyName = rewards.getCurrencyName();
String eventType = rewards.getPayoutEventType();
Toast.makeText(MainActivity.this,"Congrats! You've earned " + rewardCount + " " + currencyName + ". Event type is " + eventType,Toast.LENGTH_LONG).show();
}
Reward object
Note: in Java, you'll need to use the
getRewardAmount()
andgetCurrencyName()
, etc. methods
The reward object contains the following properties:
transactionIdentifier
will be the unique identifier for the reward - this is used to prevent duplicate rewardsplacementIdentifier
will be the unique identifier for the placement - this can be used by your analytics to show which placement rewarded the usercurrencyName
will be the name of the currency name that was rewarded. This is theCurrency Name
that you set up in the dashboard. This is different from theDisplay Name
rewardAmount
will be the amount of the currency that was rewarded, in your currencyplacementTag
will be the tag of the placement that rewarded the user - its human readable and unique
A TRReward object will look like this:
TRReward(
transactionIdentifier=tap_pr_062ff34493dff7123691f79921978391,
placementIdentifier=ffbd56740417114bc70c57f93151fa74,
currencyName=some_dirt.1s,
rewardAmount=10,
payoutEventType=profileReward,
placementTag=normal-offer
)
Error callbacks
You can use the error callback to log or report errors.
See the Error Codes page for more information on the error codes
- Kotlin
- Java
// This is set in the initialization callback
errorCallback = { trError -> showErrorToast(trError) }
...and the error toast
private fun showErrorToast(trError: TRError) {
Toast.makeText(
this@MainActivity,
"Error: ${trError.description}",
Toast.LENGTH_LONG,
).show()
}
// This is set in the error callback
new ErrorCallback() {
@Override
public void onTapResearchDidError(TRError trError) {
showErrorToast(trError);
}
}
...and the error toast
private void showErrorToast(TRError trError) {
Toast.makeText(MainActivity.this, "Error: " + trError.getDescription(),Toast.LENGTH_LONG).show();
}
TRError object
The error object contains the following properties:
code
: The error code. This can be used when debugging as there is an associated list of error codes and descriptions.
description
: The error message. This is a human readable description of the error.
User attributes
See more on user attributes here.
User attributes are used to target specific users with content (ex: an offer). They can be set at any time and the most recent values received will be used when determining which content to show.
User attributes are passed as a dictionary of key-value pairs.
User attributes prefixed with tapresearch_
are reserved for internal use. Please do not use this prefix for user attributes as doing so will result in an error
The keys must be strings and the values must be one of:
- String
- Float
- Integer
If you want to use a date, please stringify an ISO8601 date or use a timestamp.
There are two ways of sending user attributes. Firstly, you are able to pass them in initialization in initOptions. This works well any time you have user attributes avaiable at sdk initialization time. clearPreviousAttributes allows you to remove any attributes previously sent to us for the user identifier.
initialize(
// ...
initOptions =
TapInitOptions(
userAttributes =
hashMapOf(
"is_vip" to 1,
"something_else" to 2,
),
clearPreviousAttributes = true,
),
//...
)
You can send user attributes as soon as the SDK is ready. This is done by calling sendUserAttributes
with a HashMap
of attributes.
We suggest sending as many attributes as you think that you'll want to target on for surveys, special awards, etc.
- Kotlin
- Java
initialize(
// ...
sdkReadyCallback = object : TRSdkReadyCallback {
override fun onTapResearchSdkReady() {
Log.d(LOG_TAG, "SDK is ready")
val userAttributes: HashMap<String, Any> = HashMap()
userAttributes["age"] = 25
userAttributes["VIP"] = true
userAttributes["name"] = "John Doe"
userAttributes["first_seen"] = Instant.now().toString()
TapResearch.sendUserAttributes(
userAttributes,
) { trError -> showErrorToast(trError) }
//...
}
},
//...
)
initialize(
//...
public void onTapResearchSdkReady() {
Log.d(LOG_TAG, "SDK is ready");
HashMap<String, Object> userAttributes = new HashMap<>();
userAttributes.put("age", 25);
userAttributes.put("VIP", true);
userAttributes.put("name", "John Doe");
userAttributes.put("first_seen", Instant.now().toString());
TapResearch.INSTANCE.sendUserAttributes(userAttributes, new TRErrorCallback() {
@Override
public void onTapResearchDidError(TRError trError) {
Log.d(LOG_TAG, "Error sending user attributes: " + trError.toString());
}
});
//...
}
//...
)
Setting the user identifier
You can set the user identifier at any time. This is done by calling setUserIdentifier
with a string.
- Kotlin
- Java
TapResearch.setUserIdentifier(
userIdentifier = userId,
errorCallback = object : TRErrorCallback {
override fun onTapResearchDidError(trError: TRError) {
showErrorToast(trError)
}
},
)
TapResearch.INSTANCE.setUserIdentifier(
userIdentifier,
new TRErrorCallback() {
@Override
public void onTapResearchDidError(TRError trError) {
showErrorToast(trError);
}
}
);
Displaying a placement
Checking if the placement is available
A placement is a survey that is content displayed to the user.
Ideally, you check to see if the placement can be shown before actually showing it.
To find out if the content is available for the given user, call: canShowContentForPlacement("placement tag")
.
The error callback is optional.
- Kotlin
- Java
if (TapResearch.canShowContentForPlacement(
placementTag,
errorCallback = object : TRErrorCallback {
override fun onTapResearchDidError(trError: TRError) {
trError.description?.let { Log.e("TRERROR", it) }
}
},
)
) {
//...
}
if (TapResearch.INSTANCE.canShowContentForPlacement(placementTag, new TRErrorCallback() {
@Override
public void onTapResearchDidError(TRError trError) {
Log.d("TRLOG", "Whoops " + trError.toString());
}
})) {
//...
}
Showing the placement
The placement is shown by calling showContentForPlacement("placement tag")
.
The onTapResearchContentShown
, onTapResearchContentDismissed
, and onTapResearchDidError
callbacks are optional. As hashmap of customParameters is also optional.
- Kotlin
- Java
TapResearch.showContentForPlacement(
placementTag,
customParameters,
object : TRContentCallback {
override fun onTapResearchContentShown(placement: TRPlacement) {
tapResearchDidDismiss(placement)
}
override fun onTapResearchContentDismissed(placement: TRPlacement) {
tapResearchContentShown(placement)
}
},
object : TRErrorCallback {
override fun onTapResearchDidError(trError: TRError) {
showErrorToast(trError)
}
},
)
TapResearch.INSTANCE.showContentForPlacement(
placementTag,
application,
customParameters,
new TRContentCallback() {
@Override
public void onTapResearchContentShown(TRPlacement trPlacement) {
Log.d("TRLOG", "Content shown for placement " + trPlacement.toString());
}
@Override
public void onTapResearchContentDismissed(TRPlacement trPlacement) {
Log.d("TRLOG", "Content dismissed for placement " + trPlacement.toString());
}
},
new TRErrorCallback() {
@Override
public void onTapResearchDidError(TRError trError) {
showErrorToast(trError);
}
}
);
Passing custom parameters
Custom parameters allow you to receive additional information about the user when they complete a survey. This can be used to filter out users who have already completed a survey, or to target specific users.
These params will be returned via server-to-server callbacks.
There are a maximum of 5 custom parameters that can be passed per placement.
- Kotlin
- Java
val customParameters: HashMap<String, Any> = HashMap()
customParameters["age"] = 25
customParameters["VIP"] = true
customParameters["name"] = "John Doe"
TapResearch.showContentForPlacement(
placementTag,
application,
customParameters,
object : TRContentCallback {
override fun onTapResearchContentShown(placement: TRPlacement) {
tapResearchDidDismiss(placement)
}
override fun onTapResearchContentDismissed(placement: TRPlacement) {
tapResearchContentShown(placement)
}
},
object : TRErrorCallback {
override fun onTapResearchDidError(trError: TRError) {
showErrorToast(trError)
}
},
)
HashMap<String, Object> customParameters = new HashMap<>();
customParameters.put("age", 25);
customParameters.put("VIP", true);
customParameters.put("name", "John Doe");
TapResearch.INSTANCE.showContentForPlacement(
selectedItem,
application,
placementCustomParameters,
new TRContentCallback() {
@Override
public void onTapResearchContentShown(TRPlacement trPlacement) {
Log.d("TRLOG", "Content shown for placement " + trPlacement.toString());
}
@Override
public void onTapResearchContentDismissed(TRPlacement trPlacement) {
Log.d("TRLOG", "Content dismissed for placement " + trPlacement.toString());
}
},
new TRErrorCallback() {
@Override
public void onTapResearchDidError(TRError trError) {
showErrorToast(trError);
}
}
);
Android Proguard
When creating a release version of your app, please use our proguard rules to your existing proguard file.