我正在尝试在使用 Kotlin 的 Android Studio 项目中使用使用 cmake 构建的 C 库。 到目前为止,我已经能够在 Android Studio 中安装 NDK 和 cmake,将 C 库的 CMakeLists.txt 文件包含在项目中并编译项目,以便我在其中看到 .so 文件。
但我不知道如何从 Kotlin 调用 C 库函数。 C 库头文件应该包含 jni.h 吗?如果是这样,我在哪里可以找到它?库 API 函数的签名应该是什么,以便 Android Studio 能够看到它们?如何在 Android Studio Kotlin 中使用这些?
我知道有很多文档,但它们确实很零散且令人困惑,其中大部分都指向 Kotlin Native 或 java。我希望能够提供用于定义库 API 的 C 头文件的清晰代码示例以及使用它的 Kotlin 文件。 我的意思是,我是在 .kt 文件中导入某些内容还是什么?
谢谢您,非常感谢您的帮助!
我弄清楚了如何在 Koltin Android Studio 项目中使用使用 CMake 构建的共享 C 库:
在 Andoid Studio 中,将新的 cmake 共享库添加到您的 Kotlin 项目中 并指向库的 CMakeLists.txt
在 MainACtivity.kt 的顶部范围中声明 C 库函数,如下所示:
外部乐趣 addNumbers(a:Int, b:Int) :Int
C库头文件中的函数名必须包含 很多与项目相关的前缀。如果您添加此外部声明,然后打开红色灯泡旁边的菜单,告诉您找不到此功能,Android Studio 会告诉您这些是什么。在那里,您将找到一个在 C 文件中创建函数的选项,因此执行此操作,它将具有完整的前缀名称。
一旦 cmake 构建的 C 库成为项目的一部分,您必须使用“构建”菜单中的“刷新链接的 C++ 项目”来刷新它。每当您更改 C 库源时都需要执行此操作。
然后你只需构建你的项目就可以开始了。
Android 在 https://github.com/android/ndk-samples 提供了超级有用的示例。
这些的主要收获是:
让我们创建并使用一个名为 doSomething 的 C 库。 它提供了两个公共函数,展示如何将数字和字符串参数传递给 并从 Kotlin 中的 C 库返回它们。 该项目的名称是 Greeting Card(是的,这是一个 Kotlin 教程项目)。
#you should always set this
cmake_minimum_required(VERSION 3.22)
project(doSomething VERSION 1.0.0 DESCRIPTION "An exercise to build a C library with CMake in Android Studio.")
add_library(doSomething SHARED src/doSomething.c )
set_target_properties(doSomething PROPERTIES VERSION ${PROJECT_VERSION})
# this is where the header file is
set_target_properties(doSomething PROPERTIES PUBLIC_HEADER include/doSomething.h)
# define include base dir for the sources
target_include_directories(doSomething PRIVATE include)
target_include_directories(doSomething PRIVATE src)
/* Dont worry where the jni.h header comes from.
* Android Studio takes care of that.
*/
#include <jni.h>
/* JNIEXPORT and JNICALL are magic words that just have to be there.
* jint is the type of the returned value.
* The full name of the function with all the prefixes
* is generated by Android Studio as described above.
*/
JNIEXPORT jint JNICALL
Java_com_example_greetingcard_MainActivityKt_addNumbers(JNIEnv *env, jclass thiz, jint a, jint b);
JNIEXPORT jstring JNICALL
Java_com_example_greetingcard_MainActivityKt_flipString(JNIEnv *env, jclass thiz, jstring instr);
#include "include/doSomething.h"
#include <stdio.h>
#include <string.h>
JNIEXPORT jint JNICALL
Java_com_example_greetingcard_MainActivityKt_addNumbers(JNIEnv *env, jobject thiz, jint a, jint b) {
return a + b;
}
JNIEXPORT jstring JNICALL
Java_com_example_greetingcard_MainActivityKt_flipString(JNIEnv *env, jobject thiz, jstring instr) {
char *str;
jboolean isCopy;
// Get the string from the kotlin parameter
str = (*env)->GetStringUTFChars(env, instr, &isCopy);
size_t len = strlen( str );
for( size_t i = 0; i < len / 2; ++i ) {
char c = str[i];
str[i] = str[ len - i - 1 ];
str[ len - i - 1] = c;
}
return (*env)->NewStringUTF(env,str);
}
在此文件的顶部范围(即不在 MainActivity 类内),声明 C 库中的函数:
external fun addNumbers( a:Int, b:Int) :Int
external fun flipString( instr: String ): String
然后您可以按照预期在 MainActivity.kt 文件中的任何位置使用它们:
println("If we add 1 + 2, we get ${addNumbers(1,2)}!")
println("Flip \"dog\" and get \"${flipString("dog")}\".")