Android SDK
The Android SDK is currently in beta. Public types under net.linksense.sdk.* may change between 0.x releases. Pin to an exact version in production (implementation("net.linksense:sdk:0.1.0")) and review the changelog before upgrading. We commit to API stability at 1.0.
Overview
The LinkSense Android SDK delivers four capabilities:
- Install-time attribution — match a user's post-install session to the link they tapped before installing your app, including Play Install Referrer when available.
- Deferred deep linking — surface the original link URL via a callback after install.
- App Link forwarding — handle
ACTION_VIEWintents and resolve them to your in-app routing. - Link CRUD — create, read, update, and delete dynamic links directly from the device.
The SDK has no Google Play Services dependency. The only Play-adjacent code is com.android.installreferrer (AIDL, not GMS) — and only when enableInstallReferrer = true. It does not collect AAID, ANDROID_ID, IMEI, MAC, or the clipboard.
Prerequisites
minSdk24 (Android 7.0)- JVM target 11, Kotlin 2.0+
- An SDK key from your LinkSense project (Project Settings → SDK Keys)
- App Links configured for your project subdomain (see Android Deep Linking)
Installation
The SDK is published on Maven Central as net.linksense:sdk. Add it to your app module's build.gradle.kts:
dependencies { implementation("net.linksense:sdk:0.1.0")}Make sure mavenCentral() is in your repositories block (it is by default in modern Gradle projects).
Configuration
Configure the SDK in your Application.onCreate()so it's ready before any Activity launches:
class MyApp : Application() { override fun onCreate() { super.onCreate() LinkSense.configure( this, LinkSenseConfiguration( sdkKey = "ls_sdk_<project>_<random>", enableInstallReferrer = true, logLevel = LogLevel.OFF, ), ) LinkSense.start() }}Don't forget to register your Application subclass in AndroidManifest.xml:
<application android:name=".MyApp" ...></application>Configuration fields:
| Field | Type | Required | Description |
|---|---|---|---|
sdkKey | String | Yes | Your project SDK key (format: ls_sdk_<project>_<random>). Generate one in Project Settings → SDK Keys. |
enableInstallReferrer | Boolean | No | Use Google Play Install Referrer for high-confidence attribution. Requires the app to be installed via Play. Default true. |
logLevel | LogLevel | No | Diagnostic logging level (OFF, ERROR, WARN, INFO, DEBUG). Default OFF — recommended for production. |
Subsequent calls to configure after the first are no-ops by design. The SDK reuses the same install idempotency key across cold starts to prevent double-attribution.
Handling Deferred Deep Links
Register a handler to receive the original dynamic link URL once attribution resolves. The callback fires on the main thread (Looper.getMainLooper()).
LinkSense.onDeferredDeepLink { uri -> uri?.let { router.handle(it) }}If enableInstallReferrer is true and the app was installed via Google Play, the SDK uses the Install Referrer click id for high-confidence attribution. Otherwise it falls back to probabilistic fingerprint matching.
Forwarding App Links
When your app is opened via an App Link tap (warm path), forward the intent to the SDK so it can resolve the link target:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) LinkSense.handleIntent(intent) { uri -> uri?.let { router.handle(it) } } } override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) LinkSense.handleIntent(intent) { uri -> uri?.let { router.handle(it) } } }}For Digital Asset Links (assetlinks.json) hosting and the autoVerify intent filter, see Android Deep Linking.
Link CRUD
The SDK exposes createLink, getLink, updateLink, and deleteLink as suspend functions. Call them from a coroutine scope:
lifecycleScope.launch { try { val link = LinkSense.createLink( CreateLinkOptions( name = "Summer sale", desktopUrl = "https://example.com/sale", androidFallbackUrl = "https://play.google.com/store/apps/details?id=com.example.myapp", ) ) println("Created: ${link.url}") } catch (e: LinkSenseError) { println("Failed: $e") }}UpdateLinkOptions uses FieldUpdate<T> with three variants: FieldUpdate.Absent (don't send the field), FieldUpdate.Set(value) (send a new value), or FieldUpdate.Clear (explicitly null the field server-side).
Error Handling
All CRUD methods throw LinkSenseError — a sealed class mapping server error codes to typed subtypes:
try { val link = LinkSense.getLink("ln_abc123") // use link} catch (e: LinkSenseError) { when (e) { is LinkSenseError.NotConfigured -> println("Call configure() first") is LinkSenseError.Network -> println("Network failure: ${e.cause}") is LinkSenseError.RateLimited -> println("Retry after ${e.retryAfter}s") is LinkSenseError.Server -> println("Server ${e.code}: ${e.message}") else -> println("Other error: $e") }}Common subtypes: NotConfigured, InvalidSdkKey, Network, Unauthorized, ForbiddenCrossScope, ForbiddenField, InvalidInput, NotFound, CustomPathExists, RateLimited, Server.
Example & Resources
The Android SDK repository ships with a Kotlin/Compose sample app demonstrating configuration, deferred deep link handling, App Link forwarding, and link CRUD.