Compatibility
AppInspect is meant to drop into an app that already exists, without changing how
that app is built. No Compose, no Kotlin, no dependency injection, no
Application subclass and no manifest edits are required. This page is
the honest list of what it does need, and what quietly does less on older devices.
What it needs from your project
| Requirement | Value | Notes |
|---|---|---|
| minSdk | 24 (Android 7.0) | Features above this degrade silently, never crash. |
| AndroidX | Required | android.useAndroidX=true. Legacy Support Library apps are not supported. |
| Compose in your app | Not required | Why — the UI is already compiled into the published AAR. |
| Kotlin in your app | Not required | Java-only hosts work; the syntax is just longer. |
| Java / JVM target | 11 bytecode | Consumed normally by apps targeting Java 8 or 11+. |
| Kotlin compiler | Built with 2.0.21 | A host on a much older Kotlin plugin may see “compiled with an incompatible version of Kotlin”; upgrading the plugin is the fix. |
| AGP | Built with 8.6.0 | Much older AGP may not accept the published Gradle module metadata. |
| DI framework | None | No Hilt, Dagger, Koin or ServiceLoader requirement. |
Application subclass | Not required | Auto-init runs from AndroidX Startup. You only need one to configure. |
| Manifest changes | None | The activity, file provider and Startup entry are merged in from the library. |
| Permissions to declare | None | POST_NOTIFICATIONS is declared by the library, but your app must request it on Android 13+. |
You do not need Compose
The inspector's screens are Compose, but that is an implementation detail of the
library, already compiled into the AAR you resolve. A View and XML app, a
Fragment-based app, or an app with buildFeatures { compose = false } gets
the full inspector unchanged: you never enable the Compose compiler, never set
composeOptions, and never write a composable.
The only thing Compose availability changes is which long-press trigger helper you
can use. Every other entry point — shake, launcher shortcut, notification tap,
AppInspect.open(context) — is the same either way.
| Your UI | Long-press trigger |
|---|---|
| Compose | Modifier.appInspectLongPressTrigger(handle) |
| Views / XML | AppInspect.attachLongPressTrigger(view) |
The trade-off is APK size, and only in the variants AppInspect ships in: a non-Compose app picks up the Compose runtime, Foundation, Material 3 and the extended icon set transitively. That lands in your debug and staging builds, never in release when you use the no-op artifact.
Java-only hosts
Everything works. AppInspect is a Kotlin object, so the
calls go through INSTANCE, and the Kotlin extension on the OkHttp builder
is not available — add the two interceptors directly instead, in this order.
AppInspect.INSTANCE.open(context);
AppInspect.INSTANCE.registerMetadata("tenant", "internal");
// Application interceptor first, network interceptor second
new OkHttpClient.Builder()
.addInterceptor(new AppInspectOkHttpInterceptor())
.addNetworkInterceptor(new AppInspectOkHttpWireHeaderInterceptor())
.build();
The second interceptor is what makes captured events carry the
final wire headers. Omit it and the panel
shows the request as your code built it, not as it was sent.
addAppInspectInterceptor() installs both for Kotlin callers.
Three optional integrations, and why they are optional
OkHttp, WorkManager and androidx.security-crypto are declared
compileOnly. AppInspect therefore never forces a version onto your app
and never adds a library you were not already using.
| Library | If your app has it | If it does not |
|---|---|---|
| OkHttp (4.x+) | Network capture and mocking work. Your version wins. | Every other panel works; the interceptor class is simply never loaded. |
| WorkManager | The Work panel reads work specs and decodes their Data blobs. | The panel is empty — there is no work database to read. |
| androidx.security-crypto | EncryptedSharedPreferences files are decrypted for read-only inspection. | Those files show as opaque. Ordinary preferences are unaffected. |
This matters more than it looks. Had these been ordinary implementation
dependencies, adding AppInspect could have raised the OkHttp version your app
resolves to — so the builds you test would run a different HTTP stack
than release, and a networking bug could appear or disappear depending on
whether the inspector was present. appinspect-no-op follows the same rule
and declares no runtime dependency beyond the Kotlin standard library.
If you are still on OkHttp 3.x, upgrade to 4.x before adding network capture; the interceptor is compiled against the 4.x API. The other panels do not care either way.
What does less on older devices
Nothing here throws or logs an error. The feature is simply absent, and the rest of the inspector is unaffected.
| Feature | Needs | Below that |
|---|---|---|
Panels, network, storage, crashes, Logcat, shake, open() | API 24 | — |
| Launcher shortcut | API 25 | Not published; other entry points unaffected. |
| Notification channel | API 26 | Channel creation is skipped; notifications still post, as they did before channels existed. |
| ANR and native crash detection | API 30 | JVM crashes are still captured by the crash handler. ApplicationExitInfo is the OS API this relies on. |
POST_NOTIFICATIONS runtime grant | API 33 | Notifications post without a runtime grant. |
AppInspect declares POST_NOTIFICATIONS but cannot request it —
it has no Activity of its own. If your app never asks, per-request notifications
silently never appear and everything else works normally. Ask for it wherever it
fits your UX, or set networkNotificationsEnabled = false and forget
about it. See Network notifications.