Dynamic registration of Android JNI (android studio)

The story has to start here - static registration

Without comparison, there is no harm. Static registration has been criticized a lot since its birth. The cumbersome process (javah generates the header file), every time an interface is added, the slag needs to be h. Long function names, a detailed identification. The operating efficiency is low. When communicating for the first time, it is more difficult to find the person with the corresponding identity in jni according to the detailed identity. Compare them one by one. If you are lucky, a relationship is established after one match. If, say If, by the end, the day lilies were all cold. When it is difficult, when it is time to give up, it is time for man to appear on the stage, dynamic registration, yes, it is him. There is a function mapping table in JNI, which is registered to the Java virtual machine. It is love at first sight, and the communication is so smooth.

Dynamic registration, draw a few circles

There are still rules. Establish the database early and communicate immediately.

one. Entry JNI_OnLoad method

After System.loadLibrary loads the JNI dynamic library, it calls the JNI_OnLoad function to start dynamic registration. This is the place to register. You can’t find the wrong place. If you report to the police to catch a thief, you have to call 119. I am also very sad, but there is nothing I can do. Note: There can only be one onload method in one .so.

two. The highlight of the RegisterNatives method

In the JNI empire, I have to introduce JNIEnv*, the spokesperson of the JVM, who holds the power of life and death in java. The pointer to the java environment variable is a structure that contains the JVM interface, which includes the necessary to interact with the JVM and work with Java objects The function. And RegisterNatives is just one of the pawns, the registrar. But only through him can you enter the function mapping table. Function map? Don't worry, let's take our time and peel off his heart step by step. In the jni.h empire, there is such a paragraph in the description:

typedef struct { 
    const char* name; //Java中函数的名字
    const char* signature; //描述了函数的参数和返回值
    void* fnPtr; //函数指针,指向我们调用别人家c++的封装 JNI 函数方法
} JNINativeMethod; 

This is the data structure of the function mapping table. With the addition of comments, there seems to be nothing to explain. As for the tedious source code parsing, how is this structure used? Cough cough cough, back to the topic, the highlight of RegisterNatives, this is a court epic drama, careful layout, grand scenes. Let's put it this way, there are only three actors, A, B, and C, who will co-star in the ending of a story where either you die or I die. This passage is recorded in the script:

/**
 * 向JNI环境注册一个本地方法
 * @param clazz  包含本地方法的Java类
 * @param methods 本地方法描述数组
 * @param nMethods 本地方法个数
 * @return 成功返回0,否则注册失败
 */
jint RegisterNatives(jclass clazz, const JNINativeMethod *methods, jint nMethods);

Unknowingly, with hindsight, a comment completes the analysis. Keep it simple, keep it simple in the way you speak. I, who should cooperate with your performance, turn a blind eye. The registrar's description is roughly the same. If you have more needs, please do your own research.

three. End the JNI_OnUnload method

Those who come out to hang out will have to pay back sooner or later, and the huge JNI empire will end one day. When the VM releases the component, it will call the JNI_OnUnload method. All the objects that it once owned, such as objects, will return to the earth here and turn into spring mud to protect flowers. Of course, you can also choose to give up and leave this method aside, then the poisonous mushrooms will thrive one day, slowly and slowly, and then boom. Optimization is an option for you and me.

Four. Miracle Witness Moment

I have to say, at this moment, I am very excited. Flowers, why are you so red? Paste the code a little bit, with a little detail:

static const char *jniClassName = "net/mapout/jni/JNILoader";
static JNINativeMethod methods[] = {
        {
   
   "sayHello", "()Ljava/lang/String;", (void*)jniSayHello},
};

static int registerNatives(JNIEnv* env) {
    jclass clazz = env->FindClass(jniClassName);
    if (clazz == NULL)
        return JNI_FALSE;

    jint methodSize = sizeof(methods) / sizeof(methods[0]);
    if ( env->RegisterNatives(clazz, methods, methodSize) < 0 )
        return JNI_FALSE;

    return JNI_TRUE;
}

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 JNI_ERR;

    //注册方法
    if (!registerNatives(env))
        return JNI_ERR;

    result = JNI_VERSION_1_6;
    return result;
}

JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
    JNIEnv *env = nullptr;
    jint ret = vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
    if (ret != JNI_OK) {
        return ;
    }
    //回收二手女朋友,回收... 嘿嘿嘿
}

At a glance, what we need to maintain is the array of methods, and the rest is copy and paste. For a little comparison:

/**
 * 动态注册。命名简洁,清晰明了
 */
jstring jniSayHello(JNIEnv *env, jobject obj){
     return str2jstring( env, sayHello() );
}

/**
 * 静态注册。噗噗噗,一口老血喷涌而出
 */
JNIEXPORT jstring JNICALL Java_net_mapout_jni_JNILoader_sayHello
  (JNIEnv *env, jclass jclass){
    return str2jstring( env, sayHello() );
}

Another note. For the code, there is no comment that can't make it clear. If there is, please use two comments. To talk about the details, the function here has 2 parameters, a JNIEnv * has been explained, and a jobject. Slightly speaking, if the native method does not have static, then it is an instance of the class. If it is armed with static, it will be enhanced by evolution and become an instance of the class object of the class. Dynamic registration, that's what it is, it's time to show your strength.

Dynamic registration project structure diagram

Guess you like

Origin blog.csdn.net/youyi300200/article/details/72841441