Skip to main content
Version: 3.x

Android

What you'll do
  1. Install the SDK
  2. Set up reward callbacks
  3. Initialize the SDK
  4. Display a placement

Later sections cover user attributes, the user identifier, placement details, custom parameters, and more.

Testing? Your app starts in test mode, so you'll need a test device to see content while you build.

Installation​

See the Android example apps on GitHub.

Note

Minimum SDK version: 23.

Repository​

  • SDK 3.7.3 and later are published to Maven Central. Make sure mavenCentral() is in your repositories; new Android projects include it by default.
  • SDK 3.7.2 and earlier are published to the TapResearch Artifactory repository. Add it to the dependencyResolutionManagement repositories in your settings.gradle (or settings.gradle.kts) file:
settings.gradle
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url "https://artifactory.tools.tapresearch.io/artifactory/tapresearch-android-sdk/" }
}
}

Dependencies​

Your app must also declare the libraries the SDK uses — the SDK does not pull them in. Add the following to the dependencies block of your app-level build.gradle (or build.gradle.kts) file:

Replace <version> with your SDK version from the matching repository above.

build.gradle
implementation 'com.tapresearch:tapsdk:<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.5.0'
implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.0')
implementation 'com.google.android.gms:play-services-ads-identifier:18.1.0'
implementation 'com.google.android.gms:play-services-appset:16.1.0'

Integration​

Callbacks​

These are the callbacks you provide to the SDK at initialization.

ParameterDescriptionRequired?
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.Yes
qqDataCallback (TRQQDataCallback)The callback hit every time a quick question is answered by your users.No

A content callback (TRContentCallback) is passed when you show a placement, not at initialization. It lets you know when content (survey wall, banner, interstitial, etc.) is shown or dismissed — a good time to log analytics.

Reward callback (TRRewardCallback): This is called when the user completes a survey and is passed a list of TRReward objects. Pass a reward callback to initialize to receive in-app rewards.

Error callback (TRErrorCallback): This is called when there is an error and is passed an instance of TRError.

sdkReadyCallback (TRSdkReadyCallback): This is called when the SDK is ready to show content. This is a good time to show content.

SDK initialization​

You will need to initialize the SDK with both a unique user identifier and an api token.

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 Initialization Options.

Info

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.

Tip

The user identifier passed through initialization must be unique! Only initialize once you are able to provide a unique identifier. Re-using the same user identifier is not supported and will prevent your users from accessing our service.

MainActivity.kt
val myUserIdentifier = "public-demo-test-user"
val myApiToken = getString(R.string.api_token)

TapResearch.initialize(
apiToken = myApiToken,
// userIdentifier must be unique for your player!
userIdentifier = myUserIdentifier,
context = this@MainActivity,
// optional, handle rewards here or pass null and call setRewardCallback to handle later
rewardCallback = { rewards ->
showRewardToast(rewards)
},
errorCallback = { error ->
showErrorToast(error)
},
sdkReadyCallback = {
Log.d(LOG_TAG, "Tap SDK initialized and ready")
},
// optional, handle here or pass null and call setQuickQuestionCallback to handle later
qqDataCallback = { quickQuestionPayload ->
Log.d(LOG_TAG, "Quick Question completed payload: $quickQuestionPayload")
},
// optional, can pass null
initOptions =
TapInitOptions(
userAttributes =
hashMapOf(
"is_vip" to 1,
"something_else" to 2,
),
clearPreviousAttributes = false,
),
)

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

if (TapResearch.isReady()) {
// ...
} else {
// ...
}

Reward callback setup additional information​

The reward callback can be set in two ways; via initialize and also via setRewardCallback. 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.

MainActivity.kt
// this can be set via initialize and also via setRewardCallback method
val rewardCallback = TRRewardCallback { rewards -> showRewardToast(rewards) }

TapResearch.setRewardCallback(rewardCallback)

private fun showRewardToast(rewards: MutableList<TRReward>) {
var rewardCount = 0f
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()
}

// Note: in your Activity.onPause(), do:
TapResearch.setRewardCallback(null)

// Similarly, in your Activity.onResume(), do:
TapResearch.setRewardCallback(rewardCallback)

Reward object​

Each reward is a TRReward. See TRReward for its properties.

Note

In Java, use the getters: getRewardAmount(), getCurrencyName(), getPayoutEventType(), and so on.

A TRReward object looks like this when printed:

TRReward(transactionIdentifier=tap_pr_062ff34493dff7123691f79921978391, placementIdentifier=ffbd56740417114bc70c57f93151fa74, currencyName=tokens, rewardAmount=10.0, payoutEventType=PROFILE_REWARD, placementTag=normal-offer)

Quick Question callback setup additional information​

New to Quick Questions? See Quick Questions for what they are and the response payload.

The quick question callback can be set in two ways; via initialize and also via setQuickQuestionCallback. It is optional for apps using quick questions that want to receive additional information when a user completes a quick question. Here we are just defining something that you are able to do with the quick question data that is returned.

MainActivity.kt
// this can be set via initialize and also via setQuickQuestionCallback method
val quickQuestionCallback = TRQQDataCallback { quickQuestionPayload ->
Log.d(LOG_TAG, "Quick Question payload data: $quickQuestionPayload")
}

TapResearch.setQuickQuestionCallback(quickQuestionCallback)

// important: when you no longer need to wait for quick question data, such as Activity onPause, do:
TapResearch.setQuickQuestionCallback(null)

Quick Question data payload object​

A QQPayload object will look like this:

data class QQPayload(
val surveyIdentifier: String,
val appName: String,
val apiToken: String,
val sdkVersion: String,
val platform: String,
val placementTag: String,
val userIdentifier: String,
val userLocale: String,
val seenAt: String,
val complete: Complete?,
val questions: List<Question>,
val targetAudience: Array<Map<String, String>>?,
)

Error callbacks​

You can use the error callback to log or report errors.

Info

See the Error Codes page for more information on the error codes.

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

...and the error toast

MainActivity.kt
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 (both nullable). See TRError for details.

  • 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.

Send user attributes​

User attributes are used to target specific users with content (ex: an offer). The most recent values received are used when determining which content to show.

Pass user attributes in initOptions during initialization, or call sendUserAttributes after the SDK is ready.

Attribute names must be strings and must not begin with tapresearch_, which is reserved for TapResearch. Use string or numeric values for targeting. For booleans, send "true"/"false" or 0/1 instead of native booleans.

Set clearPreviousAttributes to false to merge new values with existing attributes, or true to replace the attributes you previously sent.

initialize(
// ...
initOptions =
TapInitOptions(
userAttributes =
hashMapOf(
"is_vip" to 1,
"something_else" to 2,
),
clearPreviousAttributes = true,
),
//...
)

To update attributes after initialization, pass a HashMap to sendUserAttributes.

We suggest sending as many attributes as you think that you'll want to target on for surveys, special awards, etc.

MainActivity.kt
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"] = 1
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 by calling setUserIdentifier with a string.

TapResearch.setUserIdentifier(userId)

Displaying a placement​

Checking if the placement is available​

A placement is a location in your app where TapResearch content is 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", errorCallback). The error callback is required; it receives the reason when the placement can't be shown.

MainActivity.kt
if (TapResearch.canShowContentForPlacement(
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. Its parameters, in order, are the placement tag, an optional TRContentCallback, optional custom parameters (a HashMap), and a required TRErrorCallback.

The content callback receives the placement tag (a String) in onTapResearchContentShown and onTapResearchContentDismissed.

MainActivity.kt
TapResearch.showContentForPlacement(
tag = placementTag,
contentCallback = object : TRContentCallback {
override fun onTapResearchContentShown(placementTag: String) {
tapResearchContentShown(placementTag)
}

override fun onTapResearchContentDismissed(placementTag: String) {
tapResearchDidDismiss(placementTag)
}
},
customParameters = customParameters,
errorCallback = 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 in your server-to-server postbacks.

There are a maximum of 5 custom parameters that can be passed per placement.

MainActivity.kt
val customParameters: HashMap<String, Any> = HashMap()
customParameters["age"] = 25
customParameters["VIP"] = 1
customParameters["name"] = "John Doe"

TapResearch.showContentForPlacement(
tag = placementTag,
contentCallback = object : TRContentCallback {
override fun onTapResearchContentShown(placementTag: String) {
tapResearchContentShown(placementTag)
}

override fun onTapResearchContentDismissed(placementTag: String) {
tapResearchDidDismiss(placementTag)
}
},
customParameters = customParameters,
errorCallback = object : TRErrorCallback {
override fun onTapResearchDidError(trError: TRError) {
showErrorToast(trError)
}
},
)

Getting placement details​

Info
Don't cache placement details

Placement details can change as our SDK refreshes placements in the background, so it is not recommended to store or cache these values. Instead, refetch the details each time you need to use them, e.g. to display something in your UI.

Get placement details by calling getPlacementDetails("placement tag", optional errorCallback).

It will return a TRPlacementDetails object or null:

data class TRPlacementDetails(
val name: String? = null,
val contentType: String? = null,
val currencyName: String? = null,
val isSale: Boolean? = null,
val saleType: String? = null,
val saleEndDate: String? = null, // UTC date string. i.e. SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
val saleMultiplier: Float? = null,
val saleDisplayName: String? = null,
val saleTag: String? = null,
val bonusBarProgress: TRBonusBarProgress? = null,
)

data class TRBonusBarProgress(
val isActive: Boolean? = null,
val currentCompletes: Int? = null,
val bonusWindowEndAt: String? = null, // UTC date string. i.e. SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
val bonusTiers: List<TRBonusTier>? = null,
val error: TRError? = null,
)

data class TRBonusTier(
val tierNumber: Int? = null,
val completesNeeded: Int? = null,
val rewardAmount: Float? = null,
val status: String? = null,
)
MainActivity.kt
val placementDetails = TapResearch.getPlacementDetails("my-placement-tag") { error -> println(error) }

Granting boosts​

Call grantBoost with a configured User Boosts tag. The result callback is optional:

MainActivity.kt
import kotlinx.serialization.InternalSerializationApi

@OptIn(InternalSerializationApi::class)
fun grantBoost() {
TapResearch.grantBoost("BOOST_TAG") { response ->
if (response.success == true) {
// Boost granted
} else {
response.error?.let { Log.e(LOG_TAG, "Grant boost failed: ${it.code} ${it.description}") }
}
}
}

Android ProGuard​

Add these rules to your app's ProGuard/R8 rules file:

-keep class com.tapresearch.** { *; }
-dontwarn com.tapresearch.**
-keepattributes Exceptions, InnerClasses, Signature, Deprecated, SourceFile, LineNumberTable, *Annotation*, EnclosingMethod, MethodParameters, LocalVariableTable, LocalVariableTypeTable
-keepparameternames
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}

Need help?​

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


Stay updated: watch TapResearch Android SDK releases on GitHub to get notified about new SDK releases.