APK Downloader
·9 min read

Android APK Compatibility Check: Diagnosing 'App Not Compatible' and Crash-on-Launch

Two different failures, two different causes. How to read minSdk, targetSdk, ABI, and density requirements from an APK before installing — and how to fix the most common install and launch errors.

androidapkadbtroubleshooting

“App not compatible” and “opens then immediately closes” feel like the same problem. They are not. The first is a manifest filter— Android refuses the install because a declared requirement does not match your device. The second is a runtime failure— the install succeeded, so the manifest matched, and something broke after launch. Different tools, different fixes.

Key idea: Read the APK’s declared requirements with aapt2before installing. If they match your device and it still breaks, the problem moved to runtime — and then adb logcat is the only useful tool.

Part 1 — Reading the APK’s requirements

One command gives you almost everything:

aapt2 dump badging app.apk | head -40

The lines that matter:

package: name='com.example.app' versionCode='4210' versionName='4.2.1'
sdkVersion:'26'
targetSdkVersion:'34'
native-code: 'arm64-v8a' 'armeabi-v7a'

sdkVersion is minSdk: the minimum API level. A mismatch blocks installation outright with INSTALL_FAILED_OLDER_SDK. targetSdkVersion does not block installation but determines which compatibility behaviors apply at runtime. native-code lists the CPU architectures with native libraries; a mismatch either blocks installation or causes an instant crash.

Mapping API level to Android version: 23 is 6.0, 26 is 8.0, 28 is 9, 29 is 10, 30 is 11, 31 is 12, 33 is 13, 34 is 14. So sdkVersion:'26'means Android 8.0 or newer — on Android 7 no amount of “allow unknown sources” will help.

Part 2 — Checking your device

adb shell getprop ro.build.version.sdk        # API level, e.g. 34
adb shell getprop ro.product.cpu.abi          # primary ABI
adb shell getprop ro.product.cpu.abilist      # all supported ABIs
adb shell wm density                          # dpi

The critical comparison is abilist against the APK’s native-code. A device reporting only arm64-v8a— increasingly common on newer flagships — cannot install 32-bit-only armeabi-v7a APKs.

Part 3 — The install failures and what they actually mean

ADB errorRoot causeFix
INSTALL_FAILED_OLDER_SDKAPK minSdk is higher than the device APIFind an older APK version with a lower minSdk
INSTALL_FAILED_NO_MATCHING_ABISNo compatible native libraryGet a matching ABI build or a universal APK
INSTALL_FAILED_UPDATE_INCOMPATIBLESignature differs from the installed versionUninstall the existing app first
INSTALL_FAILED_VERSION_DOWNGRADEversionCode lower than installedUse adb install -d app.apk
INSTALL_FAILED_INSUFFICIENT_STORAGENot enough free space (needs roughly 2.5x the APK size)Free space

UPDATE_INCOMPATIBLEis also the signature-mismatch error. If you are installing what you believe is the official app over a previously sideloaded modified build, this is where it surfaces. The error is a security feature doing its job — do not try to defeat it; uninstall and reinstall clean.

Part 4 — Installed fine, crashes on launch

Now the failure is at runtime. Three causes cover most cases.

Cause 1: a missing native library for the ABI

Logcat shows UnsatisfiedLinkError or dlopen failed: library "libfoo.so" not found. The APK declared a native-code list and the device matched, but a specific library is not in the split you installed. This is common with bundles where only base.apk was installed.

adb install-multiple base.apk split_config.arm64_v8a.apk split_config.xxhdpi.apk

Cause 2: a missing dependency

Logcat shows ClassNotFoundExceptionfor a Google Play Services class, or the app shows a blank white screen. Many apps assume GMS exists; on devices without it they install and then crash — often on the login or map screen rather than at launch, which makes it look random.

adb logcat -d | grep -iE "ClassNotFound|NoClassDefFound|UnsatisfiedLink|FATAL"

Cause 3: targetSdk behavior changes

An app built against an old targetSdk runs on a new Android version with legacy compatibility behaviors applied, and some of those are silently broken. The classic case: apps with targetSdk < 23 cannot request runtime permissions properly on Android 6+, so they install, launch, and fail to access storage.

Usually there is no fix on your side. Downgrade to a version whose targetSdk is closer to your OS, or wait for an update.

Part 5 — The pre-download checklist

Before downloading a version, write down four numbers: minSdk, targetSdk, the ABI list, and the version code. Compare against: your device API level (must be at least minSdk), your abilist (must overlap), your density (needs a matching split or nodpi), and your installed versionCode (remember -d when downgrading).

If all four check out and it still fails, the problem is not compatibility — it is integrity. Verify the signature.

Part 6 — Diagnostics when nothing makes sense

adb install --verbose app.apk
adb shell dumpsys package com.example.app | grep -E "versionName|versionCode|primaryCpuAbi"
adb logcat -c && adb shell am start -n com.example.app/.MainActivity && adb logcat | grep -E "FATAL|AndroidRuntime"

primaryCpuAbi is particularly useful: it tells you which ABI the installed app is actually using. If you expected arm64-v8a and see armeabi-v7a, the app is running in 32-bit mode — which explains both slowness and some native crashes.

The short version

Compatibility is a read-the-manifest problem, not a trial-and-error problem. Once you can decode aapt2 dump badgingoutput, “app not compatible” becomes a specific diagnosis with a specific fix instead of a dead end.

For the source-side checklist, see the mirror-site red flag checklist.