Android NDK - JNI中回调Java中的函数

2018-02-22  本文已影响524人  chengjian666

在实际应用中,除了在JNI层对部分功能进行C++的实现,同时还会有在JNI中对Java函数的调用以实现某种逻辑的联通。
在JNI中回调Java函数,实际上是通过反射机制来实现的,通过反射机制取得目标函数所在的类,以及其名称,通过NDK提供的接口在JNI层进行调用。

JNI中调用Java函数的栗子

package com.test.jni;
public class TestFunction {
    
    public static void testFunc(){
        Log.d("tag from Java", "worked!");
    }
}
const char[] method_class_from_java = "com/teest/jni/TestFunction";
const char[] method_name_from_java = "testFunc";
jclass cls_str_id = jenv->FindClass(method_from_java);
jmethodID m_Java_TestFunc = jenv->GetStaticMethodID(cls_str_id, method_name_from_java, "()V");
jenv->CallStaticObjectMethod(cls_str_id, m_Java_TestFunc);

通过如上方式就可以实现在JNI中调用Java中函数,具体解释如下:

其中jenv为JNI函数的环境参数,注意在反射获取java函数时其参数及返回值数据类型的签名。

NDK中数据类型签名规则

关于NDK中的签名规则如下:

字符签名 jni中类型 java中类型
V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short
字符签名 jni中类型 java中类型
[Z jbooleanArray boolean[]
[I jintArray int[]
[J jlongArray long[]
[D jdoubleArray double[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]

而对于数组而言,需要以"["开始,组合以上规则即可,具体对应关系表如下:

字符签名 jni中类型 java中类型
[Z jbooleanArray boolean[]
[I jintArray int[]
[J jlongArray long[]
[D jdoubleArray double[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]

以上均为基本数据类型的签名,对于另外两种情况:

  1. Java类(包括自定义类)
    对于参数或者返回值类型是Java类的情况,需要以"L"开头,并且以";"结束,并且以"/"隔开包名路径,并且此时在JNI中其对应接收的类型为jobject, 而对于基本数据类型,则使用其对应的NDK中的数据类型表示即可。比如:
"Landroid/os/FileUtils;"
  1. Java内部类
    对于参数或者返回值类型是Java类中的内部类的情况,则需要在以上基础结合"$"索引,比如:
"Landroid/os/FileUtils$FileStatus;"

讲到这里,基本上十分清楚了,但是有一个特殊情况,细心的同学应该可以发现,以上列表中我们并没有标记String类型。那是因为确实存在一个例外情况一定要当心,那就是String类。在使用其签名时,要使用:

"Ljava/lang/String;"

如果直接使用jstring,那就会找不到。这个例外情况一定要当心。

JNI中的 JNIEnv 和 jobject

在每个JNI对Java层开发的native函数中,第一第二个参数均是如下形式:

static void JNICALL test (JNIEnv *jenv, jobject obj)
上一篇下一篇

猜你喜欢

热点阅读