如何修复 Android 项目构建因 .so 不是 ABI 而失败的问题

Bur*_*000 6 android gradle android-gradle-plugin

我有一个使用 Android Gradle Plugin 7.4.2 的项目,我使用升级助手更新到 8.0.2,但现在我的项目无法构建,并出现以下错误:

原因:从路径 /Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni/arm64-v8.2-a/libarmnn_delegate_jni.so 提取的 jni 不是 ABI

有谁知道是否有某种方法可以在 Gradle 中指定不使用该库的 arm64-v8.2-a ABI 版本?我尝试添加以下内容:

    ndk {
        // Specifies the ABI configurations of your native
        // libraries Gradle should build and package with your app.
        abiFilters 'arm64-v8a'
    }
Run Code Online (Sandbox Code Playgroud)

并且

splits {
        abi {
            enable true
            reset()
            include "arm64-v8a"
        }
    }
Run Code Online (Sandbox Code Playgroud)

但那些没有帮助。如果我恢复升级,项目构建正常,但我想使用最新版本的 Gradle 插件。

编辑:有关额外信息,此依赖项以 .AAR 文件的形式出现,其中包含已编译的本机 .so 文件的 arm64-v8a 和 arm64-v8.2-a 版本。看起来在较旧的 Android Gradle 插件版本中,v8.2 只是被忽略,但现在它被自动拾取并导致此问题?

Sni*_*kow 2

触发错误的代码位于MergeNativeLibsTask.kt中:

    /**
     * [file] is one of these two kinds:
     *    (1) /path/to/{x86/lib.so}
     *    (2) /path/to/x86/{lib.so}
     * Where the value in {braces} is the [relativePath] from the file visitor.
     * The first (1) is from tasks that process all ABIs in a single task.
     * The second (2) is from tasks the where each task processes one ABI.
     *
     * This function distinguishes the two cases and returns a relative path that always
     * starts with an ABI. So, for example, both of the cases above would return:
     *
     *    x86/lib.so
     *
     */
    private fun toAbiRootedPath(file : File, relativePath: RelativePath) : String {
        return if (abiTags.any { it == relativePath.segments[0] }) {
            // Case (1) the relative path starts with an ABI name. Return it directly.
            relativePath.pathString
        } else {
            // Case (2) the relative path does not start with an ABI name. Prepend the
            // ABI name from the end of [file] after [relativePath] has been removed.
            var root = file
            repeat(relativePath.segments.size) { root = root.parentFile }
            val abi = root.name
            if (!abiTags.any { it == abi }) {
                error("$abi extracted from path $file is not an ABI")
            }
            abi + separatorChar + relativePath.pathString
        }
    }
Run Code Online (Sandbox Code Playgroud)

基于您的错误以“jni”开头的事实,在您的情况下,它似乎选择路径的“jni”部分作为提取的 ABI。

该代码看起来确实需要受支持的 ABI 名称作为相对路径的第一段,或者是相对路径之外的目录名称。

就您而言,我猜测您的文件值为/Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni/arm64-v8.2-a/libarmnn_delegate_jni.so和relativePath arm64-v8.2-a/libarmnn_delegate_jni.so

  • 第一个(“案例 1”)检查将尝试将“arm64-v8.2-a”与已知的 ABI 进行匹配,但这显然失败了。
  • 在else路径中,我们通过向上跳转两次(relativePath中元素的数量)找到根,最终得到/Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni。该目录的名称是“jni”,它也不匹配任何已知的 ABI。因此,出现错误。

除了确保该文件根本不调用该函数之外,我看不到任何方法可以使该函数通过。如果可能的话,我不知道如何(但我肯定不是该领域的专家)。另一个选项是从依赖项中删除“坏”ABI(如果您可以控制它)——接受的列表应该在这里

此前,这已被报告为 Google Issue Tracker 上的错误,但似乎没有太多(公开)进展。如果您没有任何新内容要添加,请不要在这些评论中发表;请使用星号图标或“+1”按钮标记问题。