rea-reverse

应用与你的手机不兼容:检查 targetSdk、ABI 和 minSdk

基于 REA 6.4.0更新于 约 6 分钟读完
本页目录

结论先行:手机提示“应用与你的手机不兼容”(英文系统是 “App not installed as app isn’t compatible with your phone”),背后其实是好几种不同的拒绝原因。在当前的 Android 版本上,最常见的是这几种:targetSdkVersion 太低(Android 14 拦截低于 23 的,Android 15 及以上拦截低于 24 的);原生库只有手机不支持的 ABI(典型情况是只有 32 位库,而手机只支持 64 位);minSdkVersion 高于手机的系统版本;或者声明了手机上没有的必需共享库。adb install 会打印出确切的 INSTALL_FAILED_* 代码,每个代码都对应构建配置里的一处修改。

本文用我自己构建的几个小 APK 把每种原因都复现了一遍,分别装到 Android 14(API 34)和 Android 16(API 36)模拟器上,下面是真实输出。然后再用本站的 APK/AAB 分析与上架体检 检查同一批文件,它在浏览器里读取 Manifest 和原生库,不上传任何内容。

适合谁读:在商店以外分发自家 APK、或者手动安装测试包,然后从用户或测试机那里收到这句提示的开发者。

读完你会知道:

  • 怎么用 adb 拿到真正的失败代码
  • 四类原因各自的复现方式和对应代码
  • 哪些原因工具会直接标出来,哪些要从报告的表格里读
  • Gradle、Flutter、Unity 里分别该改哪里
  • REA(morluto 的开源项目)6.4.0 能补充什么、做不到什么

只测试你自己的构建或已获授权的构建,并且只用你自己控制的设备。

第 1 步:拿到真实的错误代码

手机不会告诉你原因。连上设备(或启动模拟器),从电脑上安装:

adb install app-release.apk

下面是样例 APK 的结果。所有 APK 的包名都是 dev.example.compat,都用我的发布密钥签名,每次只改一项设置。

样例 问题 Android 14(API 34) Android 16(API 36)
compat-target22.apk targetSdkVersion 22 INSTALL_FAILED_DEPRECATED_SDK_VERSION INSTALL_FAILED_DEPRECATED_SDK_VERSION
compat-target23.apk targetSdkVersion 23 Success INSTALL_FAILED_DEPRECATED_SDK_VERSION
compat-armv7-only.apk 只有 lib/armeabi-v7a/ INSTALL_FAILED_NO_MATCHING_ABIS INSTALL_FAILED_NO_MATCHING_ABIS
compat-x86_64-only.apk 只有 lib/x86_64/ INSTALL_FAILED_NO_MATCHING_ABIS INSTALL_FAILED_NO_MATCHING_ABIS
compat-min35.apk minSdkVersion 35 INSTALL_FAILED_OLDER_SDK Success
compat-missing-library.apk 必需的 <uses-library> 不存在 INSTALL_FAILED_MISSING_SHARED_LIBRARY INSTALL_FAILED_MISSING_SHARED_LIBRARY
compat-watch-feature.apk 要求 android.hardware.type.watch Success Success
compat-fixed.apk target 36、min 24,arm64-v8a + armeabi-v7a + x86_64 Success Success

两台模拟器都是 arm64 镜像,ro.product.cpu.abilist 只有 arm64-v8a,没有任何 32 位 ABI。近几代 Pixel 手机同样只支持 64 位。

完整的失败信息本身就说得很清楚:

Failure [INSTALL_FAILED_DEPRECATED_SDK_VERSION: App package must target at least SDK version 23, but found 22]
Failure [INSTALL_FAILED_DEPRECATED_SDK_VERSION: App package must target at least SDK version 24, but found 23]
Failure [INSTALL_FAILED_NO_MATCHING_ABIS: INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]
Failure [INSTALL_FAILED_OLDER_SDK: Requires newer sdk version #35 (current version is #34)]
Failure [INSTALL_FAILED_MISSING_SHARED_LIBRARY: Reconciliation failed...: Reconcile failed: Package dev.example.compat requires unavailable shared library dev.example.missing.library; failing!]

前两行分别来自 API 34 和 API 36 模拟器,可以看到下限从 23 提到了 24。在我的模拟器上,logcat 没有记录这些失败,所以要看原因就看 adb 的输出。

第 2 步:在浏览器里检查 APK

打开 APK/AAB 分析与上架体检,场景选 Play 以外(线下分发) 或 两者都要。安装类规则 SIDE-01 属于线下分发场景,PLAY-04 属于 Google Play 场景,选“两者都要”就能同时看到。然后拖入 APK。

工具对这批样例的结果(按 2026-10-14 的规则):

compat-target22.apk
  SIDE-01  fail  reject  targetSdkVersion=22
                         Android 15+ requires targetSdkVersion >= 24
                         Android 14+ requires targetSdkVersion >= 23
  note: Installation fails on Android 14 and later (INSTALL_FAILED_DEPRECATED_SDK_VERSION).
  PLAY-01  fail  reject  targetSdkVersion=22, required: >= 36 (phone/tablet, since 2026-08-31)

compat-target23.apk
  SIDE-01  fail  reject  targetSdkVersion=23, Android 15+ requires targetSdkVersion >= 24
  note: Installation fails on Android 15 and later (INSTALL_FAILED_DEPRECATED_SDK_VERSION).

compat-armv7-only.apk
  PLAY-04  fail  reject  lib/armeabi-v7a/ present, lib/arm64-v8a/ missing

SIDE-01 和两台模拟器的结果完全吻合:target 22 在两台上都装不上,target 23 只在 Android 16 上装不上。

另外三种原因没有单独的检查项,要从报告里读出来:

  • 只有 x86_64。PLAY-04 只标两种情况:有 32 位 ABI 却缺对应的 64 位 ABI,以及 .so 的 ELF 头和所在目录不一致。只有 lib/x86_64/ 的 APK 两条都不触发,compat-x86_64-only.apk 的所有检查都通过了。问题要看原生库表格:只有一行,ABI 是 x86_64,ELF 是 64-bit x86-64,ARM 处理器的手机用不了。确认表里有 arm64-v8a。
  • minSdk。摘要里有 minSdk,拿它和手机的系统版本比(API 34 是 Android 14,35 是 Android 15,36 是 Android 16)。minSdk 设得高本身是合理选择,所以没有检查项会标它。
  • 必需共享库。当前版本没有用表格列出 <uses-library>。打开 Manifest → 原始 XML,查找带 android:required="true" 的 uses-library。

第 3 步:读取手机这一侧的信息

要对比,需要知道手机的 API 级别和支持的 ABI。用原生 adb:

adb shell getprop ro.build.version.sdk
adb shell getprop ro.product.cpu.abilist

用 REA 6.4.0 的话,inspect-adb-device 会读取一组固定的构建属性,其中就包括这两项:

export REA_ADB_PATH="$HOME/Library/Android/sdk/platform-tools/adb"
rea inspect-adb-device emulator-5582 --format json

API 34 模拟器上 normalized_result.properties 的摘录:

ro.build.version.release  14
ro.build.version.sdk      34
ro.product.cpu.abilist    arm64-v8a
ro.product.model          sdk_gphone64_arm64

rea list-adb-features <serial> 会列出设备声明的功能(pm list features),后面讲 Play 过滤时用得上。

REA 拿不到安装失败代码本身。rea install-adb-package 能装上正常的样例,但每次安装失败都只返回通用的 unreadable_output 错误,没有 INSTALL_FAILED_* 原文。6.4.0 的代码从 adb 的标准输出里读 Failure [...],而我用的 adb 37.0.1 把它写到标准错误,并以状态码 1 退出。这一步请继续用 adb install。

第 4 步:在构建里修好

targetSdkVersion 太低(DEPRECATED_SDK_VERSION)

提高 targetSdk。Android 14 拒绝低于 23 的,Android 15 及以上拒绝低于 24 的(Android 15 行为变更)。别只提到下限:自 2026-08-31 起,Google Play 要求手机和平板应用达到 36(PLAY-01),而且这个安装下限在两个 Android 版本里已经提高了两次。

android {
    defaultConfig {
        minSdk = 24
        targetSdk = 36
    }
}

提高 target 会改变运行时行为(权限、后台限制、Intent 等),要实际测试新版本,不能只是重新打个包。Flutter 项目的这些值在 android/app/build.gradle(.kts) 里,常见写法是 flutter.targetSdkVersion,由 Flutter SDK 版本决定。Unity 在 Player Settings → Other Settings 的 Target API Level 里设置。

adb install --bypass-low-target-sdk-block 可以强行装上 target 过低的包,我的 target 22 样例加这个参数后在两台模拟器上都装上了。它是给开发者在自己设备上测试旧构建用的,普通用户没有这个选项,它也不会修好 APK 本身。

没有匹配的 ABI(NO_MATCHING_ABIS)

面向手机一定要带 arm64-v8a。在 x86_64 模拟器上测试就保留 x86_64;只有要支持老的 32 位设备时才加 armeabi-v7a:

android {
    defaultConfig {
        ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64") }
    }
}

重点排查两种情况:为模拟器临时设置、之后一直没改回来的 abiFilters;以及只提供 32 位 .so 的第三方 SDK。Flutter 的 release 构建默认就包含 arm64 库,检查一下构建脚本里有没有 --target-platform 参数。Unity 要选 IL2CPP,并在 Target Architectures 里勾选 ARM64;Mono 后端不支持 ARM64。只勾了 ARMv7 的 Unity 包,在只支持 64 位的手机上就会这样失败。

带三种 ABI 的 compat-fixed.apk 在两台模拟器上都装上了。如果还要上架 Play,记得对 64 位库做一次 16 KB 页面大小检查。

minSdkVersion 太高(OLDER_SDK)

要么是手机系统确实太旧,要么是 minSdk 被意外抬高了,常见原因是某个依赖要求更高的版本,Manifest 合并时取了较大值。如果你本来就想支持这台手机,降低 minSdk,并替换掉把它抬高的依赖;如果不打算支持,这个提示就是对的,告诉用户最低支持的 Android 版本即可。

缺少共享库(MISSING_SHARED_LIBRARY)

<uses-library android:required="true"> 指定了一个这台手机没有的库,比如某个厂商专有库。如果应用没有它也能运行,改成 android:required="false",在运行时再判断;否则就单独出一个不依赖它的构建变体。

uses-feature:不是安装器的检查项

声明必需 android.hardware.type.watch 的样例,用 adb install 在两台手机模拟器上都装上了。在我的测试里,<uses-feature> 不会阻止安装。Google Play 和一些商店用它来决定哪些设备能看到这个应用。如果用户是在商店页面上看到“不兼容”,拿你声明的必需功能和受影响设备上 rea list-adb-features 的输出对比,把可选的功能改成 android:required="false"。

常见问题

手机说“不兼容”,adb 却给出别的代码? 以 adb 为准。如果代码是 INSTALL_FAILED_UPDATE_INCOMPATIBLE,那是和已装版本的签名冲突,请看 安装包与现有包冲突。

64 位手机能跑只有 32 位库的 APK 吗? 只有手机还列出 32 位 ABI 时才行(看 ro.product.cpu.abilist)。很多新手机已经不支持,我的两台模拟器都报了 NO_MATCHING_ABIS。请提供 arm64-v8a。

应用里根本没有原生代码,还会是 ABI 的问题吗? 不会。没有 lib/ 目录就没有可匹配的东西,去查 targetSdk、minSdk 和共享库。

我拿到的是 AAB,不是 APK。 AAB 不能直接安装。先用 bundletool 生成 APK,见 AAB 转 APK 教程。

下一步