# Android

> Capture Android identity, events, errors, crashes, and backend request context.

Canonical page: https://anectico.com/docs/instrument/android/


The native Kotlin SDK supports Android minSdk 24 and has no third-party runtime dependency. During
early access, add the artifact and repository configuration supplied during onboarding.

## Add the dependency

During early access, copy the supplied AAR into your app module's `libs/anectico-sdk.aar`, then add:

```kotlin
dependencies {
    implementation(files("libs/anectico-sdk.aar"))
    // Optional when using the Anectico OkHttp interceptor:
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
}
```

After the public Maven release, replace the local AAR with the exact published
`com.anectico:sdk:<version>` coordinate supplied for your release.

The SDK's `INTERNET` permission is merged into the application manifest.

## Initialize once

```kotlin
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        Anectico.init(
            this,
            AnecticoOptions(
                apiKey = BuildConfig.ANECTICO_API_KEY,
                environment = "production",
                release = "com.acme.shop@2.4.1+241",
                dist = "241",
                enableCrashReporting = true,
                debug = BuildConfig.DEBUG,
            ),
        )
    }
}
```

`serviceName` defaults to the application ID and `serviceVersion` to `versionName`.

`init` reports failure rather than absorbing it — `IllegalArgumentException` for invalid
configuration, `AnecticoInitException` (with the cause) for anything else that stops setup — so an
app that starts is an app whose telemetry is really running. Methods called before a successful
`init` record and send nothing: a debug build throws `AnecticoNotInitializedException` at the call
site, and a release build logs the first one at ERROR. See the
[Android SDK API reference](/docs/reference/android-sdk#calling-before-init).

Use a project-scoped key with `ingest:write` and `analytics:write`. Do not include read, management,
or agent scopes in the application.

## Connect identity and events

```kotlin
Anectico.identify("user_8842", mapOf("email" to "buyer@acme.example", "plan" to "pro"))
Anectico.group("company", "acme", mapOf("plan" to "enterprise"))
Anectico.capture("checkout_started", mapOf("cart_size" to 3))
Anectico.screen("Checkout")
Anectico.captureLog(
    "checkout prepared for offline sync",
    severity = "info",
    attributes = mapOf("items" to 3),
)

// On logout:
Anectico.reset()
```

`reset` also clears global error-user context and buffered breadcrumbs, preventing
the prior account's diagnostic context from attaching to the next account on a
shared device.

Every captured event — not only the automatic `$app_opened`/`$app_backgrounded` lifecycle
events — carries the reserved `$release` and `$app_version` properties, sourced from the same
`release`/`serviceVersion` you pass to `AnecticoOptions` (or `versionName` when you don't set
them explicitly). Neither is invented: an app that never configures a release sends events with
neither property. See [Reserved event properties](/docs/investigate/event-schema#reserved-properties).

`captureLog` sends OTLP logs to `/v1/logs` with the current customer/session and Android
app/device/release context. Logs are atomically persisted before delivery, retain their occurrence
time and stable `anectico.log.id` across process recreation, and retry network/429/5xx failures in
oldest-first order. `Anectico.flush` flushes both events and logs.

`maxQueueSize` is applied separately: the SDK can retain that many diagnostic events and that many
logs, rather than splitting one count between them. The log spool also drops oldest past 10 MiB.

## Capture errors and upload mappings

```kotlin
try {
    checkout()
} catch (error: Exception) {
    Anectico.captureError(error, CaptureOptions(tags = mapOf("screen" to "checkout")))
}
```

Anectico classifies explicit `captureError` calls as severity `error`, handled, with mechanism
`java.caught_exception`. The uncaught-exception handler classifies fatal crashes as severity
`fatal`, unhandled, with mechanism `java.uncaught_exception`. Those values are SDK-owned and cannot
be replaced by capture tags; unrelated application tags still appear on the occurrence.

The occurrence also includes SDK-owned app version/build, Android model and OS version, and Anectico
SDK/platform context for Issue Story. These are shared runtime descriptors, not physical-device
identifiers; the SDK never collects Android ID, serial number, installation ID, or the
user-assigned device name.

Fatal exceptions and failed manual error sends are spooled and retried on the next launch. Upload
the exact R8/ProGuard mapping for the captured `release` and `dist`:

```bash
anectico symbols upload-proguard mapping.txt --release "$RELEASE" --dist "$DIST"
```

The Issue Story identifies missing or mismatched mappings beside the raw R8 frames and shows the
exact release/distribution keys to upload. An empty distribution is a real key; preserve it with
`--dist ''`. After a mapping resolves, each recovered **Original source** entry remains paired with
a **Raw frame** line containing the captured obfuscated function and location; R8 inline entries
repeat that raw evidence in mapping order. The upload key requires `errors:write`.

## Propagate to your backend

For OkHttp:

```kotlin
val client = OkHttpClient.Builder()
    .addInterceptor(com.anectico.sdk.okhttp.AnecticoInterceptor())
    .build()
```

For `HttpURLConnection`, call `AnecticoPropagation.apply(connection)`. Send these headers only to
trusted application services.

## Verify

Identify a test user, capture one event and caught error, call `Anectico.flush`, and confirm the evidence
shares one customer. Test a fatal crash only in a safe test build, then relaunch so the spool drains.

- [Capture errors and releases](/docs/instrument/errors)
- [Android SDK API reference](/docs/reference/android-sdk)
- [Replay or symbols are not working](/docs/help/replay-and-symbols)
