Ready to work
The NDK downloaded by Android Studio is the latest version, which no longer supports armabi and mips architectures, so if you want to support the generation of all cpu platforms, you need to download r15 or the previous version of ndk, and you can download the old version of NDK through the official website
If there is a ready-made so, you can skip the first step to make a so.
One, make and generate .so
Here I do two at the same time, it is convenient to call each other later
Create two new java classes,
NativeMethodCall generates target so
CallNativeMethod generates intermediate so to call target so
public class CallNativeMethod {
public static native String callNativeMethodFromSO();
public static native int callNativeMethodFromSOSub(int a,int b);;
}
public class NativeMethodCall {
public static native String helloFormC();
public static native int sub(int a,int b);
}
Pay attention to the package name, the so method name generated afterwards is based on "package name_class name_method name".
After creation, open Terminal and
use the cd command to go to the java directory of the current project
and then use the javah + package name class name command to generate a .h file.
I created the .h for both files here and created a
new jni directory in main, and dragged the .h files to the jni directory.
Then I created several files in the jni directory, namely:
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := NativeMethod #对应生成libcreate.so库
LOCAL_SRC_FILES := NativeMethod.c #create.c源文件的名字
include $(BUILD_SHARED_LIBRARY) #构建动态链接库
include $(CLEAR_VARS)
LOCAL_MODULE :=CallNativeMethod
LOCAL_SRC_FILES :=CallNativeMethod.c
LOCAL_SHARED_LIBRARIES := NativeMethod
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
Application.mk:
APP_ABI := all
NativeMethod.c:
( note the long method name in this, you can copy the corresponding name in the automatically generated .h above )
(#include <com_wwb_test_testcallnativelibrary_NativeMethodCall.h> This sentence should also be changed to your own.h )
#include <stdio.h>
#include <stdlib.h>
#include <com_wwb_test_testcallnativelibrary_NativeMethodCall.h>
JNIEXPORT jstring JNICALL Java_com_wwb_test_testcallnativelibrary_NativeMethodCall_helloFormC
(JNIEnv * env, jclass jobject){
return (*env) -> NewStringUTF(env,"hello form C");
};
JNIEXPORT jint JNICALL Java_com_wwb_test_testcallnativelibrary_NativeMethodCall_sub
(JNIEnv *env, jclass jobject, jint a, jint b){
return a+b;
};
CallNativeMethod.c:
( note the long method name in this, you can copy the corresponding name in the automatically generated .h above )
(#include <com_wwb_test_testcallnativelibrary_NativeMethodCall.h> This sentence should also be changed to your own.h )
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
#include "jni.h"
#include "dlfcn.h"
#include <fcntl.h>
#include <com_wwb_test_testcallnativelibrary_CallNativeMethod.h>
void * filehandle = NULL;
jstring (*getResult)(JNIEnv *, jobject) =NULL;
JNIEXPORT jstring JNICALL Java_com_wwb_test_testcallnativelibrary_CallNativeMethod_callNativeMethodFromSO
(JNIEnv * env, jclass thiz){
jstring result = "";
filehandle = dlopen("libNativeMethod.so", RTLD_LAZY);
if (filehandle) {
getResult = (jstring (*)(JNIEnv *, jobject)) dlsym(filehandle,"Java_com_wwb_test_testcallnativelibrary_NativeMethodCall_helloFormC");
if (getResult)
result = getResult(env, thiz);
dlclose(filehandle);
filehandle = NULL;
}
return result;
};
jint (*getSubResult)(JNIEnv *, jobject, jint, jint) =NULL;
JNIEXPORT jint JNICALL Java_com_wwb_test_testcallnativelibrary_CallNativeMethod_callNativeMethodFromSOSub
(JNIEnv * env, jclass thiz, jint a, jint b){
jint result = 0;
filehandle = dlopen("libNativeMethod.so", RTLD_LAZY);
if (filehandle) {
getSubResult = (jint (*)(JNIEnv *, jobject, jint, jint)) dlsym(filehandle,"Java_com_wwb_test_testcallnativelibrary_NativeMethodCall_sub");
if (getSubResult)
result = getSubResult(env, thiz, a, b);
dlclose(filehandle);
filehandle = NULL;
}
return result;
};
Among them, CallNativeMethod is calling the corresponding method in NativeMethod.
Then, go back to Terminal, and use the cd command to go to the jni directory.
Use the ndk-build command in the ndk directory, as shown in the figure below, which is my ndk location. After pressing Enter
, you can see in the generated libs directory that the various architectures .so.
Second, call .so
Add the following code to build.gradle in the app directory
sourceSets {
main() {
jniLibs.srcDirs = ['src/main/libs']
jni.srcDirs = [] //This prevents the auto generation of Android.mk
}
}
Modify MainActivity.java
public class MainActivity extends AppCompatActivity {
//直接加载调用最终so
// static {
// //加载so库
// System.loadLibrary("NativeMethod");
// }
//加载调用中间so
static {
//加载so库
System.loadLibrary("CallNativeMethod");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//调用最终so方法,返回结果
// Log.e("CallNative",""+NativeMethodCall.helloFormC());
// Log.e("CallNative",""+NativeMethodCall.sub(1,2));
//调用中间so方法, 中间so再去调用最终so,返回结果
Log.e("CallNative",""+CallNativeMethod.callNativeMethodFromSO());
Log.e("CallNative","1 + 2 = "+CallNativeMethod.callNativeMethodFromSOSub(1,2));
}
}
What is annotated is the code that directly calls the final so.
What is not annotated is to call the intermediate so, and the method for the intermediate so to call the final so is detailed in the implementation in CallNativeMethod.c.
Run it on a mobile phone or an emulator, and you can see that the printing result is
realized. Java calls so, and so calls another so method.
If the .so is ready-made, just put it directly in the src/main/libs directory.
Just add
and java calls.
More types of libraries call jar, so, aar, you can refer to the third-party library method in android.mk