c/c++和java交互,需要找到双方各自对应的函数或方法来调用。这种产生联系的方式有两种方式,一个是静态注册,另一种事动态注册。动态注册是比静态注册的好处是不需要JNI那一套很长的命名。

其他的规则和静态注册无异,只是注册的地方不同而已。

下面是动态注册的方式。

/**
 * 动态注册
 */
extern "C" {

jstring stringFromJNI2(JNIEnv *env, jobject instance) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

jint add(JNIEnv *env, jclass clazz, jint a, jint b) {
    LOGE("ADD!!");
    return a + b;

}

#define JNIREG_CLASS "com/slzr/ndk/NDKManager"//指定要注册的类
/**
* 方法对应表
*/
static JNINativeMethod gMethods[] = {
//        {"stringFromJNI2", "()Ljava/lang/String;", (void *) stringFromJNI2},
        {"add",            "(II)I",                (void *) add}
};

/*
* 为某一个类注册本地方法
*/
static int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *gMethods,
                                 int numMethods) {
    jclass clazz;
    clazz = env->FindClass(className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }
    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
        return JNI_FALSE;
    }

    return JNI_TRUE;
}


/*
* 为所有类注册本地方法
*/
static int registerNatives(JNIEnv *env) {
    return registerNativeMethods(env, JNIREG_CLASS, gMethods,
                                 sizeof(gMethods) / sizeof(gMethods[0]));
}

/*
* System.loadLibrary("lib")时调用
* 如果成功返回JNI版本, 失败返回-1
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    jint result = -1;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }
    assert(env != NULL);
    if (!registerNatives(env)) {//注册
        return -1;
    }
    //成功
    result = JNI_VERSION_1_6;
    return result;
}
}

这里说明一下,JNI_OnLoadSystem.loadLibrary加载完动态库执行的函数,写在jni.h里面。
registerNatives写本地的方法。gMethods写方法列表,第一参数是java里面的方法名称,第二参数是方法输入参数,第三个参数是c/c++里面对应的函数。它的结构类型如下:

typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;

第二个参数可以参照java的反射。

字符 Java类型 C类型
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

数组则以"["开始,用两个字符表示。
[I       jintArray      int[]
[F     jfloatArray    float[]
[B     jbyteArray    byte[]
[C    jcharArray    char[]
[S    jshortArray   short[]
[D    jdoubleArray double[]
[J     jlongArray     long[]
[Z    jbooleanArray boolean[]

gMethods里面的第二参数()表示输入参数,有多少就写多少进去。比如说两个int参数,就写(II)。括号后面跟着的是返回值V表示没有返回值void。Ljava/lang/String;对应是String类型。Ljava/lang/Object;对应是Object类型。

在java层面仍然需要native 编写。

    public native int add(int a, int b);

附件:
demo源码地址

打赏 赞(0)
微信
支付宝
微信二维码图片

微信扫描二维码打赏

支付宝二维码图片

支付宝扫描二维码打赏

分类: Android

0 条评论

发表评论

电子邮件地址不会被公开。