Android Kotlin JNI参数传递异常求助:参数无法传入C++实现
解决JNI参数传递失效与Invalid JObject错误
看起来你踩了JNI和Kotlin交互中最常见的签名匹配坑!你遇到的invalid jobject和stale Local错误,核心原因是Kotlin外部函数的声明与C++ JNI函数的签名/参数不匹配——原生类型(Int)的容错性稍高,所以简单的加法函数能正常运行,但涉及对象类型(比如String)时,参数不匹配会直接导致引用失效,触发严格的JNI校验错误。
最可能的问题:Companion Object函数未加@JvmStatic
如果你的addnum5是在Activity的companion object里声明的,那必须给它加上@JvmStatic注解,同时对应的JNI函数第二个参数要从jobject改成jclass:因为Kotlin的伴生对象函数在JVM层面是静态方法,JNI调用静态方法时传递的是类引用(jclass)而非实例引用(jobject),写错参数类型会直接导致虚拟机传递的引用不匹配,触发错误。
修正后的代码示例
Kotlin端
class MainActivity : AppCompatActivity() { companion object { // 必须加@JvmStatic让JVM识别为静态方法 @JvmStatic external fun addnum5(desc: String, a: Int, b: Int): Int // 其他带对象参数的外部函数同理,静态声明都要加@JvmStatic @JvmStatic external fun hello(msg: String): String } }
C++端
// 第二个参数改成jclass,对应静态方法的类引用 extern "C" JNIEXPORT jint JNICALL Java_dx_wtf_MainActivity_addnum5(JNIEnv *env, jclass clazz, jstring desc, jint a, jint b) { LOGI("*** ENTRY POINT ***"); // 即使硬编码返回也不会再报错了 return 69; }
如果你的外部函数是直接在Activity类中(非伴生对象),那JNI函数用jobject thiz是正确的,但要确保类的全路径(dx.wtf.MainActivity)完全匹配,包名和类名不能写错。
彻底避免手动写错签名:用javap自动生成
手动写JNI函数名很容易出错,建议用javap工具自动生成正确的签名:
- 编译你的项目,找到编译后的字节码文件(一般在
app/build/intermediates/javac/debug/classes/dx/wtf/MainActivity.class) - 打开终端,进入该字节码所在的目录,执行命令:
javap -s -p dx.wtf.MainActivity
- 你会看到类似这样的输出,里面包含了每个方法的完整JNI签名:
public static native int addnum5(java.lang.String, int, int); descriptor: (Ljava/lang/String;II)I
根据这个签名来写JNI函数,绝对不会出错。
额外检查项
- 确保所有JNI函数都用
extern "C"修饰:C++会对函数名做名字修饰,不加extern "C"的话,虚拟机找不到对应的JNI函数,也会导致参数传递混乱。 - 添加字符串参数的空值处理:在读取jstring之前先判断是否为null,避免空指针异常:
if (desc == nullptr) { LOGI("传入的字符串为null"); return a + b; } const char *message = env->GetStringUTFChars(desc, nullptr); if (message != nullptr) { LOGI("收到字符串:%s", message); env->ReleaseStringUTFChars(desc, message); }
为什么原生类型的函数能正常运行?
因为JNI对于原生类型(比如Int对应jint)的参数,即使签名略有偏差,虚拟机可能还能勉强传递数值;但一旦涉及对象类型(String对应jstring),参数不匹配会直接导致引用失效,触发JNI的严格校验错误。
内容的提问来源于stack exchange,提问作者daparic
相关产品推荐
相关产品推荐

