Android SDK
Add the RevenueHog Kotlin SDK to an Android app to identify users, attach attributes, map Play purchases to users and serve paywall SKUs from the dashboard.
The Android SDK (com.revenuehog:revenuehog-android) is a Kotlin library with zero runtime dependencies: it uses HttpURLConnection and org.json, which ship with the platform.
Requirements
- minSdk 24, compileSdk 35, Java 11.
- The
INTERNETpermission. - An app in your workspace whose package name matches. RevenueHog resolves Android writes to a connected Google Play app with that package first, then to an App Store app with the same ID. See Google Play.
Install
The artifact is not on Maven Central yet. Publish it to your local Maven repository from a checkout of the SDK repository:
git clone https://github.com/Parra-Inc/revenue-hog-sdks
cd revenue-hog-sdks/kotlin
./gradlew :revenuehog-android:publishToMavenLocalThen add mavenLocal() to your repositories and depend on it:
dependencies {
implementation("com.revenuehog:revenuehog-android:0.2.0")
}You can also include the module from source.
Quickstart
Configure in Application.onCreate()
class App : Application() {
override fun onCreate() {
super.onCreate()
RevenueHog.configure(this)
}
}Identify users
RevenueHog.identify("user_42") // after login
RevenueHog.reset() // on logoutAttribute purchases
Wrap your Play Billing listener:
val listener = RevenueHog.billingListener(myListener) as PurchasesUpdatedListener
val billingClient = BillingClient.newBuilder(context)
.setListener(listener)
.enablePendingPurchases()
.build()Or call attributePurchase from your own listener:
override fun onPurchasesUpdated(result: BillingResult, purchases: List<Purchase>?) {
purchases?.forEach { purchase ->
RevenueHog.attributePurchase(
purchaseToken = purchase.purchaseToken,
productId = purchase.products.firstOrNull(),
)
}
}How auth works
There is no API key and no attestation on Android yet (Play Integrity is planned). Requests carry no Authorization header and go through the quarantine path: RevenueHog accepts them when the package name resolves to exactly one app and labels the data unverified. See Authentication.
Play purchase tokens
attributePurchase sends the Play purchaseToken as originalTransactionId. When the write resolves to a Google Play app, the server stores the token as the subscription's lineage key, the ID every Play event of that subscription carries, so the attribution joins the customer in the live feed. Older SDK builds that send no platform on attribute calls are still recognized: a long non-numeric ID is treated as a Play token.
SDK README versus server
The SDK's README still describes Play ingestion as future work. The server now ingests Google Play through Google Play and joins SDK attributions to Play customers as described above.
API reference
All public calls are fire-and-forget onto a single background daemon thread named revenuehog. None throw.
| Call | What it does |
|---|---|
RevenueHog.configure(context, options = Options()) | Sets up the SDK and flushes the offline queue. Call once in Application.onCreate(). |
RevenueHog.identify(userId) | Links the anonymous ID, and every purchase reported under it, to your user ID. Clears the paywall cache when the user changes. |
RevenueHog.setAttributes(map) | Attaches a flat Map<String, String> to the user's profile. |
RevenueHog.attributePurchase(purchaseToken, productId?) | Links a Play purchase to the current user. |
RevenueHog.billingListener(delegate?) | Returns a PurchasesUpdatedListener proxy that attributes every purchase and then calls your delegate. Built with reflection, so the SDK never depends on Play Billing. If Play Billing is not on the classpath, returns delegate unchanged. |
RevenueHog.reset() | Forgets the user on logout and issues a fresh anonymous ID. |
RevenueHog.flush() | Retries the offline queue. |
RevenueHog.paywall(entitlement, fallback, forceVariant?, onResult) | Fetches the ordered SKU list. onResult runs on the SDK thread. See Paywall. |
RevenueHog.paywallShown(paywall, rendered) | Reports that the paywall appeared, with the product IDs that rendered. |
All methods are @JvmStatic, so Java callers use RevenueHog.identify("user_42").
Options
RevenueHog.configure(this, Options(
baseUrl = "https://hog.internal.example",
logLevel = LogLevel.DEBUG,
))Prop
Type
Paywall and PaywallSku
data class PaywallSku(val productId: String, val kind: String) // "subscription", "iap" or "unknown"
data class Paywall(
val entitlement: String,
val skus: List<PaywallSku>,
val experimentId: String? = null,
val variantKey: String? = null,
val isFallback: Boolean,
) { val productIds: List<String> }RevenueHog.paywall("pro", listOf("com.example.pro.annual", "com.example.pro.monthly")) { paywall ->
// runs on the SDK thread: hop to main before touching views
// query Play Billing with paywall.productIds, re-sort to that order, render
RevenueHog.paywallShown(paywall, renderedProductIds)
}The paywall fetch uses a 2.5 second connect and read timeout. If paywall is called before configure, onResult receives the fallback immediately.
What is stored
Everything lives in the SharedPreferences file dev.revenuehog.sdk: user ID (rh_user_id), anonymous ID (rh_anon_id), sent purchases (rh_sent_txns), install ID (rh_install_id), paywall cache (rh_paywall_cache) and the offline queue (rh_queue, cap 100).
What is sent
Your user ID or anonymous ID, the package name as bundleId, platform: "android", OS version (Build.VERSION.RELEASE), device model (Build.MODEL), locale and the attributes you pass. No advertising ID.
Behavior notes
- Failed requests (network error,
429,5xx) retry up to 3 times with backoff of 500 ms then 1 s, then queue. Other non-2xx responses are dropped. - The SDK skips purchases already reported for the current user.
- The Android SDK does not send
environmenton paywall fetches, so the server treats them as Production.
Troubleshooting
Filter by tag RevenueHog and pass Options(logLevel = LogLevel.DEBUG).
Expected for this SDK until attestation support ships.
Check that the package name matches an app in your workspace exactly. Unknown or ambiguous package names are accepted with 200 and dropped.
Related
Last updated on
iOS SDK
Install the RevenueHog Swift package, enable App Attest, and attribute StoreKit 2 purchases to your users automatically with one line of code at app launch.
React Native SDK
Add the pure JavaScript RevenueHog SDK to a React Native or Expo app, including Expo Go, to attribute purchases, identify users and serve paywall SKUs.