Android JNI introduction includes a complete Demo

  • What is the JIN
  • Environment configuration
  • Generate C header file details
  • Native layer changes the value of Java properties (non-static)
  • Native layer changes the value of Java properties (static)
  • Native calls Java static methods
  • Attribute signature

What is the JIN

Java Native Interface (JNI) is a Java native Interface that translates Java to C/C++ communication.

Baidu encyclopedia

Environment configuration

NDK(Side by Side)

CMake needs to be used later, so it’s best to download it



New project:



Choose Native C++ and go to the next step!

Generate C header file details

Defining a constant of type int in mainActivity generates a macro in the C header file

Automatically generate header C header file:

Step 1: Access the Java directory in your project

My address is: the CD Desktop/AndroidProject/JNI/app/SRC/main/Java /

Reveal in Finder allows you to quickly open the current file

\

Step 2: Enter Java instructions

Javah com. Example. Jni. MainActivity (javah class name. The package name)Copy the code

Then you see the generated.h file

\

MainActivity defined in the constant, automatically generated macro!

.h File contents:

/ / the JNI header files
#include <jni.h>

// Solve the cyclic copy problem
#ifndef _Included_com_example_jni_MainActivity // If the macro is not defined
#define _Included_com_example_jni_MainActivity// Define the macro

#ifdef __cplusplus // If C++ is used, C is used
extern "C" {// Use C to prevent function overloading (solve the problem of function name conflicts)
#endif
#undef com_example_jni_MainActivity_A

// Automatically detects MainActivity generated macros
#define com_example_jni_MainActivity_A 234L

// Function declaration
extern "C" JNIEXPORT jstring JNICALL Java_com_example_jni_MainActivity_getString
  (JNIEnv *, jobject);



#ifdef __cplusplus// do nothing in C++
}
#endif
#endif
Copy the code

Note here to add very clear, not long winded, if you do not understand, leave a message in the comment section!

Function implementation file:

//extern "C" JNIEXPORT jstring JNICALL Java_com_example_jni_MainActivity_getString
// (JNIEnv *, jobject){}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = please see the following comment = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


//JNIEnv is a C++ function that eventually calls C's JNINativeInterface method, so it must be C (extern "C")
extern "C" // Use C to compile

JNIEXPORT // flag that the method will be called externally (VS will fail,AS will not)

jstring // Return value of method in Java,
// Return jString, which indicates that the Java type is String
// If it is jint, it is an int in Java

JNICALL// this is JIN.

// Function name, designed by JDK (JNI is a Java technology, not native technology)
Java_com_example_jni_MainActivity_getString
        (JNIEnv *env, jobject job) {
    /** * JNIEnv :(JNIEnv) is the most important thing in Java /C++ communication MainActivity(this) * : Static: whoever calls it is the same class as MainActivity. Class */
}
Copy the code

JNIEnv is a very important parameter, it is the essence of JNI, this parameter will eventually call the structure of C (JNINativeInterface).

Note the second parameter:

  • When it is non-static, the jobject object is generated
  • When static, jClass objects are generated

Native layer changes the value of Java properties (non-static)

Implementation effect: Java property value is “zhang SAN “, through calling native function, modify to Li Si

 public String name = "Zhang";
Copy the code

Create a method to call Native in MainActivity

 // Change the name to "li Si" via native
public native void changeName(a);
Copy the code

Native layer code:

I write directly in the implementation file!

// log library in NDK toolchain (for printing)
#include <android/log.h>

// Define macros to print results
#define TAG "szj"
/ /... I don't even know what to pass, but I can use macro in JNI to pass
#defineLOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__);
#defineLOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__);
#defineLOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__);


// Function implementation
extern "C"
JNIEXPORT void JNICALL
Java_com_example_jni_MainActivity_changeName(JNIEnv *env, jobject thiz) {
    /** * get class */
    jclass j_cls = env->GetObjectClass(thiz);

    /** * jfieldID GetFieldID(jclass clazz, const char* name, Const char* sig) * Parameter 1: mainActivity. class * Parameter 2: attribute name * Parameter 3: attribute signature L indicates the reference type */
    jfieldID j_fid = env->GetFieldID(j_cls, "name"."Ljava/lang/String;");


    /** * jobject GetObjectField(jobject obj, JfieldID fieldID) * Change the Java property to jString * Parameter 1 :jobject parameter 2: signature ID * static_cast
      
        Cast to jString */
      
    jstring j_str = static_cast<jstring>(env->GetObjectField(thiz, j_fid));

    /** * const char* GetStringUTFChars(jString string, Jboolean * isCopy) * Print string * Parameter 1: string to be converted * Parameter 2: unknown */
    const char *chars = env->GetStringUTFChars(j_str, NULL);
    LOGD("native %s", chars);
    LOGI("native %s", chars);
    LOGE("native %s", chars);

    jstring st = env->NewStringUTF("Bill");

    /** * void SetObjectField(jobject obj, jfieldID fieldID, Jobject value) * changed to Li4 * Parameter 1 :jobject * Parameter 2: signature ID * Parameter 3: modified jstring */
    env->SetObjectField(thiz, j_fid, st);
}
Copy the code

Similar to Java reflection;

Ideas:

  • Get jclass from GetObjectClass() (JNI attributes that start with j for example :jclass, jString,jfieldID, etc.)
  • Get the ID of the attribute name with GetFieldID()
  • We then change the String on Java to the jString that JNI recognizes via GetObjectField()
  • And finally I’m going to change it to ‘Li Si’ with SetObjectField()

The property signature will finally say!

Use:

The running results are as follows:

Native layer changes the value of Java properties (static)

Native layer changes static properties:

// Change age +10 via native
public static native void changeAge(a);
Copy the code

Vative layer code:

extern "C"
JNIEXPORT void JNICALL
Java_com_example_jni_MainActivity_changeAge(JNIEnv *env, jclass clazz) {
    /** * Parameter 3: Basic type signature (int corresponds to I) */
    jfieldID j_id = env->GetStaticFieldID(clazz, "age"."I");

    Jint GetStaticIntField(jclass clazz, jfieldID fieldID) * Jclass * ID */
    jint j_age = env->GetStaticIntField(clazz, j_id);

    // Modify parameters
    j_age += 10;

    Void SetStaticIntField(jclass clazz, jfieldID fieldID, Jint value) * Parameter 1 :jclass parameter 2: static attribute ID parameter 3: new static value */
    env->SetStaticIntField(clazz, j_id, j_age);
}
Copy the code

Use:



Operation effect:

Native calls Java static methods

Java layer:

	public int add(int number1,int number2){
        return number1+ number2;
    }
    //native calls Java methods
    public native int nativeAdd(a);
Copy the code

Native layer:

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_jni_MainActivity_nativeAdd(JNIEnv *env, jobject thiz) {
    /** * Get jclass * jclass GetObjectClass(jobject obj) */
    jclass j_c = env->GetObjectClass(thiz);

    /** * get method ID; * jmethodID GetMethodID(jclass clazz, const char* name, const char* sig) * jmethodID (jclass clazz, const char* name, const char* sig
    jmethodID jmethodId = env->GetMethodID(j_c, "add"."(II)I");

    /** * jint(*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...) ; * The method calling Java returns an int */
    jint jint1 = env->CallIntMethod(thiz, jmethodId, 4.2);
    LOGE("native %d", jint1);

    // The method must return 0, otherwise the following error will be reported.
    //Fatal signal 5 (SIGTRAP), code 1 (TRAP_BRKPT), fault addr 0x7675a751dc in tid 18347 (com.example.jni),
    // pid 18347 (com.example.jni)
    return 0;
}
Copy the code

The running results are as follows:

Attribute signature

Eight basic types of signatures:

java native
boolean Z
short S
int I
byte B
double D
float F
char C
long J

Method examples:

java native
void sum(int a,int b) (II)V
void sum(int a,int b,int c) (III)V

Array examples:

java native
array int[] [ I
array int[][] [ [ I
array float[][][] [ [ [ F

It is also possible to obtain all signatures in a class with a directive:

Step 1: Go to the.class directory:

Enter this directory:

My address is: CD/Users/shizhenjiang/Desktop/AndroidProject JNI/app/build/intermediates/javac/debug/classes/com/example/JNICopy the code

Then enter the command:

javap -s -p xxx.class
Copy the code

The final result is:

  • Red box: I input the command
  • Green box: The method/attribute name descriptor is a signature

\

Note:

If the so library returns an error, comment out the other two

In the same way, if you want to see JNI basic use (native simp-lib.cpp) code, then JNI advanced and QQ voice practice code comment out!

Only one CPP file can now exist



Other JNI articles:

Android JNI :Android JNI

Android JNI QQ funny voice combat (including complete Demo)

The complete code

Original is not easy, your praise is my biggest support ~