> ## Documentation Index
> Fetch the complete documentation index at: https://learn.biq.li/llms.txt
> Use this file to discover all available pages before exploring further.

# Android SDK

> Install and use the Biqli Android SDK for verified App Links and Google Play deferred attribution.

<Warning>
  The Android SDK is in **Public Beta**. It supports Android API 23 and later. Validate deferred installation through a Google Play test track before production use.
</Warning>

The open-source Kotlin-first SDK is published on Maven Central as `li.biq:biqli-android`.

## Install

```kotlin theme={null}
dependencies {
    implementation("li.biq:biqli-android:1.0.0")
}
```

The package transitively includes Google Play Install Referrer `2.2`. It requests only `android.permission.INTERNET`; it does not request Advertising ID, location, contacts, or storage permissions.

* [Source and releases](https://github.com/BiqliLLC/biqli-android)
* [Maven Central package](https://central.sonatype.com/artifact/li.biq/biqli-android/1.0.0)
* [Google Play Install Referrer documentation](https://developer.android.com/google/play/installreferrer)

## Configure

Call `Biqli.configure` once before resolving attribution, normally from `Application.onCreate` or the first activity:

```kotlin theme={null}
Biqli.configure(
    context = applicationContext,
    appId = "biq_mapp_01ARZ3NDEKTSV4RRFFQ69G5FAV",
    publishableKey = "biqli_mobile_pk_your_public_mobile_key",
)
```

| `BiqliConfiguration` property | Type                       | Default                 | Description                                                                      |
| :---------------------------- | :------------------------- | :---------------------- | :------------------------------------------------------------------------------- |
| `appId`                       | `String`                   | Required                | Public Mobile App ID beginning with `biq_mapp_`.                                 |
| `publishableKey`              | `String`                   | Required                | Public app-scoped key beginning with `biqli_mobile_pk_`.                         |
| `apiBaseUrl`                  | `String`                   | `https://biq.li/api/v1` | HTTPS API base without credentials, query, or fragment.                          |
| `consentRequired`             | `Boolean`                  | `false`                 | Prevent Install Referrer access and resolver requests until consent is supplied. |
| `diagnosticsEnabled`          | `Boolean`                  | `false`                 | Enable bounded SDK diagnostic events.                                            |
| `diagnosticListener`          | `BiqliDiagnosticListener?` | `null`                  | Receives status enums without tokens, keys, URLs, or payloads.                   |

The `appId` and mobile key must come from the same registered Mobile App. Never embed a `biqli_...` secret workspace API key.

## Declare the App Link

Add an intent filter for every attached hostname to the activity that receives the link:

```xml theme={null}
<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data
        android:scheme="https"
        android:host="go.example.com"
        android:pathPrefix="/" />
</intent-filter>
```

The public `assetlinks.json` package and SHA-256 certificate must match the installed build. A local debug key and Google Play App Signing key are different certificates.

## Resolve with coroutines

```kotlin theme={null}
lifecycleScope.launch {
    try {
        val result = Biqli.resolveAttribution(intent)
        result.link?.route?.let(router::open)

        // Send a live receipt to your trusted backend before granting a reward.
        result.attributionReceipt?.let(backend::verifyReceipt)
    } catch (error: BiqliException) {
        // Keep startup non-blocking. Retry pending work on a later cold launch.
    }
}
```

Use a `singleTop` activity to forward a new verified link:

```kotlin theme={null}
override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    lifecycleScope.launch {
        Biqli.resolveAttribution(intent)
    }
}
```

Call resolution on each cold launch. `Biqli.handleAppLink(intent)` captures a verified HTTPS intent without resolving it. `Biqli.attributionFlow(intent, consentGranted)` emits the same single resolution through a Kotlin `Flow`.

## Java callback API

```java theme={null}
Biqli.configure(
    getApplicationContext(),
    "biq_mapp_01ARZ3NDEKTSV4RRFFQ69G5FAV",
    "biqli_mobile_pk_your_public_mobile_key"
);

Biqli.resolveAttribution(getIntent(), true, new BiqliAttributionCallback() {
    @Override public void onSuccess(BiqliAttributionResult result) {
        // Read result.getOpen(), result.getLink(), and result.getAttribution().
    }

    @Override public void onError(BiqliException error) {
        // Retry transient pending work on a later launch.
    }
});
```

Callbacks run on the main thread.

## Result model

`BiqliAttributionResult` contains:

| Property             | Type           | Meaning                                                                  |
| :------------------- | :------------- | :----------------------------------------------------------------------- |
| `open`               | `Open`         | Open ID, first-open flag, `MatchType`, and `Confidence`.                 |
| `click`              | `Click?`       | Matched click ID, or `null`.                                             |
| `link`               | `Link?`        | Link ID, short URL, and in-app route, or `null`.                         |
| `attribution`        | `Attribution?` | Referral code, safe metadata map, and allowed dynamic values, or `null`. |
| `attributionReceipt` | `String?`      | Short-lived signed receipt returned only by a live matched resolution.   |
| `requestId`          | `String`       | Request ID to use for tracing and support.                               |

`MatchType` values are `EXACT_APP_LINK`, `EXACT_INSTALL_REFERRER`, `EXACT_HANDOFF`, `PROBABILISTIC`, and `NONE`. Android normally returns the first, second, or `NONE`.

## Install Referrer lifecycle

During the pending first-open window, the SDK contacts Google Play once, extracts only a valid opaque `biqli_token`, and closes the connection. It never persists or transmits the complete referrer string. The extracted token, pending request, app-instance ID, and cached result use Android Keystore-backed encrypted preferences.

An empty referrer, unsupported service, permission error, developer error, or missing Play Store becomes a terminal clean no-match. A service disconnect or timeout remains retryable during the 24-hour first-open window.

Once first-open attribution reaches a terminal result, a cold launch without a new App Link returns the cached result without creating another resolver event. The cached result excludes `attributionReceipt`.

## Retry and timeout behavior

* Connection timeout: 5 seconds.
* Read timeout: 5 seconds.
* Immediate attempts: at most three.
* Backoff between attempts: 400 ms, then 800 ms, plus 0–250 ms random jitter.
* Immediate retries: transport errors, HTTP `429`, and HTTP `5xx`.
* Later-launch recovery: the same pending event and idempotency key remain in encrypted storage.

The SDK does not run an autonomous background retry loop. Your app must call resolution again on a later cold launch.

## Consent

When `consentRequired` is `true`, call:

```kotlin theme={null}
Biqli.resolveAttribution(intent, consentGranted = userHasConsented)
```

If consent is not granted, the SDK throws `BiqliException.ConsentRequired` before it reads Install Referrer or contacts Biqli.

## Diagnostics

When enabled, diagnostics can report:

```text theme={null}
APP_LINK_CAPTURED
INSTALL_REFERRER_FOUND
INSTALL_REFERRER_EMPTY
INSTALL_REFERRER_UNAVAILABLE
INSTALL_REFERRER_RETRYABLE
RESOLVER_RETRY
RESOLVER_MATCHED
RESOLVER_NO_MATCH
```

These bounded enums intentionally omit raw URLs, referrers, handoff tokens, keys, and response payloads.

## Errors

| Exception              | Meaning                                               |
| :--------------------- | :---------------------------------------------------- |
| `NotConfigured`        | `Biqli.configure` has not completed.                  |
| `ConsentRequired`      | This configuration requires consent.                  |
| `InvalidConfiguration` | App ID, mobile key, or API base is invalid.           |
| `InvalidResponse`      | The resolver response could not be decoded safely.    |
| `Http(status, code)`   | The server rejected a terminal HTTP request.          |
| `Transport`            | All immediate transport/server retry attempts failed. |

## Test the published dependency

Confirm Gradle resolves the Maven Central release rather than a local project substitution, then verify the built app and installed-app App Link. The deferred Install Referrer path is proven only by a Google Play installation. Follow [Test and troubleshoot mobile links](/developers/mobile/testing-troubleshooting).
