You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 13:16:11