The Uptick Android SDK renders Uptick offers natively in your Kotlin app. It supports the same features as the iOS SDK :
sdk_order_confirmation (popup) and sdk_order_status (inline). See
Placements
.
Add the Uptick Maven repository to your settings.gradle:
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() maven { url "https://sdk.uptick.com/maven" } } }
Add the dependency to your app-level build.gradle:
dependencies { implementation 'com.uptick:uptick-android:1.1.5' }
Each screen that shows offers needs a placement in the Uptick dashboard, and your app passes the matching value when it starts the offer flow.
| Placement | Placement value |
Screen | Render type |
|---|---|---|---|
sdk_order_confirmation |
Placement.SDK_ORDER_CONFIRMATION |
The screen shown right after the order is placed | popup |
sdk_order_status |
Placement.SDK_ORDER_STATUS |
An order status or order details screen | inline |
The placement’s configuration in the dashboard decides whether its offers render as a popup or inline. The SDK reads the render type from the flow and tells your app through onRenderTypeReceived, so the same code handles both.
Add two FrameLayout containers to your layout:
uptickPopup hosts popup offers. It covers the whole screen and sits above your content; the SDK draws the dimmed overlay inside it.
uptickInline hosts inline offers, where an inline offer belongs in your content.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Thanks for your order!" /> <FrameLayout android:id="@+id/uptickInline" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> <FrameLayout android:id="@+id/uptickPopup" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
Create an UptickManager and a FrameLayout for the SDK to render into. Keep both for the life of the screen.
val uptickManager = UptickManager() val uptickView = FrameLayout(this)
onRenderTypeReceived is called on the main thread before each offer is shown. Its RenderTypeInfo has the renderType, "popup" or "inline". Move uptickView into the matching container:
uptickManager.onRenderTypeReceived = { info -> (uptickView.parent as? ViewGroup)?.removeView(uptickView) if (info.renderType == "popup") { findViewById<FrameLayout>(R.id.uptickPopup).addView(uptickView) } else { findViewById<FrameLayout>(R.id.uptickInline).addView(uptickView) } }
When the flow ends, because the user closed it or there are no more offers, the SDK removes the offer from uptickView.
Call initiateView to start the offer flow.
integrationId: The ID of your integration.
siteUrl: The full URL of your site, including https://, e.g. https://www.example.com/. It is sent as dl on every request, so offers, site targeting and site blocking resolve to your site.
placement: The Placement for this screen. See
Placements
.
optionalParams: Any other parameters. They are the same as on the web; see the
Parameter List
.
initiateView throws an IllegalArgumentException and starts no flow if siteUrl is not a full http(s) URL.
import com.uptick.sdk.v1.model.Placement uptickManager.initiateView( context = this, container = uptickView, integrationId = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE", siteUrl = "https://www.example.com/", placement = Placement.SDK_ORDER_CONFIRMATION, optionalParams = mapOf( "first_name" to "Rebecca", "order_id" to "12345", "total_price" to "49.99" ) )
Set these callbacks on uptickManager before you call initiateView. They are called on the main thread.
| Callback | When it is called |
|---|---|
onOfferReceived |
An offer is ready to show. |
onOfferViewed |
The offer was shown to the user. |
onOfferAccepted |
The user accepted the offer. |
onOfferRejected |
The user rejected the offer. |
uptickManager.onOfferReceived = { offer -> Log.d("Uptick", "Received offer ${offer.position} of ${offer.total}") } uptickManager.onOfferViewed = { offer -> Log.d("Uptick", "Viewed offer ${offer.id}") } uptickManager.onOfferAccepted = { offer -> Log.d("Uptick", "Accepted offer ${offer.id}") } uptickManager.onOfferRejected = { offer -> Log.d("Uptick", "Rejected offer ${offer.id}") }
Each offer callback receives an UptickDataModel:
| Property | Type | Description |
|---|---|---|
id |
String |
The ID of the offer. |
position |
String |
The position of the offer in the flow, starting at 1. |
total |
String |
The number of offers in the flow. |
onError is called on the main thread when the offer flow fails, for example when a request fails or the response can’t be read.
onError is for logging and monitoring only. When an offer fails, the SDK doesn’t show the user an error, and your app shouldn’t either: as on the web, a failed offer simply shows nothing.
uptickManager.onError = { errorMessage -> Log.w("Uptick", "Offer failed: $errorMessage") }
Set these properties on uptickManager before you call initiateView. Each takes a color Int.
| Property | Default | Used for |
|---|---|---|
primaryColor |
Green (#5bb85d) |
The accept button and highlighted text. The integration’s highlight color, when set in the dashboard, takes precedence. |
secondaryColor |
Light gray (#efefef) |
The reject button, borders and other secondary elements. |
cardBgColor |
White | The offer’s background. |
bgColor |
Semi-transparent black (#4D000000) |
The dimmed overlay behind a popup offer. |
unselectedDigitColor |
Light gray (#efefef) |
The progress indicator’s inactive steps. |
uptickManager.primaryColor = Color.parseColor("#4f46e5") uptickManager.secondaryColor = Color.parseColor("#e5e7eb") uptickManager.cardBgColor = Color.WHITE
A complete order confirmation activity, using the layout from step 1:
import android.os.Bundle import android.util.Log import android.view.ViewGroup import android.widget.FrameLayout import androidx.appcompat.app.AppCompatActivity import com.uptick.sdk.apputils.UptickManager import com.uptick.sdk.v1.model.Placement class OrderConfirmationActivity : AppCompatActivity() { private val uptickManager = UptickManager() private lateinit var uptickView: FrameLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_order_confirmation) uptickView = FrameLayout(this) uptickManager.onRenderTypeReceived = { info -> (uptickView.parent as? ViewGroup)?.removeView(uptickView) if (info.renderType == "popup") { findViewById<FrameLayout>(R.id.uptickPopup).addView(uptickView) } else { findViewById<FrameLayout>(R.id.uptickInline).addView(uptickView) } } uptickManager.onError = { errorMessage -> // Log only; don't show the user an error for a failed offer. Log.w("Uptick", "Offer failed: $errorMessage") } uptickManager.initiateView( context = this, container = uptickView, integrationId = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE", siteUrl = "https://www.example.com/", placement = Placement.SDK_ORDER_CONFIRMATION, optionalParams = mapOf("first_name" to "Rebecca") ) } }
For an inline offer on an order status screen, use the same code with placement = Placement.SDK_ORDER_STATUS.
siteUrl is your site’s full URL. Check onError for failures.