正确方式是用 add_library(xxx SHARED IMPORTED) 声明导入库,再通过 set_target_properties(xxx PROPERTIES IMPORTED_LOCATION ${LIB_PATH}) 绑定全路径(含 ${ANDROID_ABI}),最后在 target_link_libraries 中引用目标名;禁用 find_library 和裸路径链接。

怎么在 CMakeLists.txt 里正确声明 add_library 引入已编译的 .so 文件
直接用 add_library 声明一个 IMPORTED 类型的库,是引入预编译 .so 的唯一可靠方式。别用 link_libraries 或裸写 target_link_libraries,它们不认路径、不认 ABI 架构、容易静默失败。
常见错误现象:编译通过但运行时报 java.lang.UnsatisfiedLinkError: dlopen failed: library "xxx.so" not found —— 大概率是没指定 IMPORTED_LOCATION,或路径写错、ABI 不匹配。
- 必须写全路径:
set(LIB_PATH ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libxxx.so),注意${ANDROID_ABI}是 CMake 自动提供的变量(如arm64-v8a),不能硬编码 - 声明时加
SHARED IMPORTED:add_library(xxx SHARED IMPORTED) - 立刻用
set_target_properties绑定路径:set_target_properties(xxx PROPERTIES IMPORTED_LOCATION ${LIB_PATH}) - 如果
.so有依赖其他.so(比如依赖libc++_shared.so),得一并声明并确保它们都在jniLibs/对应 ABI 目录下
为什么 find_library 找不到你放好的 .so
find_library 只查系统路径或 CMAKE_LIBRARY_PATH 指定的路径,它不会自动扫描 jniLibs/。你手动把 .so 放进项目目录,不代表 CMake 能“看见”它。
典型误操作:写 find_library(XXX_LIB xxx PATHS ${CMAKE_SOURCE_DIR}/src/main/jniLibs/arm64-v8a) —— 这样写看似合理,但 find_library 查的是文件名不含 lib 前缀和 .so 后缀的“库名”,即它实际找的是 xxx,不是 libxxx.so;而且一旦路径里有多个 ABI 子目录,硬编码 arm64-v8a 就会让其他 ABI 编译失败。
Android 开发调试技能,通过系统 ADB 工具操作 Android 设备。以下场景必须触发此技能:(1) 直接 ADB 操作——安装 APK、查看设备列表、抓取 logcat 日志、查看已安装应用、清除应用数据、截图、重启设备、拉取/推送文件、查看 CPU/内存/电池信息、adb shell 操作;(2)...
- 放弃
find_library,改用add_library(... IMPORTED)+set_target_properties - 路径拼接务必用
${ANDROID_ABI},不要写死字符串 - 检查
jniLibs/下是否真有对应 ABI 的目录,比如jniLibs/arm64-v8a/libxxx.so,缺目录或文件名大小写不对都会失败
target_link_libraries 怎么写才真正链接上
声明完 IMPORTED 库之后,target_link_libraries 才能识别这个名字。但它只接受目标名(即 add_library 第一个参数),不接受路径或文件名。
容易踩的坑:写成 target_link_libraries(native-lib ${CMAKE_SOURCE_DIR}/.../libxxx.so) —— 这会触发 CMake 报错 Cannot find source file: .../libxxx.so,因为它试图把这个路径当源码去编译,而不是链接。
- 确保
target_link_libraries的第一个参数是你项目的 native 库名(比如native-lib) - 后续跟的是已声明的 IMPORTED 目标名,例如
xxx(和add_library(xxx ...)一致) - 顺序重要:被依赖的库(xxx)要写在依赖它的库(native-lib)后面,CMake 链接顺序敏感
- 如果
.so依赖libc++_shared.so,也得声明并链接:add_library(c++ SHARED IMPORTED)→set_target_properties(c++ ...)→ 再一起列在target_link_libraries里
ABI 不匹配导致运行时找不到库的排查要点
Gradle 打包时只会把 jniLibs/${ANDROID_ABI}/ 下的 .so 打进 APK 对应目录。如果 CMake 编译出的 native 库 ABI 和你放的 .so ABI 不一致,运行时必然 dlopen failed。
最常被忽略的一点:Android Studio 默认可能只构建 arm64-v8a,但你放的 .so 是 armeabi-v7a 版本,或者反过来。
- 确认
app/build.gradle里的ndk.abiFilters和你jniLibs/下实际存在的子目录严格一致 - 在
CMakeLists.txt开头加message(STATUS "ABI: ${ANDROID_ABI}"),编译时看日志输出是否符合预期 - 用
file(GLOB XXX_SO "${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libxxx.so")+message(FATAL_ERROR "Missing ${XXX_SO}")主动报错,比运行时报错早发现 - APK 打包后解压,检查
lib/目录下是否有对应 ABI 子目录及目标.so文件
${ANDROID_ABI}、多一个斜杠、名字大小写差一点,都可能让链接静默成功但运行崩溃。动手前先确认 jniLibs/ 目录结构和 abiFilters 完全对齐,比反复改 CMake 更省时间。

















