阅读量:2
在Kotlin和C++之间通过JNI进行接口传递时,需要注意两边参数定义的映射关系。JNI(Java Native Interface)为Java(Kotlin也适用)与本地语言(如C/C++)之间的交互提供了桥梁。在Kotlin中定义的外部函数和C++中的实现需要通过JNI签名相互对应。
Kotlin端
在Kotlin中,我们定义一个包含external
方法的类。例如:
package com.example.native class NativeLib { external fun stringFromJNI(): String external fun addNumbers(a: Int, b: Int): Int companion object { init { System.loadLibrary("native-lib") } } }
C++端
在C++中,我们需要定义与Kotlin中external
方法对应的函数实现,并使用正确的JNI签名。每个参数类型在JNI中都有对应的类型签名。
常见JNI类型签名
Kotlin类型 | JNI签名 | C++类型 |
---|---|---|
Int | I | jint |
Long | J | jlong |
Boolean | Z | jboolean |
Byte | B | jbyte |
Char | C | jchar |
Short | S | jshort |
Float | F | jfloat |
Double | D | jdouble |
String | Ljava/lang/String; | jstring |
Array | [ | jarray |
Object | L…; | jobject |
示例:实现stringFromJNI
和addNumbers
生成JNI头文件:
假设已经生成了Kotlin类对应的.class文件,可以使用
javac
生成头文件:javac -h . path/to/classes/com/example/native/NativeLib.class
生成的头文件
com_example_native_NativeLib.h
可能如下所示:/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_native_NativeLib */ #ifndef _Included_com_example_native_NativeLib #define _Included_com_example_native_NativeLib #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_native_NativeLib * Method: stringFromJNI * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_native_NativeLib_stringFromJNI (JNIEnv *, jobject); /* * Class: com_example_native_NativeLib * Method: addNumbers * Signature: (II)I */ JNIEXPORT jint JNICALL Java_com_example_native_NativeLib_addNumbers (JNIEnv *, jobject, jint, jint); #ifdef __cplusplus } #endif #endif
实现C++方法:
创建对应的C++文件
native-lib.cpp
,并实现这些方法:#include <jni.h> #include <string> #include "com_example_native_NativeLib.h" JNIEXPORT jstring JNICALL Java_com_example_native_NativeLib_stringFromJNI(JNIEnv *env, jobject obj) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } JNIEXPORT jint JNICALL Java_com_example_native_NativeLib_addNumbers(JNIEnv *env, jobject obj, jint a, jint b) { return a + b; }
调用过程
加载本地库:
在Kotlin中,加载本地库并调用本地方法:
package com.example.main import com.example.native.NativeLib fun main() { val nativeLib = NativeLib() val resultString = nativeLib.stringFromJNI() val sum = nativeLib.addNumbers(3, 5) println(resultString) // 输出: Hello from C++ println(sum) // 输出: 8 }
确保本地库存在:
确保
native-lib
库文件存在并可以在运行时加载。通常在Android项目中,会把.so文件放在src/main/jniLibs/
目录下。
注意
- 方法签名必须完全匹配,包括参数类型和返回类型。
JNIEnv
指针和jobject
对象是每个本地方法的必需参数。- 字符串和数组等复杂类型需要使用JNI提供的函数进行转换和操作。