Skip to main content
Version: 3.x

Android

Notes on apps in test mode!

If your app is in test mode, you MUST use a test user. These are defined in "Test Devices" on the dashboard.

Support

If you are experiencing issues or need assistance, please reach out to developers@tapresearch.com

Installation

Example apps are available here

Minimum SDK version: 24

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.1+*:

Required for you to import the following dependencies.

If you're using a kotlin project, add the following to your build.gradle file

View in context

info

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

View in context

implementation 'com.tapresearch:tapsdk:3.2.1' // 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.1")
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.

OverrideDescriptionRequired?
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.

Understanding that the user identifier may not be known yet, please use whatever anonymous identifier you have available until the real user identifier is known.

Once the user identifier is known, use the setUserIdentifier method to update the identifier.

We suggest initializing the TapResearch SDK as early in the boot process as possible. 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

View in context

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,
),
)

Reward callback setup additional information

The reward callback is set within the initialization step. 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.

// this is set in the initialization callback
rewardCallback = { rewards -> showRewardToast(rewards) }

View in context

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()
}

Reward object

Note: in Java, you'll need to use the getRewardAmount() and getCurrencyName(), etc. methods

The reward object contains the following properties:

  • transactionIdentifier will be the unique identifier for the reward - this is used to prevent duplicate rewards
  • placementIdentifier will be the unique identifier for the placement - this can be used by your analytics to show which placement rewarded the user
  • currencyName will be the name of the currency name that was rewarded. This is the Currency Name that you set up in the dashboard. This is different from the Display Name
  • rewardAmount will be the amount of the currency that was rewarded, in your currency
  • placementTag 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

View in context

// This is set in the initialization callback
errorCallback = { trError -> showErrorToast(trError) }

...and the error toast

View in context

private fun showErrorToast(trError: TRError) {
Toast.makeText(
this@MainActivity,
"Error: ${trError.description}",
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.

note

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.

View in context

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) }
//...
}
},
//...
)

Setting the user identifier

You can set the user identifier at any time. This is done by calling setUserIdentifier with a string.

View in context

TapResearch.setUserIdentifier(
userIdentifier = userId,
errorCallback = object : TRErrorCallback {
override fun 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(context, "placement tag"). The error callback is optional.

View in context

if (TapResearch.canShowContentForPlacement(
context,
placementTag,
errorCallback = object : TRErrorCallback {
override fun onTapResearchDidError(trError: TRError) {
trError.description?.let { Log.e("TRERROR", it) }
}
},
)
) {
//...
}

Showing the placement

The placement is shown by calling showContentForPlacement("placement tag", application).

The onTapResearchContentShown, onTapResearchContentDismissed, and onTapResearchDidError callbacks are optional. As hashmap of customParameters is also optional.

View in context

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)
}
},
)

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.

View in context

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)
}
},
)