Docs

API reference

Every public class, method, property and enum in lander-android 0.1.0.

Everything public is in the link.lander.android package:

import link.lander.android.*
TypeKind
LanderEntry point (a Kotlin object; static methods from Java)
LanderLinkA link delivered to the app
LanderShortLinkA link created with createLink
LanderLinkOptionsThe fields of a link to create, with a builder for Java
LanderConfidenceEnum: how sure Lander is
LanderExceptionError from calls that need the API
LanderLinkListener, LanderSubscription, LanderCallbackCallback types for Java

Lander

object Lander

Kotlin calls members on Lander directly. From Java, every non suspending member is a static method (Lander.handleIntent(intent)); suspending functions have callback overloads.

Lander.VERSION

const val VERSION: String // "0.1.0"

The SDK version, sent as sdkVersion in the launch report and as X-Lander-Sdk: android/0.1.0 on every request.

Lander.DEFAULT_BASE_URL

const val DEFAULT_BASE_URL: String // "https://api.golander.link"

Lander.initialize

@JvmStatic @JvmOverloads
fun initialize(
    context: Context,
    apiKey: String,
    baseUrl: String = DEFAULT_BASE_URL,
    enableLogging: Boolean = false,
)

Starts the SDK. Call it once, in Application.onCreate. Returns immediately; the install ID is loaded and the launch reported with POST /v1/sdk/init in the background.

Prop

Type

  • Throws IllegalArgumentException when apiKey, trimmed, is a secret key or not a publishable key (pk_test_ or pk_live_ followed by at least 24 letters or digits). The key is never included in the message.
  • Never throws for network errors.
  • A second call is ignored.
  • Registers activity lifecycle callbacks on the Application: events are flushed when the app goes to the background, a failed first launch report is retried when it comes back, and links of activities restored after process death are not delivered again.

Lander.handleIntent

@JvmStatic
fun handleIntent(intent: Intent?)

Hands an intent to Lander. Call it from onCreate and onNewIntent of every activity with Lander intent filters.

  • Reads the URL of ACTION_VIEW intents; other intents carry no link. The first call of the process tells the SDK whether the app was launched by a link.
  • Marks the intent with an extra, so a recreated activity (rotation, process death, Recents) does not deliver the link again. Intents with FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY are ignored.
  • The same URL twice within two seconds counts once.
  • Safe before initialize: the link is kept until the SDK starts. Any thread.
@JvmStatic
val deepLinks: Flow<LanderLink>

Every link the app receives: App Links, custom scheme URLs and deferred links.

  • Safe to collect at any time, even before initialize.
  • Links that arrive while nobody collects are buffered and replayed, in order, to the next collector.
  • Every active collector gets live links; buffered links go to the first one.
  • Includes the launch link unless getInitialLink claimed it first.
  • Unknown links and links that could not be resolved are delivered with isResolved == false and only the URI set.
  • Does not include links returned by claimHandoff.

Lander.addDeepLinkListener

@JvmStatic
fun addDeepLinkListener(listener: LanderLinkListener): LanderSubscription

deepLinks for Java or Kotlin without coroutines. The listener is called on the main thread, starting with buffered links. Call remove() on the returned subscription to stop.

suspend fun getInitialLink(): LanderLink?

@JvmStatic
fun getInitialLink(callback: LanderCallback<LanderLink?>)

The link that launched the app, or null. Waits until the launch intent reached handleIntent (or the first activity resumed), then for the resolve request when the app was opened by a link, and on a first launch for the launch report (a deferred link may come back). Delivered once: returns null if deepLinks or an earlier call already delivered it, and after this call deepLinks will not deliver it.

Throws IllegalStateException before initialize.

suspend fun createLink(
    path: String = "/",
    params: Map<String, Any> = emptyMap(),
    title: String? = null,
    campaign: String? = null,
    channel: String? = null,
    tags: List<String> = emptyList(),
    iosFallbackUrl: String? = null,
    androidFallbackUrl: String? = null,
    webFallbackUrl: String? = null,
    ogTitle: String? = null,
    ogDescription: String? = null,
    ogImageUrl: String? = null,
    expiresAt: Date? = null,
): LanderShortLink

suspend fun createLink(options: LanderLinkOptions): LanderShortLink

@JvmStatic
fun createLink(options: LanderLinkOptions, callback: LanderCallback<LanderShortLink>)

Creates a short link with POST /v1/sdk/links. The slug is random and the domain is the project's default domain.

Prop

Type

  • Throws IllegalArgumentException when path does not start with / or a params value is not a String, Number or Boolean.
  • Throws LanderException when the request fails. Retries network errors, timeouts, 408, 429 (except link_quota_exceeded) and 5xx up to 3 attempts with one Idempotency-Key, waiting at most 10 seconds in total.
  • Throws IllegalStateException before initialize.

Lander.claimHandoff

suspend fun claimHandoff(userId: String): LanderLink?

@JvmStatic
fun claimHandoff(userId: String, callback: LanderCallback<LanderLink?>)

After sign in, returns the link your backend bound to userId with POST /v1/handoffs, or null when nothing is pending. The link has isDeferred == true, confidence == DETERMINISTIC and method == "authenticated_handoff". It is returned only, never also emitted on deepLinks.

  • Throws IllegalArgumentException when userId, trimmed, is empty or longer than 256 characters.
  • Throws LanderException when the request fails after retries, or with code install_not_registered when the install could not be reported to Lander yet.
  • Throws IllegalStateException before initialize.

Lander.trackEvent

@JvmStatic @JvmOverloads
fun trackEvent(name: String, properties: Map<String, Any?> = emptyMap(), linkId: String? = null)

Records a custom event. Fire and forget: validates, queues and returns. Events are stored on the device and sent in batches of up to 100 to POST /v1/sdk/events, with retries.

  • Throws IllegalArgumentException for a name that is empty or over 100 characters, a linkId that is not a UUID, or properties that are not JSON values.
  • Never throws for network errors.
  • Throws IllegalStateException before initialize.

Lander.installId

@JvmStatic
val installId: String?

The random UUID v4 of this install, once loaded (shortly after initialize). Stored in noBackupFilesDir, so it never moves to another device.

class LanderLink(
    val uriString: String,
    val linkId: String? = null,
    val url: String? = null,
    val path: String? = null,
    val params: Map<String, Any> = emptyMap(),
    val campaign: String? = null,
    val channel: String? = null,
    val isDeferred: Boolean = false,
    val confidence: LanderConfidence = LanderConfidence.UNATTRIBUTED,
    val method: String? = null,
)

A link delivered to the app. When Lander knows the link, the fields mirror the API's ResolvedLink; otherwise only the URI is set.

PropertyTypeMeaning
uriStringStringThe URL that opened the app, exactly as Android delivered it. For a deferred link, the link's own URL.
uriUriuriString parsed as an android.net.Uri.
linkIdString?Lander link ID, or null when unknown to Lander.
urlString?Canonical short link.
pathString?The in app route set on the link.
paramsMap<String, Any>Link params with the opened URL's query parameters merged over them. Values are String, Number or Boolean.
campaign, channelString?Attribution labels.
isDeferredBooleanRecovered after an install or handed off after sign in.
confidenceLanderConfidenceHow sure Lander is.
methodString?app_link, universal_link, install_referrer, landing_page, authenticated_handoff or probabilistic_match. null when unresolved.
isResolvedBooleanlinkId != null.
routeStringpath when resolved, otherwise the raw URL's path and query; for custom scheme URLs the host is the first path segment (acmeshop://product/123 gives /product/123).

LanderLink.unresolved(uri: String) builds an unresolved link, handy in tests. equals compares every field; toString() summarizes the link for logs.

class LanderShortLink(
    val id: String,
    val url: String,
    val domain: String,
    val slug: String,
    val path: String,
    val params: Map<String, Any> = emptyMap(),
    val title: String? = null,
    val campaign: String? = null,
    val channel: String? = null,
    val tags: List<String> = emptyList(),
    val expiresAt: Date? = null,
    val createdAt: Date? = null,
)

A link created with createLink. uri is url as an android.net.Uri. toString() returns url. Two short links are equal when id and url are.

LanderLinkOptions

class LanderLinkOptions private constructor(...) {
    class Builder {
        fun path(path: String): Builder
        fun param(key: String, value: Any): Builder
        fun params(params: Map<String, Any>): Builder
        fun title(title: String?): Builder
        fun campaign(campaign: String?): Builder
        fun channel(channel: String?): Builder
        fun tags(tags: List<String>): Builder
        fun iosFallbackUrl(url: String?): Builder
        fun androidFallbackUrl(url: String?): Builder
        fun webFallbackUrl(url: String?): Builder
        fun ogTitle(title: String?): Builder
        fun ogDescription(description: String?): Builder
        fun ogImageUrl(url: String?): Builder
        fun expiresAt(date: Date?): Builder
        fun build(): LanderLinkOptions
    }
}

The same fields as createLink's parameters, readable as properties. build() throws IllegalArgumentException for a path without a leading / or a param value that is not a String, Number or Boolean.

LanderConfidence

enum class LanderConfidence(val wireName: String) {
    DETERMINISTIC("deterministic"),
    PROBABILISTIC("probabilistic"),
    UNATTRIBUTED("unattributed"),
}
ValueMeaning
DETERMINISTICMatched by an exact identifier: an App Link open, a Play Install Referrer token, the Continue in app page or an authenticated handoff.
PROBABILISTICMatched by coarse signals within a short window. Only for iOS deferred links of projects that opted in.
UNATTRIBUTEDNo link could be tied to this open. Unresolved links always have this.

LanderConfidence.parse(value) maps the API's string to a value, with anything unknown as UNATTRIBUTED.

LanderException

class LanderException(
    val code: String,
    override val message: String,
    val statusCode: Int? = null,
    val retryAfter: kotlin.time.Duration? = null,
) : Exception(message)

Thrown by calls that need an answer from the API (createLink, claimHandoff). initialize and trackEvent never throw it.

PropertyMeaning
codeThe API's error code (for example rate_limited), or network_error, timeout, invalid_response or install_not_registered for client side failures.
messageHuman readable.
statusCodeHTTP status, or null when no response was received.
retryAfterThe server's Retry-After, when it sent one.
retryAfterMillisretryAfter in milliseconds, for Java.
isRetryabletrue for no response, invalid_response, 408, 429 (except link_quota_exceeded) and 5xx.

Java callbacks

fun interface LanderLinkListener {
    fun onDeepLink(link: LanderLink)
}

fun interface LanderSubscription {
    fun remove()
}

interface LanderCallback<T> {
    fun onSuccess(result: T)
    fun onError(error: Exception)
}

Listeners and callbacks are called on the main thread. onError receives a LanderException for API and network failures, or an IllegalArgumentException / IllegalStateException for programming errors.

On this page