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.
“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 thenadb logcatis the only useful tool.
Part 1 — Reading the APK’s requirements
One command gives you almost everything:
aapt2 dump badging app.apk | head -40The 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 # dpiThe 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 error | Root cause | Fix |
|---|---|---|
INSTALL_FAILED_OLDER_SDK | APK minSdk is higher than the device API | Find an older APK version with a lower minSdk |
INSTALL_FAILED_NO_MATCHING_ABIS | No compatible native library | Get a matching ABI build or a universal APK |
INSTALL_FAILED_UPDATE_INCOMPATIBLE | Signature differs from the installed version | Uninstall the existing app first |
INSTALL_FAILED_VERSION_DOWNGRADE | versionCode lower than installed | Use adb install -d app.apk |
INSTALL_FAILED_INSUFFICIENT_STORAGE | Not 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.apkCause 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.