Static registration refers to the association between Java native methods and corresponding local functions according to predefined naming rules, which implements the binding between Java native methods and local functions. These functions will be statically registered in the JVM when the Java class is loaded to ensure that the JVM can correctly find the corresponding functions.
Dynamic registration is to provide a mapping table that corresponds to the local function one by one, and then register the mapping table to the JVM in the JNI_OnLoad callback. In this way, the JVM can use this mapping table to call the corresponding function, without having to search for the function name to be called through the function name like static registration. Therefore, the local function name does not need to follow specific naming rules.
PS: There is no direct relationship between static registration and static libraries in JNI. Whether it is static registration or dynamic registration, dynamic libraries (.so files) or static libraries (.a files) can be generated.
public class MainActivity extends AppCompatActivity { // Used to load the 'myjni' library on application startup. static { ("myjni"); } @Override protected void onCreate(Bundle savedInstanceState) { (savedInstanceState); // String str = stringFromJNI(); ("TAG", "onCreate: str="+str); } /** * A native method that is implemented by the 'myjni' native library, * which is packaged with this application. */ public native String stringFromJNI(); //java native method}
Static registration
The function names of local functions need to follow the format of Java_class fully qualified name_method name (in the fully qualified name of the class fully qualified name. It needs to be replaced with _) naming specification.
extern "C" JNIEXPORT jstring JNICALL Java_com_louis_myjni_MainActivity_stringFromJNI( JNIEnv* env, //JNIEnv refers to the current JNI environment, and Java layer code can be operated using JNIEnv jobject /* this */) { //jobject refers to the instance object of the class where the java native method is located in the corresponding JNI function. If the native method is static, the type needs to be changed to jclass, which represents the class object std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); }
Dynamic registration
- When the Java layer calls a method, the JNI_OnLoad function is called when the library is loaded into the Java virtual machine.
- PS: For example, the JNI function and FFmpeg related functions of Android system are used dynamic registration
//Define local function, function name arbitraryjstring stringFromJNI_JNI_OnLoad(JNIEnv *env, jobject/* this */) { std::string hello = "Hello from C++ stringFromJNI_JNI_OnLoad"; return env->NewStringUTF(hello.c_str()); } //Define a JNINativeMethod structure array (map table), the structure contains the Java method name, method signature (method descriptor), and pointers to the corresponding associated local functionJNINativeMethod nativeMethods[] = { //stringFromJNI corresponds to Java native method, stringFromJNI_JNI_OnLoad corresponds to local function {"stringFromJNI", "()Ljava/lang/String;", (jstring *) stringFromJNI_JNI_OnLoad} }; // When Java calls, the JNI_OnLoad function will be executed//JavaVM *vm parameter is a pointer to a Java virtual machine, through which the JVM functions can be accessed//void *reserved is a reserved parameter and is usually not usedJNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env; //Get the JNI environment associated with the current thread if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { LOGE("Failed to obtain JNI environment"); return JNI_ERR; } // Find and load a class through the fully qualified name of the class, and return a jclass reference pointing to the class. jclass clazz = env->FindClass("com/louis/myjni/MainActivity"); if (clazz == NULL) { LOGE("Failed to obtain jclass"); return JNI_ERR; } //Calculate the length of the arr array int length = sizeof(arr) / sizeof(arr[0]); int nMethods = sizeof(nativeMethods) / sizeof(nativeMethods[0]); // Parameter nMethods Specifies the number of NativeMethods in the array if (env->RegisterNatives(clazz, nativeMethods, nMethods) != JNI_OK) { LOGE("Registering a local function failed"); return JNI_ERR; } LOGE("Registered successfully"); return JNI_VERSION_1_6; //Return the currently supported JNI version number}
Summarize
Static registration is simple and easy to use. Functions must have related declarations like JNIEXPORT jstring JNICALL, and the function names must be named according to JNI naming rules. Since JNI function names are exposed, there are certain security risks.
Dynamic registration is flexible and does not rely on fixed naming rules. However, you need to register and manually associate it yourself, so you can choose different implementations according to the conditions at runtime, which is more suitable for complex projects.
This is the end of this article about a brief analysis of JNI static registration and dynamic registration in Java. For more related contents of JNI static registration and dynamic registration, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!