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.
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 ~