Android NDK导入C静态库(.a)出现未定义符号错误求助
解决方案:Android NDK链接C静态库未定义符号问题
核心问题分析
你遇到的链接错误主要来自三个点:
- CMake未正确导入预编译静态库,错误地将头文件当作库源文件
- C++调用C函数时未处理名字修饰导致符号不匹配
- JNI与Kotlin层的参数类型不匹配(单个Byte无法对应C的字节数组指针)
1. 修正CMakeLists配置
你的CMake代码错误地用头文件创建静态库,正确做法是直接导入预编译的librgil.a:
cmake_minimum_required(VERSION 3.22.1) project(libraryconnector) # 导入预编译的C静态库 add_library(es_rgil STATIC IMPORTED) # 配置库路径和头文件目录,根据你的实际文件位置调整 set_target_properties(es_rgil PROPERTIES # 假设librgil.a放在src/main/cpp/libs/[ABI]/目录下 IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/librgil.a # 指定头文件所在目录,让编译器能找到es_rgil.h INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR} ) # 构建你的JNI共享库 add_library( libraryconnector SHARED native-lib.cpp) # 链接静态库到你的JNI库 target_link_libraries( libraryconnector es_rgil)
注意:
- 要把
librgil.a放到对应ABI的子目录,比如src/main/cpp/libs/arm64-v8a/、src/main/cpp/libs/armeabi-v7a/ - 在Module的build.gradle中指定支持的ABI:
android { defaultConfig { ndk { abiFilters 'arm64-v8a', 'armeabi-v7a' // 和你的库架构匹配 } } }
2. 修复C++与C函数的名字修饰问题
因为你的JNI文件是.cpp(C++),调用C编写的库函数时,必须用extern "C"包裹头文件,避免C++名字修饰导致符号找不到:
#include <jni.h> // 用extern "C"包裹C头文件,确保函数名按C规则解析 extern "C" { #include "es_rgil.h" } extern "C" JNIEXPORT int32_t JNICALL Java_com_bartosz_lewandowski_libraryconnector_MainActivity_mifareAuth( JNIEnv *env, jobject /* this */, jbyte sector, jboolean keyType, jbyteArray key, // 改成jbyteArray,对应Kotlin的ByteArray jsize len) { es_rgil_mifare_key_type k_type = ES_RGIL_MIFARE_KEY_A; if (keyType) { k_type = ES_RGIL_MIFARE_KEY_B; } // 将JNI的字节数组转为C指针 uint8_t* key_ptr = reinterpret_cast<uint8_t*>(env->GetByteArrayElements(key, nullptr)); if (!key_ptr) return -1; // 处理内存分配失败 int32_t result = es_rgil_mifare_auth( static_cast<uint8_t>(sector), k_type, key_ptr, static_cast<size_t>(len) ); // 释放JNI数组资源 env->ReleaseByteArrayElements(key, reinterpret_cast<jbyte*>(key_ptr), JNI_ABORT); return result; }
3. 修正Kotlin层函数声明
原来的key: Byte是单个字节,和C函数需要的字节数组指针不匹配,改成ByteArray:
external fun mifareAuth(sector: Byte, isKeyTypeB: Boolean, key: ByteArray, len: Int): Int
额外检查项
- 确认
librgil.a的架构和你编译的ABI完全一致(比如库是arm64-v8a,就不要编译x86) - 检查
es_rgil.h中是否正确定义了es_rgil_mifare_key_type枚举,确保ES_RGIL_MIFARE_KEY_A/B是有效值 - 清理项目后重新构建(Build → Clean Project → Rebuild Project)
内容的提问来源于stack exchange,提问作者Bartosz Lewandowski
相关产品推荐
相关产品推荐

