#### Introduction After learning the basis of C language, we simply understand some paradigms of C language programming, understand Pointers, structures, unions, functions, file IO and so on. Our ultimate goal is to learn NDK development, and NDK development is inseparable from our JNI technology. Now, let’s start our JNI journey. #### The concept of JNI, JNI stands for Java Native Interface, Java Native Interface, you can call the API provided by the system through JNI. As we know, whether Linux or Windows or MAC OS, these operating systems, All rely on C/C++ written, but also include some assembly language to write the underlying hardware drivers. Java, unlike C/C++, does not compile directly to the platform machine code, but to Java bytecode. Class files that the VIRTUAL machine can run. JIT compiles to the machine code on the fly, so it is not as efficient as C/C++ code. Let’s look at the JNI call diagram below:

JNI can call C/C++, but JNI calls are still slower than native applications written in C/C++. However, for high performance computing, this is not a big deal. It has its drawbacks.

####JNI development process is as follows:

1. Write native method 2. Javah method, generate.h header file 3. Copy. H header files to CPP project 4. Copy jni.h and jni_md.h files to CPP project 5. Implement the function declared by the.h header file 6. Generate DLL file 7. Java project introduces the DLL file 8. Load the dynamic link library. 9. Run the Java class

####1. Write native methods

public class JniTest { public native static String getStringFromC(); public static void main(String[] args){ String text= getStringFromC(); System.out.printf(text); }}Copy the code

####2. Call the Javah method in Java and generate a. H header file to open the command line, run the CD command to go to the SRC directory of the current Java project, and run the javah command with the full class name:

D:\IdeaProjects\jni1\src>javah com.haocai.jni.JniTest
Copy the code

##### may appear if the file contains Chinese characters

Error: Unmappable character encoding GBKCopy the code

So you can specify the encoding format to solve this problem

D:\IdeaProjects\jni1\src>javah -jni -encoding UTF-8  com.haocai.jni.JniTest
Copy the code

The.h header is then generated in the SRC directory:

####3. Copy the. H header file to the CPP project. Copy the. H header file to the VS code file directory, in the solution header directory -> right-click -> Add -> Add existing items. Add our header file.

####4. Copy the jni.h and jni_md.h files to the CPP project

# JDK jni.h header file directoryD: \ Java \ jdk1.8.0 _60 \ include \ jni h# add jni_md.h to the jni_md.h headerD: \ Java \ jdk1.8.0 _60 \ include \ win32 \ jni_md hCopy the code

Add the jni.h header file to the header directory as described above. Change <> to “”, <> indicates that the system header file is imported, and” “indicates that the third-party header file is imported.

####5. Implement the functions declared in the.h header file.

Com_haocai_jni_JniTest. H content

#include <jni.h>
/* Header for class com_haocai_jni_JniTest */

#ifndef _Included_com_haocai_jni_JniTest
#define _Included_com_haocai_jni_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_haocai_jni_JniTest
 * Method:    getStringFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_haocai_jni_JniTest_getStringFromC
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif
Copy the code

Com_haocai_jni_JniTest. H header file function

/*
 * Class:     com_haocai_jni_JniTest
 * Method:    getStringFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_haocai_jni_JniTest_getStringFromC
  (JNIEnv *, jclass);
Copy the code

##### Create a new.c file, import our generated header file, and implement our generated C functions.

#include "com_haocai_jni_JniTest.h"JNIEXPORT jstring JNICALL Java_com_haocai_jni_JniTest_getStringFromC (JNIEnv *env, Jclass JCLS) {//JNIEnv structure pointer //env secondary pointer // represents the Java runtime environment, call Java code // simple implementation // C string into a Java stringreturn (*env)->NewStringUTF(env,"String From C");

}
Copy the code

#### Note: JNIEnv in JNI development is implemented differently in C and C++

JNIEnv: JNIEnv has a number of methods that interact with Java and represent the Java runtime environment. JNI Environment.

##### in C:

The JNIEnv structure pointer is an alias for the env secondary pointer

JNIEXPORT jString JNICALL Java_com_test_JniTest_getStringFromC (JNIEnv * env, jclass JCLS)return (*env)->NewStringUTF(env, "String From C");
}
Copy the code

##### in C++ :

JNIEnv is a first-level pointer to an alias env for a structure

JNIEXPORT jString JNICALL Java_com_test_JniTest_getStringFromC (JNIEnv * env, jclass JCLS){//env is a first-level pointer that does not need to be passed againreturn env->NewStringUTF("String From C");
}
Copy the code

Why use secondary Pointers:

Why do I need to pass in JNIEnv? JNIEnv is required during function execution

Why didn’t C++ come in? Because C++ has this pointer. C++ is just a set of C encapsulation, to a variable assigned to a pointer, the variable is a secondary pointer source analysis

In the jni.h header file there is the following precompiled code:

#ifdef __cplusplus
typedef JNIEnv_ JNIEnv;
#else
typedef const struct JNINativeInterface_ *JNIEnv;
#endif
Copy the code

In a C environment, JNIEnv is a pointer alias to the JNINativeInterface_ structure. In a C++ environment, JNIEnv is an alias for the structure JNIEnv_, which encapsulates JNINativeInterface_. #####C language structure and pointer related knowledge review Android NDK development journey 6–C language structure

struct Man
{
    char name[20];
    int  age;
};

void main() {
    struct Man m1 = { "Jack", 30}; Struct Man *p = &m1;printf(" %s, %d\n", m1.name, m1.age);
    printf(" %s, %d\n",(*p).name,(*p).age);
    //"- >"The arrow is"(*P)."The shorthandprintf(" %s, %d\n", p->name, p->age);

    system("pause"); } Result output: Jack, 30 Jack, 30 Jack, 30Copy the code

##### The NewStringUTF function in C language is roughly implemented as follows:

#include <stdio.h>Typedef struct JNINativeInterface_* JNIEnv; Char * (*NewStringUTF)(JNIEnv*, char*); }; Char * NewStringUTF(JNIEnv* env,char* STR) {//NewStringUTF (JNIEnv* env,char* STRreturn str;
}


void main() {// instantiate struct JNINativeInterface_ struct_env; struct_env.NewStringUTF = NewStringUTF; JNIEnv e = &struct_env; JNIEnv *env = &e; Char * STR = (*env)->NewStringUTF(env,"abc");

	printf("%s", str); getchar(); } Result output: ABCCopy the code

That is, when we call the following statement in C:

(*env)->NewStringUTF(env, "String From C");
Copy the code

Env is a second-level pointer to a structure, which takes the content *. Env is a first-level pointer that allows you to manipulate the structure with the -> symbol. The NewStringUTF function uses JNIEnvironment, so we need to pass in the second-level pointer env itself.

In C++, however, JNIEnv is an alias for a structure. The structure itself can also be accessed using a first-level pointer, but since the this keyword represents itself in C++, you can omit the passing argument (already wrapped).

struct JNIEnv_ {
    const struct JNINativeInterface_ *functions;

    jstring NewStringUTF(const char *utf) {
        return functions->NewStringUTF(this,utf); } // code omitted}Copy the code

As shown above, JNIEnv in C++ is the alias of JNIEnv_, and JNIEnv_ is a wrapper around JNINativeInterface_. When a function is called, the JNINativeInterface_ constructor is called:

functions->NewStringUTF(this, utf);
Copy the code

NewStringUTF (JNINativeInterface_); NewStringUTF (JNINativeInterface_); NewStringUTF (JNINativeInterface_) So in C++ you can use this pointer directly to represent the current caller’s pointer (secondary pointer), whereas in C speech you need a secondary pointer to do this.

####6. Generate a dynamic link library DLL file

The library name features extension
The dynamic library 1. Dynamic libraries defer loading links to some library functions until the program runs

2. Resources can be shared between processes. (Hence dynamic libraries are also called shared libraries.)

3. Can be dynamically injected into the program
win(.dll)linux(.so)
Static library Static library links to function libraries are done at compile time.

2. The program has nothing to do with the function library during operation, which is convenient for transplantation.

3. Waste of space and resources because all related object files are linked together into an executable file with the involved library.
win(.lib)linux(.a)

Now that we know about static and dynamic libraries, let’s generate a dynamic library, using VS as an example:

Select Project -> Right-click -> Properties -> General -> Project Default -> Configuration Type and select dynamic library. DLLCopy the code

When the configuration is complete, select Project -> Build. Can generate dynamic link library. DLL file.

####7. The Java project imports this DLL file

####8. Load the dynamic link library

Static {system.loadLibrary ();"jni1");
    }
Copy the code

####9. Run the Java class

public class JniTest { public native static String getStringFromC(); public static void main(String[] args){ String text= getStringFromC(); System.out.printf(text); } // loadLibrary static{system.loadLibrary ()"jni1"); }}Copy the code

# # # # output:

String From C
Copy the code

# # # #

##### this is the beginning of the JNI series, and the process is relatively simple. However, we need to understand the structure and pointer knowledge behind JNIEnv to lay a foundation for further study of JNI.

Special thanks to Jason At The Brain Institute