android studio构建报“so is not an ABI”?

我尝试用android(java)调用so库文件,gradle(kotlin DSL, version 6.0)编译的时候, 出现一下问题:

* What went wrong:
Execution failed for task ':app:mergeDebugNativeLibs'.
> out extracted from path E:\proj\android\MyApplicationWithJava\app\build\intermediates\merged_jni_libs\debug\mergeDebugJniLibFolders\out\libhello.so is not an ABI

goole了一下,可能有几个方面导致这个问题的出现
1 so文件和设备的ABI不一致

2 gradle的配置问题

上面都尝试了,并不能解决这个问题。

另外,我的so库文件是通过手动命令编译的,不是通过项目,命名如下:

g++ -m64 com_shinja_jni_HelloJNI.cpp -fPIC -shared -o libhello1.so -I D:\app\code\jdk\jdk17\include -I D:\app\code\jdk\jdk17\include\win32
说明:
system: win10
jdk: 17
android studio: 2024.1.1
android SDK: 34
gradle: 6.0
g++:(Rev6, Built by MSYS2 project) 13.2.0

非常感谢您的回答!

阅读 2.6k
avatarAI BotBETA

问题分析

您遇到的错误“out extracted from path ... libhello.so is not an ABI”通常表明Android构建系统无法识别或正确处理提供的.so文件。这通常是因为.so文件与Android平台预期的ABI(应用程序二进制接口)不匹配。

在您的情况下,问题可能是由于以下几个原因:

  1. ABI不匹配:您使用g++ -m64编译的libhello1.so是针对64位系统的,但Android设备通常使用ARM或ARM64架构。因此,您应该为Android编译正确的ABI版本。
  2. 手动编译的SO文件:您手动编译的.so文件可能不包含Android所需的元数据或签名,这可能导致构建系统无法识别它。
  3. Gradle配置问题:尽管您提到已经检查了Gradle配置,但确保您的build.gradle文件中正确配置了NDK和CMake(如果您正在使用它)以处理原生库。

解决方案

  1. 使用NDK编译SO文件
    使用Android NDK(Native Development Kit)来编译您的原生库。NDK包含了一组工具,用于在Android平台上编译C和C++代码。您可以使用CMake或ndk-build作为构建系统。

    以下是一个使用CMake的基本示例CMakeLists.txt

    cmake_minimum_required(VERSION 3.4.1)
    
    add_library(hello-jni SHARED com_shinja_jni_HelloJNI.cpp)
    
    find_library(log-lib log)
    
    target_link_libraries(hello-jni ${log-lib})

然后,在您的build.gradle文件中配置CMake:

android {
    ...

    defaultConfig {
        ...

        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
    }

    externalNativeBuild {
        cmake {
            path "src/main/jni/CMakeLists.txt"
            version "3.10.2"
        }
    }
}
  1. 确保SO文件是针对正确的ABI
    使用NDK编译时,确保为Android设备支持的ABI(如armeabi-v7a、arm64-v8a、x86、x86_64)编译库。
  2. 检查Gradle配置
    再次检查您的build.gradle文件,确保没有遗漏或错误的配置。
  3. 清理和重建项目
    在Android Studio中,尝试“Clean Project”和“Rebuild Project”来确保所有构建文件和缓存都是最新的。
  4. 检查SO文件是否损坏
    使用文件检查工具或尝试在不同的Android项目中使用相同的SO文件来确保文件本身没有损坏。

遵循上述步骤后,您应该能够解决“is not an ABI”的错误,并成功地在Android应用程序中集成您的原生库。

2 个回答
✓ 已被采纳新手上路,请多包涵

已解决,问题如下
1 gradle的配置jniLibs.srcDirs = ['src/main/jniLibs']是告诉构建工具从该目录下找库文件,如果是x86_64架构就从src/main/jniLibs/x86_64目录下找,搜索格式是src/main/jniLibs/{abi}。所以应该手动建一个x86_64目录,将库文件放进去。(使用cmake工具应该会自动创建,没试过猜测)

继续后面的调用过程还发现几个问题,这里补充下:
1 手动编译库文件时使用的标准的g++,应该使用ndk里的c++编译工具,否则会出现 xxx.so has bad ELF magic (x86_64的magic number是7F 45 4C 46)。

D:\app\code\Android\SDK\ndk\27.0.11902837\toolchains\llvm\prebuilt\windows-x86_64\bin\x86_64-linux-android24-clang++ -m64 -shared -o libhello.so -fPIC com_shinja_jni_HelloJNI.cpp

2 构建通过,运行时应用程序崩溃,logcat也没有报错日志,调试发现报错java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found,应该是自己的库依赖了标准库libc++_shared.so,手动解决依赖的办法是将libc++_shared.so复制到src/main/jniLibs/x86_64下面。注意标准库的abi,选择对应的。

你编译的方式就有问题,要编译android使用的so库,要使用ndk编译链来进行编译,
你上面的编译应该是编译当前环境下的 动态链接库,而不是android使用的。

cmake -DCMAKE_TOOLCHAIN_FILE=/opt/adt-bundle-linux/sdk/ndk/23.0.7599858/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-21 -DANDROID_TOOLCHAIN=clang -DANDROID_STL=c++_shared -DCMAKE_BUILD_TYPE=Release -G Ninja $1

补充下,不需要手动拷贝 c++_shared

externalNativeBuild {
                cmake {
                    // force -O2 optimize flag, as Release build type does not utilize this flag
                    cppFlags '-O2'
                    arguments '-DANDROID_STL=c++_shared',
                            '-DANDROID_ABI=arm64-v8a',
                            '-DANDROID_NATIVE_API_LEVEL=21',
                            '-DCMAKE_BUILD_TYPE=Release',
                            '-DCMAKE_VERBOSE_MAKEFILE=ON'
                }
            }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题