Overview
What is JNI
JNI is the abbreviation of Java Native Interface, which provides several APIs to communicate between Java and other languages (mainly C & C++ ). Since Java 1.1, the JNI standard has become part of the Java platform, which allows Java code to interact with code written in other languages.
What is NDK
NDK is an acronym for Native Development Kit. It is part of the SDK (software development kit) software development kit, but usually requires a separate download. See About NDK for details .
Advantages and disadvantages of JNI
- advantage:
- Interact with other languages, each according to his own strengths.
- Increase the difficulty of decompilation
- shortcoming:
- Losing the advantage of Java's cross-platform
Java calls C
module
under configurationbuild.gradle
android { compileSdkVersion 25 buildToolsVersion "25.0.0" defaultConfig { ... ndk { moduleName "CallEachOther" //编译生成so库的名字,要和loadLibrary里面的参数一致 abiFilters "armeabi","armeabi-v7a","x86","x86_64","mips","arm64-v8a","mips64"//编译支持的平台 } } }
new
Java
classpublic class JNITest_Java { static { System.loadLibrary("CallEachOther"); } public native String getStringFromC(); }
System.loadLibrary
The parameter in here isbuild.gradle
the valuemoduleName
in , ieCallEachOther
. Here we define anative
methodgetStringFromC()
. For now, theJava
end can temporarily come to an end. Next, it's time to generate the header files.generate
.h
header fileOpen
AS
the built-inTerminal
,cd src/main/java
command to enter theJava
folder. ps: usecmd
the same effect as the commandEnter the command
javah 完整包名.类名
. E.g:javah com.dongyk.jnitest.JNITest_Java。
At this point, it will be
Java
generated in the directory包名_类名.h
.AS2.2.2
It will turn red when you open it, it looks like itAS
isbug
. But it does not affect the normal compilation.
Create a new folder in the
main
directory , New .jni
JniTestC.c
#include <stdio.h> #include <stdlib.h> #include "com_dongyk_jnitest_JNITest_Java.h" JNIEXPORT jstring JNICALL Java_com_dongyk_jnitest_JNITest_1Java_getStringFromC(JNIEnv * env, jobject jobj){ char* str = "I come from C"; return (*env)->NewStringUTF(env,str); };
There are certain rules for names of methods here. Format:
Java_包名_类名
. The method name is too long. It is recommended to copy it from the newly generated.h
file. Here is a brief explanation of this method:JNIEnv * env
env
The pointer points to a table of function pointers.jobject jobj
Java
Points to the object instantiated in codeJava
, equivalent to the this pointer.(*env)->NewStringUTF
Represents calling aenv#NewStringUTF()
method.- Finally return "I come from C".
called in
MainActivity
.public class MainActivity extends AppCompatActivity { private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); String result = new JNITest_Java().getStringFromC(); tv.setText(result); } }
C calls Java
Java
add method to classpublic class JNITest_Java { static { System.loadLibrary("JavaCallC"); } public native String getStringFromC(); public native int callAdd(); public int add(int a, int b) { Log.i("TAG","add was called"); return a + b; } }
Understand the process first. The code called at the
Java
layer must be theJava
code. A method is written here . When this method is called, the callingcallAdd()
method is notified . This process is first as a concrete implementation of the method, and the method is called in it. Then call the command to generate the header file.C
add()
C
Java
C
Java
javah
.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_dongyk_jnitest_JNITest_Java */ #ifndef _Included_com_dongyk_jnitest_JNITest_Java #define _Included_com_dongyk_jnitest_JNITest_Java #ifdef __cplusplus extern "C" { #endif /* * Class: com_dongyk_jnitest_JNITest_Java * Method: getStringFromC * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL ava_com_dongyk_jnitest_JNITest_1Java_getStringFromC (JNIEnv *, jobject); /* * Class: com_dongyk_jnitest_JNITest_Java * Method: callAdd * Signature: ()V */ JNIEXPORT jint JNICALL Java_com_dongyk_jnitest_JNITest_1Java_callAdd (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
.c
The specific implementation of the main functionJNIEXPORT jint JNICALL Java_com_dongyk_jnitest_JNITest_1Java_callAdd(JNIEnv *env, jobject jobj){ // 得到字节码 jclass clazz = (*env)->FindClass(env,"com/dongyk/jnitest/JNITest_Java"); // 得到方法 jmethodID jmethodid = (*env)->GetMethodID(env,clazz,"add","(II)I"); // 实例化类 jobject jobject = (*env)->AllocObject(env,clazz); // 调用方法 return (*env)->CallIntMethod(env,jobject,jmethodid,3,5); };
(*env)->GetMethodID中
The last parameter is the method signature. BecauseJava
method overloading is supported, but these overloaded methodsJni
are named the same in , the method signature is introduced to distinguish function overloading. Get the method signature: firstrebulid
download the project,cd build\intermediates\classes\debug
then usejavap -s 包名/类名
it to get all the method signatures. E.g:javap -s com/dongyk/jnitest/JNITest_Java
public int add(int, int); descriptor: (II)I
descriptor
The corresponding is the method signature. Of course. There areFindClass、GetMethodID
other methods in it, see XXX\sdk\ndk-bundle\platforms\android-xx\arch-arm\usr\include\jni.h for details.called in
MainActivity
.public class MainActivity extends AppCompatActivity { private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); int result = new JNITest_Java().callAdd(); tv.setText(result+""); } }
So far, a
Jni
small entry for beginners has beenDemo
written~