Android study notes-local call, Java calls C/C++, generates .so, .so calls other .so

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
Insert picture description here

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
Insert picture description here
use the cd command to go to the java directory of the current project
Insert picture description here
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 Insert picture description here
new jni directory in main, and dragged the .h files to the jni directory.
Insert picture description here
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;
    };

Insert picture description here
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
Insert picture description here
Insert picture description here
Insert picture description here
, you can see in the generated libs directory that the various architectures .so.
Insert picture description here

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
        }
    }

Insert picture description here
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.

java
CallNativeMethod.so
NativeMethod.so

Run it on a mobile phone or an emulator, and you can see that the printing result is
Insert picture description here
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 Insert picture description here
and java calls.

More types of libraries call jar, so, aar, you can refer to the third-party library method in android.mk

Guess you like

Origin blog.csdn.net/wwb1990/article/details/104256783
SO?