如何在Android Studio的Kotlin项目中使用CMake构建的C库?
Kotlin调用CMake构建C库的完整指南(附示例)
1. 关于jni.h的说明
- 必须包含:所有供JNI调用的C函数都依赖
jni.h里的类型定义(比如jint、jstring)和函数接口,所以C文件/头文件里要加#include <jni.h>。 - 位置不用手动找:Android Studio会自动关联NDK里的
jni.h路径,直接写#include <jni.h>就行,不用额外配置。
2. C函数的JNI签名规则
要让Kotlin能识别C函数,函数名必须严格遵循JNI命名规范:
JNIEXPORT <返回类型> JNICALL Java_<包名>_<类名>_<函数名>(JNIEnv* env, jobject thiz, [参数列表])
- 包名里的
.要换成_,比如包com.example.myapp→com_example_myapp - 如果是静态函数,第二个参数是
jclass clazz(代替jobject thiz) - 返回类型和参数类型要对应JNI类型(比如Kotlin的
Int对应jint,String对应jstring)
3. 完整示例代码
3.1 C头文件(native-lib.h)
#include <jni.h> #ifndef _Included_com_example_myapp_NativeLib #define _Included_com_example_myapp_NativeLib #ifdef __cplusplus extern "C" { #endif // 普通函数:计算两数之和 JNIEXPORT jint JNICALL Java_com_example_myapp_NativeLib_addNumbers (JNIEnv *, jobject, jint, jint); // 静态函数:返回C端字符串 JNIEXPORT jstring JNICALL Java_com_example_myapp_NativeLib_getNativeString (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
3.2 C实现文件(native-lib.c)
#include "native-lib.h" JNIEXPORT jint JNICALL Java_com_example_myapp_NativeLib_addNumbers (JNIEnv *env, jobject thiz, jint a, jint b) { return a + b; } JNIEXPORT jstring JNICALL Java_com_example_myapp_NativeLib_getNativeString (JNIEnv *env, jclass clazz) { return (*env)->NewStringUTF(env, "Hello from C library!"); }
3.3 CMakeLists.txt配置
确保生成的.so库能被项目识别:
cmake_minimum_required(VERSION 3.22.1) project("mynativelib") # 编译C文件为共享库 add_library( mynativelib # 库名,Kotlin加载时要用到 SHARED native-lib.c) # 可选:链接NDK日志库,方便C端打日志 find_library( log-lib log) target_link_libraries( mynativelib ${log-lib})
3.4 Kotlin调用代码
先创建一个类声明native方法:
package com.example.myapp class NativeLib { // 加载.so库,名称和CMake里的mynativelib完全一致 init { System.loadLibrary("mynativelib") } // 声明native方法,签名和C函数对应 external fun addNumbers(a: Int, b: Int): Int // 静态native方法 companion object { external fun getNativeString(): String } }
然后在Activity里调用:
package com.example.myapp import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.TextView class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val nativeLib = NativeLib() // 调用普通native方法 val sum = nativeLib.addNumbers(5, 3) findViewById<TextView>(R.id.sample_text).text = "5 + 3 = $sum" // 调用静态native方法 val nativeStr = NativeLib.getNativeString() println(nativeStr) } }
4. 必踩坑提醒
- 库名必须完全匹配:CMake里的
add_library名称和Kotlin中System.loadLibrary的参数要一模一样(不用加lib前缀或.so后缀) - 函数签名不能错:包名、类名、函数名的下划线替换要精准,参数类型要对应(比如
jint对应Kotlin的Int,不能用Long) - C代码要加
extern "C":如果你的库是C写的,必须用extern "C"包裹函数声明,避免C++的名字修饰导致JNI找不到函数
内容的提问来源于stack exchange,提问作者eltomito
相关产品推荐
相关产品推荐

