美文网首页
NDK is missing a “platforms” dir

NDK is missing a “platforms” dir

作者: ZuYuan | 来源:发表于2021-12-04 17:52 被阅读0次

    背景

    第一次开发Native项目,需要在AndroidStudio(简称AS)上配置好NDK。

    环境配置:AGP版本=3.4.2,compileSdkVersion=28,targetVersion=26,NDK版本=22.0.7026061,cmake.abiFilters="armeabi-v7a", "arm64-v8a"。

    问题

    1. 在下载并配置好NDK后(下载:AS的SDK Tools),sync报错NullPointerException,但它其实是“NDK is missing a "platforms" directory.”引发的,只是这一句日志被标记为警告。
    2. 基于问题一,在网上找了个解决方式(我信了它的邪😭),在ndk目录下新建一个“platforms”的文件夹就可以sync过了。但是接下来又编译报错“Error:ABIs [arm64-v8a] are not supported for platform. Supported ABIs are [armeabi-v7a, x86]”。

    解决过程

    问题二的难点在于造成类似“ABIs [arm64-v8a] are not supported for platform”的原因有好几种,我归纳总结为:

    1. NDK升级到17之后,不再支持armeabi架构。因此NDK升级是有可能造成类似 “ABIs [xxx] are not supported for platform”的错误;
    2. compileSdkVersion设置为19,也会导致这个问题,因为版本号为19的系统只能是32位的;
    3. 对自己和对NDK的不信任:对自己不信任是因为对编译的东西还不够熟悉,总觉得自己哪里配置出错了;对NDK不信任是觉得从官网下载的NDK为什么会出现“问题一”呢?是不是NDK下载错了,或者xxxxx的原因。

    解决方式

    根据问题二报出的堆栈信息,进行断点调试:

    adb命令:./gradlew :[module]:installDebug -Dorg.gradle.debug=true --no-daemon 。(AGP7以上需要自己处理下Java11兼容问题)

    关键断点行:NdkHandler -> supports64Bits() (找不到这个类的同学在app的build.gradle下implementation一下AGP,例如 "com.android.tools.build:gradle:3.4.2")。

    问题原因:编译时Gradle会判断这次编译实际支持的abi,当在build.gradle下配置的abi不属于实际支持的abi时,就会报错“ABIs [arm64-v8a] are not supported for platform...”。

    实际支持的abi的判断方式为:

    判断前提:gradle认为highestVersion>=20时,abi能够支持到64位,反之只能支持32位

    //root 即配置NDK路径
    File platformDir = new File(root, "/platforms");
    File[] platformSubDirs = platformDir.listFiles(File::isDirectory);
    int highestVersion = 0;
    assert platformSubDirs != null;
    for (File platform : platformSubDirs) {
      if (platform.getName().startsWith("android-")) {
        try {
          int version = Integer.parseInt(
              platform.getName().substring("android-".length()));
          //targetVersion即在build.gradle下配置的目标版本 此次为26
          if (version > highestVersion && version < targetVersion) {
            highestVersion = version;
          }
        } catch (NumberFormatException ignore) {
          // Ignore unrecognized directories.
        }
      }
    }
    return highestVersion;
    

    根据上面的代码举个例子:

    targetVersion=26, “platforms”目录下有三个文件夹“android-19”、“android-25”、“android-31”时,经过上面的程序后,会输出highestVersion=25。而根据前提,25>=20,就认为arm64可用。

    解决方式:在NDK目录下新建了“platforms”文件夹,并在“platforms”文件夹下新建了“android-19”、"android-21"、"android-31"三个文件夹。

    补充
    应该有同学会疑问新建空文件夹会不会导致其它的问题产生?实际上并不会。“/platforms/android-N”这个路径实际上在SDK的目录下就有,它的含义为第N个版本的android sdk文件。我猜想在这里Gradle只是想知道当前允许编译哪几个版本的apk,而哪个版本的sdk文件夹存在就认为能够编译对应版本的apk。如果只能编译版本号20以下的apk,那么就可以认为当前并不支持arm64。而判断方式则是根据一个固定路径下的文件名称去判断(无语...)。

    为了进一步验证上面的猜想,我新建了一个基于AGP7.0的Cpp项目。这次不用新建“/platforms"文件夹也能编译过去了,因为在AGP7.0上supports64Bits的判断条件为 compileSdkVersion >= AndroidVersion.SUPPORTS_64_BIT (build.gradle下配置的compileSdkVersion)。显然Google也认为在AGP3.4.2上的supports64Bits判断方式并不稳妥。

    相关文章

      网友评论

          本文标题:NDK is missing a “platforms” dir

          本文链接:https://www.haomeiwen.com/subject/ulzvxrtx.html