Android SDK (Kotlin & Java)
RapidoReach surfaces a rewarded survey offerwall inside your Android app. The SDK handles:
- Registering / identifying the user
- Checking survey availability for a placement
- Presenting the offerwall UI (WebView)
- Notifying you about offerwall lifecycle + reward events
Installation
1.1.0+
Add the dependency to your app module:
dependencies {
implementation "com.rapidoreach:cbofferwallsdk:1.1.0"
}
If you use settings.gradle dependency resolution management, ensure mavenCentral() is enabled:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
Manual installation (AAR)
You can download the latest version of the SDK from our GitHub page:
https://github.com/rapidoreach/AndroidNativeSDK
- Download the latest
.aarand copy it into your app’sapp/libs/folder. - Add the
libsfolder as a repository (project-levelbuild.gradle):
allprojects {
repositories {
google()
mavenCentral()
flatDir { dirs("app/libs") }
}
}
- Add the AAR dependency (app module
build.gradle):
dependencies {
implementation(files("libs/<SDK_FILE_NAME>.aar"))
}
- Ensure required dependencies are included (AAR installs don’t always resolve transitive dependencies reliably via
flatDir):
dependencies {
implementation "androidx.appcompat:appcompat:1.6.1"
implementation "androidx.core:core-ktx:1.12.0"
implementation "androidx.lifecycle:lifecycle-process:2.6.2"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0"
implementation "com.google.android.gms:play-services-ads-identifier:18.0.1"
implementation "com.google.android.gms:play-services-appset:16.1.0"
}
Integration
Requirements
- Minimum Android version: 23 (minSdk 23+)
- AndroidX app (AppCompat recommended)
- Gradle with
google()+mavenCentral()
Integration Checklist
- Create an app in the RapidoReach dashboard and copy your API key.
- Add the SDK dependency.
- Initialize the SDK once you have an
Activitycontext. - Wait for the SDK ready callback (or
isReady()). - Check
canShowContentForPlacement(tag)and present the offerwall. - (Optional) Send user attributes for targeting.
- (Optional) Use survey list / quick questions APIs.
- Reward users via server callback (recommended) or client-side callbacks (optional).
Get Your API Key
Create a publisher account and an Android app in the RapidoReach dashboard, then copy your API Key:
Permissions
Ensure your AndroidManifest.xml includes:
<uses-permission android:name="android.permission.INTERNET" />
Cleartext HTTP (local testing only)
If you point the SDK to an http:// backend (like a local proxy), Android 9+ requires allowing cleartext traffic.
The simplest way for dev builds is:
<application
android:usesCleartextTraffic="true"
... />
Prefer a Network Security Config for tighter control in production.
Callbacks
RapidoReach provides callbacks for readiness, content lifecycle, rewards, and errors.
Callback list (Kotlin facade)
sdkReadyCallback: called when the SDK finishes registering the user and can show content.contentCallback: called withSHOWN/DISMISSEDwhen the offerwall opens/closes.rewardCallback: called when rewards are detected (client callback mode only).errorCallback: called for initialization/runtime errors.
Callback list (Java listeners)
RapidoReachSdkReadyListener:onSdkReady()andonSdkError(code, message)RapidoReachSurveyListener:onRewardCenterOpened()/onRewardCenterClosed()RapidoReachRewardListener:onReward(quantity)RapidoReachErrorListener:onError(code, message)RapidoReachSurveyAvailableListener:rapidoReachSurveyAvailable(boolean available)
Threading
- Java listener callbacks are typically delivered on the main thread.
- Kotlin facade networking helpers (
getPlacementDetails,listSurveys,fetchQuickQuestions, etc.) return on a background thread. If you update UI, switch to the main thread.
SDK Initialization
Initialize the SDK from an Activity (it needs an activity context to launch the offerwall UI).
- Kotlin
- Java
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.rapidoreach.rapidoreachsdk.RapidoReachSdk
import com.rapidoreach.rapidoreachsdk.RrInitOptions
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
RapidoReachSdk.initialize(
apiToken = "<YOUR_API_KEY>",
userIdentifier = "<YOUR_APP_USER_ID>",
context = this,
sdkReadyCallback = { Log.d("RapidoReach", "SDK ready") },
rewardCallback = { rewards ->
rewards.forEach { r ->
Log.d("RapidoReach", "Reward: ${r.rewardAmount} ${r.currencyName ?: "coins"}")
}
},
contentCallback = { event ->
Log.d("RapidoReach", "Content event: ${event.type} placement=${event.placementTag}")
},
errorCallback = { err ->
Log.e("RapidoReach", "Error: ${err.code} ${err.description}")
},
initOptions = RrInitOptions(
navigationBarText = "Earn Rewards",
navigationBarColor = "#211548",
navigationBarTextColor = "#FFFFFF",
)
)
}
}
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.rapidoreach.rapidoreachsdk.RapidoReach;
import com.rapidoreach.rapidoreachsdk.RapidoReachConfig;
import com.rapidoreach.rapidoreachsdk.RapidoReachSdkReadyListener;
import com.rapidoreach.rapidoreachsdk.RapidoReachErrorListener;
import com.rapidoreach.rapidoreachsdk.RapidoReachRewardListener;
import com.rapidoreach.rapidoreachsdk.RapidoReachSurveyListener;
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
RapidoReachConfig config = new RapidoReachConfig.Builder("<YOUR_API_KEY>", "<YOUR_APP_USER_ID>")
.navigationBarText("Earn Rewards")
.navigationBarColor("#211548")
.navigationBarTextColor("#FFFFFF")
.build();
RapidoReach.initialize(config, this);
RapidoReach.getInstance().setRapidoReachSdkReadyListener(new RapidoReachSdkReadyListener() {
@Override public void onSdkReady() { /* SDK ready */ }
@Override public void onSdkError(String code, String message) { /* init error */ }
});
RapidoReach.getInstance().setRapidoReachErrorListener(new RapidoReachErrorListener() {
@Override public void onError(String code, String message) { /* runtime error */ }
});
RapidoReach.getInstance().setRapidoReachRewardListener(new RapidoReachRewardListener() {
@Override public void onReward(int quantity) { /* reward total callback */ }
});
RapidoReach.getInstance().setRapidoReachSurveyListener(new RapidoReachSurveyListener() {
@Override public void onRewardCenterOpened() { /* shown */ }
@Override public void onRewardCenterClosed() { /* dismissed */ }
});
}
}
Checking if SDK is ready to use
The SDK is “ready” after user registration completes.
if (RapidoReachSdk.isReady()) {
// Can show content
}
If you’re using the Java API:
if (RapidoReach.getInstance().isReady()) {
// Can show content
}
Reward callback setup additional information
RapidoReach supports two reward strategies:
- Server-side callbacks (recommended): rewards are sent to your backend callback endpoint configured in the RapidoReach dashboard.
- Client-side callbacks (optional): the SDK polls rewards and invokes
rewardCallback/RapidoReachRewardListener.
If you enable client-side callbacks, ensure your reward flow is idempotent and you do not award the user twice if you also have server callbacks enabled.
Client-side reward polling is only enabled when the backend config indicates client callback mode; otherwise the SDK will skip polling.
Reward object
The Kotlin facade uses RrReward:
| Field | Type | Notes |
|---|---|---|
rewardAmount | Int | Amount awarded (required) |
currencyName | String? | Optional display currency |
placementIdentifier | String? | Optional metadata |
placementTag | String? | Placement tag (e.g. default) |
transactionIdentifier | String? | Optional transaction id |
payoutEventType | String? | Optional payout type |
In SDK 1.1.0, the reward callback is totals-based and currently only guarantees rewardAmount (and may set placementTag). Other fields may be null.
Quick Question callback setup additional information
Unlike some SDKs that push quick questions via a callback, RapidoReach quick questions are fetched on-demand:
- Call
fetchQuickQuestions(tag) - Render your own UI based on the returned payload
- Call
answerQuickQuestion(tag, questionId, answer)
Quick Question data payload object
Quick question APIs return RrQuickQuestionPayload:
| Field | Type | Notes |
|---|---|---|
data | Map<String, Any?> | Raw payload returned by backend |
The payload is intentionally unopinionated so the backend can evolve the schema. Treat it as a JSON-like map and safely unwrap values.
Error callbacks
Errors can happen during initialization, networking, or UI presentation.
- Kotlin: handle via the
errorCallbackpassed toRapidoReachSdk.initialize. - Java: handle via
RapidoReachErrorListenerand initialization failures viaRapidoReachSdkReadyListener.onSdkError(...).
RrError object
RapidoReach exposes an RrError object:
| Field | Type | Notes |
|---|---|---|
code | String | Machine-readable error code |
description | String? | Human-readable message |
Common error codes you may see from the Android SDK:
MISSING_PARAMS(missing API token or user id)MISSING_ACTIVITY(initialization requires an Activity context)MISSING_APPUSER_ID(registration failed)NOT_READY(SDK not ready yet)NO_CONTENT(no content available)SHOW_FAILED(offerwall failed to open)INVALID_PARAMS(invalid/reserved parameters)NETWORK(request failed)
Send User attributes
Send user attributes to improve survey targeting.
Attribute keys prefixed with tapresearch_ are reserved and will be rejected.
RapidoReachSdk.sendUserAttributes(
attributes = mapOf("age" to 25, "gender" to "male", "premium_user" to true),
clearPrevious = false
) { err ->
if (err != null) {
Log.e("RapidoReach", "sendUserAttributes failed: ${err.code} ${err.description}")
}
}
Setting the user identifier
If your app user changes (login/logout), update the SDK. This will re-register the SDK user; wait for the ready callback again before showing content.
RapidoReachSdk.setUserIdentifier("<NEW_APP_USER_ID>") { err ->
Log.e("RapidoReach", "setUserIdentifier error: ${err.code} ${err.description}")
}
Java equivalent:
RapidoReach.getInstance().updateUserIdentifier("<NEW_APP_USER_ID>");
Displaying a placement
Placements are referenced by a placement tag (often "default").
Checking if the placement is available
Kotlin:
val canShow = RapidoReachSdk.canShowContentForPlacement("default") { err ->
Log.d("RapidoReach", "Not available: ${err.code} ${err.description}")
}
Java:
boolean canShow = RapidoReach.getInstance().isSurveyAvailable();
In SDK 1.1.0, availability is currently based on the last registration state and may not be fully per-placement on the client side.
Showing the placement
Kotlin:
RapidoReachSdk.showContentForPlacement("default")
Java:
RapidoReach.getInstance().showRewardCenter("default");
Passing custom parameters
Custom parameters are currently supported for direct survey flows (showSurvey). They are not guaranteed to affect the standard offerwall (showContentForPlacement) in SDK 1.1.0.
Rules:
- Keep values JSON-like (
String,Int,Double,Boolean, nested maps/lists) - Keep the payload small
RapidoReachSdk.showSurvey(
tag = "default",
surveyId = "<SURVEY_ID>",
customParameters = mapOf("sub_id" to "12345", "screen" to "home"),
)
Getting Placement Details
Fetch basic placement metadata (when available) from the backend:
RapidoReachSdk.getPlacementDetails("default") { result ->
result.fold(
onSuccess = { details -> Log.d("RapidoReach", "Placement: $details") },
onFailure = { err -> Log.e("RapidoReach", "Placement details error: ${err.message}") }
)
}
RrPlacementDetails object
getPlacementDetails returns an RrPlacementDetails. Fields are optional and may be null depending on what your backend/account returns.
| Field | Type | Notes |
|---|---|---|
name | String? | |
currencyName | String? | Virtual currency display name (if configured) |
Survey List & Specific Surveys
These APIs are useful if you want to preview surveys or deep-link into a specific survey.
RapidoReachSdk.listSurveys("default") { result ->
result.fold(
onSuccess = { surveys -> Log.d("RapidoReach", "Surveys: $surveys") },
onFailure = { err -> Log.e("RapidoReach", "listSurveys error: ${err.message}") }
)
}
Check if a specific survey can be shown:
RapidoReachSdk.canShowSurvey("default", "<SURVEY_ID>") { result ->
result.fold(
onSuccess = { /* can show */ },
onFailure = { err -> Log.d("RapidoReach", "canShowSurvey: ${err.message}") }
)
}
Show a specific survey. The SDK will open the returned entry URL inside its WebView:
RapidoReachSdk.showSurvey(
tag = "default",
surveyId = "<SURVEY_ID>",
customParameters = mapOf("sub_id" to "12345"),
)
Quick Questions
Fetch quick questions for a placement:
RapidoReachSdk.fetchQuickQuestions("default") { result ->
result.fold(
onSuccess = { payload -> Log.d("RapidoReach", "Quick questions: ${payload.data}") },
onFailure = { err -> Log.d("RapidoReach", "No quick questions: ${err.message}") }
)
}
Answer a quick question:
RapidoReachSdk.answerQuickQuestion(
tag = "default",
questionId = "<QUESTION_ID>",
answer = "yes",
) { result ->
result.fold(
onSuccess = { payload -> Log.d("RapidoReach", "Answer response: ${payload.data}") },
onFailure = { err -> Log.e("RapidoReach", "answerQuickQuestion error: ${err.message}") }
)
}
Rewards
Server-side callbacks (recommended)
For fraud prevention and idempotency, reward your users on your server using your RapidoReach callback endpoint configured in the dashboard.
Client-side rewards (optional)
If your app is configured for client callback mode, the SDK can invoke rewardCallback (Kotlin) / RapidoReachRewardListener (Java).
If you enable client-side rewards, ensure your reward flow is idempotent. Do not award the user twice if you also have a server callback configured.
Android Proguard
If you use R8/ProGuard, add:
-keep class com.rapidoreach.rapidoreachsdk.** { *; }
Best Practices
- Initialize in the first screen where you have an
Activitycontext. - Wait for
sdkReadyCallback(orisReady()) before showing content. - Always check availability before presenting the offerwall.
- Present the offerwall only when your activity is in a safe state (avoid showing while finishing / during configuration changes).
Troubleshooting
MISSING_ACTIVITY: you calledRapidoReachSdk.initializewith a non-Activity context.NOT_READY: initialization hasn’t completed; wait forsdkReadyCallback.NO_CONTENT: no content available for the placement at the moment.