我正在try 构建一个Kotlin/Native库,并在Android应用程序中使用它.我实际上希望使用预构建的共享库,而不是.jar,因为我希望我的代码被混淆.

我已经设法让我的Kotlin/Native库在我的Android应用程序中使用JNI和许多试验和错误.问题是,我只使用这个Kotlin/Native代码创建了一个非常简单的"Hello world"函数:

fun sayHello(): String {
    return "Hello, Kotlin/Native!"
}

以下是JNI的C++代码:

extern "C" JNIEXPORT jstring JNICALL
Java_com_my_package_NativeLib_sayHello(
        JNIEnv *env,
        jobject /* this */) {
    libshared_lib_ExportedSymbols *lib = libshared_lib_symbols();
    return env->NewStringUTF(lib->kotlin.root.sayHello());
}

最后是我的Android类中的这段Kotlin代码:

class NativeLib {
    external fun sayHello(): String

    companion object {
        init {
            System.loadLibrary("native-lib")
        }
    }
}

郑重声明,我正在将带有Gradle的Kotlin/Native构建为Android Target的预置共享库.然后我将.so文件复制/粘贴到我的应用程序的libs文件夹中,然后使用一些Gradle魔术让它正常工作.

然而,当我开始编写一个函数时,它变得更复杂了,该函数使用一个字节数组作为参数,如下所示(实现与此无关):

fun readByteArray(byteArray: ByteArray): String {
    val unsignedByteArray = byteArray.toUByteArray()
    var i = 0

    while (i < byteArray.size) {
        // Access the array
        val byte = unsignedByteArray[i].toUInt()
    }

    return "Done reading the array"
}

然后将这个添加到我在Android端的NativeLib个类中:

external fun readByteArray(byteArray: ByteArray): String

JNI C++的类似功能应该是什么:

extern "C" JNIEXPORT jstring JNICALL
Java_com_my_package_NativeLib_readByteArray(JNIEnv *env, jobject,
                                            jbyteArray byte_array) {
    libshared_lib_ExportedSymbols *lib = libshared_lib_symbols();
    // What to do here?
    return env->NewStringUTF(lib->kotlin.root.readByteArray(/* and here? */));
}

问题是Kotlin/Native正在生成这个头文件:

typedef void* libshared_lib_KNativePtr;
...
typedef struct {
  libshared_lib_KNativePtr pinned;
} libshared_lib_kref_kotlin_Byte;
...
typedef struct {
  libshared_lib_KNativePtr pinned;
} libshared_lib_kref_kotlin_ByteArray;
...
struct {
  struct {
    const char* (*readByteArray)(libshared_lib_kref_kotlin_ByteArray byteArray);
    const char* (*sayHello)();
  } root;
} kotlin;
...

这就是我被困住的地方,我到底应该如何制造一个libshared_lib_kref_kotlin_ByteArray?以下是我到目前为止所try 的方法,但在代码试图读取数组时发生崩溃:

extern "C" JNIEXPORT jstring JNICALL
Java_com_my_package_NativeLib_readByteArray(JNIEnv *env, jobject,
                                            jbyteArray byte_array) {
    libshared_lib_ExportedSymbols *lib = libshared_lib_symbols();
    libshared_lib_KNativePtr ptr = env->GetDirectBufferAddress(byte_array);
    libshared_lib_kref_kotlin_ByteArray byteArray;
    byteArray.pinned = ptr;
    return env->NewStringUTF(lib->kotlin.root.readByteArray(byteArray));
}

我也试过使用GetByteArrayElements(),但没有成功. 有人知道如何处理那些Kotlin生成的类型吗?

推荐答案

正如Botje在我问题的注释中所述,我似乎需要在Kotlin/Native函数中使用C互操作类型,才能从JNI C代码中正确地调用它.

下面是我不得不编写的Kotlin/Native代码:

fun readByteArray(byteArray: CPointer<ByteVar>, length: Int): String {
    // Convert the C interop array type to a standard Kotlin type
    val ktByteArray = byteArray.readBytes(length)

    // Here access the `ktByteArray` as we would any Kotlin array

    return "Done reading the array"
}

下面是将其与我的Kotlin JVM代码绑定在一起的C++JNI粘合剂:

extern "C" JNIEXPORT jstring JNICALL
Java_com_my_package_NativeLib_readByteArray(JNIEnv *env, jobject,
                                            jbyteArray byte_array) {
    libshared_lib_ExportedSymbols *lib = libshared_lib_symbols();
    jsize len = env->GetArrayLength(byte_array);
    jbyte *nativeByteArray = env->GetByteArrayElements(byte_array, nullptr);
    const char *response = lib->kotlin.root.readByteArray(nativeByteArray, len);
    return env->NewStringUTF(response);
}

Android相关问答推荐

为什么使用. DeliverveAsState()时会出现空指针异常?

写入排除例外以进行依赖性判断

使用Kotlin的SD卡

懒惰的垂直网格中盒子的重量-Jetpack组合

Kotlin DSL:为什么我可以从Play Store获取发布版本的日志(log)?

在模块中找到重复的类com.google.Firebase.auth.ktx.AuthKt||Android Studio

登录方法显示为空列表,即使它显示的是Firebase身份验证控制台

在以XML格式设置完整屏幕视图时可见App Compat按钮

在带有REACT-Native-CLI的开发和生产中使用Firebase的最佳实践

使用lazyColumn迁移paging3的旧代码

Camera2 将图像从 ImageReader 传递到 MediaRecorder

为什么我的应用程序使用这些信息?

如何在 Jetpack Compose 中设置卡片高度

我该怎么做文本计时器

Jetpack Compose 部分或开放侧边框

在 Kotlin 中循环遍历字符串并用新行替换句号

并行运行两个挂起函数并在第一个返回时返回

Jetpack Compose:对角拆分卡片并将内容放入其中

WindowManager 内的 RecyclerView 不更新

为什么我不能在屏幕外拿任何物体