如何在Android中通过JNI调用带ByteArray参数的Kotlin/Native预构建共享库
问题:Kotlin/Native共享库JNI调用ByteArray参数崩溃问题
我正在构建Kotlin/Native库并在Android应用中使用,因需要代码混淆,选择预构建共享库而非.jar文件。目前已通过JNI成功调用简单的"Hello World"函数,但在实现接收ByteArray参数的readByteArray函数时遇到问题:不清楚如何构建Kotlin/Native生成的libshared_lib_kref_kotlin_ByteArray类型,尝试使用GetDirectBufferAddress和GetByteArrayElements均导致崩溃,求解决方法。
相关代码
Kotlin/Native代码
fun readByteArray(byteArray: ByteArray): String { val unsignedByteArray = byteArray.toUByteArray() var i = 0 while (i < byteArray.size) { // Access the array val byte = unsignedByteArray[i].toUInt() i++ } 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_ByteArray; ... struct { struct { const char* (*readByteArray)(libshared_lib_kref_kotlin_ByteArray byteArray); const char* (*sayHello)(); } root; } kotlin; ...
解决方案
不能直接用JNI数组操作函数强转生成libshared_lib_kref_kotlin_ByteArray,必须通过Kotlin/Native提供的内存管理API创建对应Kotlin ByteArray实例,具体实现步骤如下:
- 获取JNI数组的原始数据指针和长度
- 调用Kotlin/Native生成的数组创建API生成Kotlin ByteArray对象
- 将对象指针封装为要求的结构体类型
- 调用目标函数后释放所有资源,避免内存泄漏
完整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(); // 1. 获取Java ByteArray的原始数据和长度 jbyte* src_bytes = env->GetByteArrayElements(byte_array, nullptr); jsize byte_count = env->GetArrayLength(byte_array); // 2. 创建Kotlin/Native ByteArray实例 libshared_lib_KNativePtr kotlin_byte_array = lib->kotlin.ByteArrayOf(src_bytes, byte_count); // 3. 封装为要求的结构体 libshared_lib_kref_kotlin_ByteArray kref_byte_array; kref_byte_array.pinned = kotlin_byte_array; // 4. 调用Kotlin函数 const char* result_str = lib->kotlin.root.readByteArray(kref_byte_array); // 5. 释放JNI数组引用 env->ReleaseByteArrayElements(byte_array, src_bytes, JNI_ABORT); // 6. 转换结果为Java String jstring result = env->NewStringUTF(result_str); // 7. 释放Kotlin对象,避免内存泄漏 lib->DisposeStablePointer(kotlin_byte_array); return result; }
关键说明
- 数组创建API:Kotlin/Native会自动生成
ByteArrayOf这类数组创建函数,一般挂载在kotlin结构体下,可在完整生成的头文件中确认具体命名。 - 内存管理:Kotlin/Native创建的对象必须用
DisposeStablePointer释放;JNI数组引用必须通过ReleaseByteArrayElements释放。 - 禁止直接强转:
libshared_lib_kref_kotlin_ByteArray的pinned字段是Kotlin/Native内部稳定指针,不能直接赋值JNI数组指针,必须通过官方API生成。
内容的提问来源于stack exchange,提问作者Paul-Etienne
相关产品推荐
相关产品推荐

