Android构建遇UnsatisfiedLinkError,CMake加载.so库问题求助
java.lang.UnsatisfiedLinkError 我在构建指纹采集验证应用时遇到了两个相关错误:
java.lang.UnsatisfiedLinkError:无法通过dalvik.system.PathClassLoader加载NativeMorphoSmartSDK_6.13.2.0-4.1- 空指针类型的
UnsatisfiedLinkError
我使用OpenSSL和第三方库实现功能,以下是我的CMake配置文件:
# For more information about using CMake with Android Studio, read the documentation: https://d.android.com/studio/projects/add-native-code.html # Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.4.1) # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds them for you. # Gradle automatically packages shared libraries with your APK. add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp ) add_library(openssl SHARED IMPORTED) set_target_properties (openssl PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/lib/libcrypto.so ) set_target_properties (openssl PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/lib/libssl.so ) set_target_properties (openssl PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/lib/libidkit.so ) set_target_properties (openssl PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/lib/libjnidispatch.so ) set_target_properties (openssl PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/lib/libMSO100.so ) set_target_properties (openssl PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/lib/libNativeMorphoSmartSDK_6.13.2.0-4.1.so ) # Searches for a specified prebuilt library and stores the path as a # variable. Because CMake includes system libraries in the search path by # default, you only need to specify the name of the public NDK library # you want to add. CMake verifies that the library exists before # completing its build. include_directories(openssl-armeabi-v7a/include/) find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log ) # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this # build script, prebuilt third-party libraries, or system libraries. target_link_libraries( # Specifies the target library. native-lib ${CMAKE_CURRENT_SOURCE_DIR}/openssl-armeabi-v7a/lib/libcrypto.a ${CMAKE_CURRENT_SOURCE_DIR}/openssl-armeabi-v7a/lib/libssl.a # Links the target library to the log library # included in the NDK. ${log-lib} )
想请教:当前通过CMake加载.so文件的方式是否正确?还有哪些加载.so文件的方法?如何解决这个错误?
嘿,我来帮你拆解下这个问题——你遇到的java.lang.UnsatisfiedLinkError基本是CMake配置的几个关键错误导致的,咱们一步步理清楚:
一、当前CMake配置的核心问题
你的配置里有几个明显的错误,直接导致了库加载失败:
重复覆盖导入库路径
你把所有第三方.so都塞进了名为openssl的导入库,每次调用set_target_properties都会覆盖之前的IMPORTED_LOCATION值,最后只有libNativeMorphoSmartSDK_6.13.2.0-4.1.so会被CMake识别,其他像libcrypto.so、libssl.so这些库都被覆盖丢失了。每个第三方.so都得单独定义成一个导入库,不能共用一个目标名。静态库与动态库混用冲突
你在target_link_libraries里链接了静态版本的libcrypto.a和libssl.a,但同时又尝试导入它们的动态.so版本,这会让链接器混乱,直接引发加载错误。得统一用静态或动态版本,不能两边都沾。硬编码架构导致适配问题
你在include_directories里写死了armeabi-v7a,如果你的项目支持多架构(比如现在主流的arm64-v8a),其他架构下根本找不到头文件,自然会出问题。应该用${ANDROID_ABI}来动态匹配当前编译的架构。
二、修复后的CMake配置参考
我帮你调整了配置,你可以直接用:
cmake_minimum_required(VERSION 3.4.1) # 定义你的主Native库 add_library(native-lib SHARED src/main/cpp/native-lib.cpp) # 每个第三方动态库单独定义 add_library(crypto SHARED IMPORTED) set_target_properties(crypto PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libcrypto.so) add_library(ssl SHARED IMPORTED) set_target_properties(ssl PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libssl.so) add_library(idkit SHARED IMPORTED) set_target_properties(idkit PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libidkit.so) add_library(jnidispatch SHARED IMPORTED) set_target_properties(jnidispatch PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libjnidispatch.so) add_library(MSO100 SHARED IMPORTED) set_target_properties(MSO100 PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libMSO100.so) add_library(MorphoSDK SHARED IMPORTED) set_target_properties(MorphoSDK PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libNativeMorphoSmartSDK_6.13.2.0-4.1.so) # 动态匹配架构的头文件路径 include_directories(${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/include/) # 找到系统log库 find_library(log-lib log) # 把所有依赖库链接到你的主库 target_link_libraries(native-lib crypto ssl idkit jnidispatch MSO100 MorphoSDK ${log-lib})
三、其他加载.so文件的方法
除了CMake,Android里还有几种常用的Native库加载方式:
- Gradle直接配置(最简单)
不用写CMake,直接在app/build.gradle的android块里加这段,Gradle会自动打包jniLibs下的所有.so:
android { sourceSets { main { jniLibs.srcDirs = ['src/main/jniLibs'] } } }
然后在Java代码里用System.loadLibrary("NativeMorphoSmartSDK_6.13.2.0-4.1")加载就行——注意要去掉前缀lib和后缀.so。
- 手动指定绝对路径加载
如果你的库不在默认的jniLibs目录,也可以用绝对路径加载:
System.load("/data/data/com.your.package/files/libNativeMorphoSmartSDK_6.13.2.0-4.1.so");
不过这种方式要处理文件权限和不同设备的路径适配,一般不推荐在正式项目里用。
- 传统NDK的Android.mk/Application.mk
这是比较老的构建方式,现在CMake更主流,但如果是维护旧项目可以用:
Android.mk用来定义库的编译、链接规则Application.mk指定项目支持的CPU架构
四、额外排查小技巧
- 检查架构兼容性:用
readelf -h libxxx.so命令查看每个.so支持的架构,确保和你项目配置的架构一致(比如arm64-v8a、armeabi-v7a)。 - 检查库的依赖:有些.so依赖其他库,用
objdump -x libxxx.so | grep NEEDED可以查看它需要的依赖库,确保所有依赖都打包进了APK。 - 注意加载顺序:如果库之间有依赖关系,得先加载依赖库,再加载主库。比如
libNativeMorphoSmartSDK依赖libMSO100.so,那就要先调用System.loadLibrary("MSO100"),再加载SDK库。
内容的提问来源于stack exchange,提问作者Gajanand Swamy

