JNI NDK (Android Studio+CMake) Implements Java Call C++ Code Flow

Keywords: Java Android cmake

JNI/NDK Java Call C/C++ Preface

_Through the first article, we learned about Android Studio+CMake environment for JNI/NDK development, and the second article explained the process of generating a simple so library file. So in the actual development process, we often have to make calls between two layers, such as C/C++ calling the Java layer, or Java calling the C/C++ layer. Only by calling each other between the two layers can we achieve high performance and security.

JNI/NDK Java Calls C/C++ to Write java Files

Generally speaking, it is easier for Java layer to call C/C++ layer code. More is the processing in C/C++ layer, which is the difficulty. Here we introduce the common types of string, int, arr array in C/C++ layer.

public class NativeUtils {
    //1. Refer to the JIN/NDk library file (the library name is consistent with the C/C++ file name created)
    static {
        System.loadLibrary("jni-utils");
    }
    //2. Define native native methods (which call C/C++ to implement functions on behalf of this method)

    //Processing strings with return values and no parameters
    public native String JavaCallJNI();

    //Processing int type with parameters and return values
    public native int JavaCallJNISum(int num1, int num2);

    //Processing int [] array type with parameters and return values
    public native int[] JavaCallJNIArr(int[] arr);
}

JNI/NDK Java Calls C/C++ to Write C/C++ Files

_Through the last step, we have written the code of the java layer. Secondly, the specific implementation of calling C/C++ in the java layer is written here, according to the corresponding business needs to achieve the corresponding functions.


//1. Introducing Jni header file
#include <jni.h>
#include <stdlib.h>
#include <stdio.h>

//2. Writing C/C++ functions of JNI corresponding to NativeUtils
//C/C++ Function Interpretation - ------------------------------------------------------------------------------------------------------------------------------------------------------------
//JNIEXPORT JNI exports jstring function return value JNICALL JNI for invocation
//Java_full class name_NativeUtils method name (JNIEnv * env, jobject)
// Function Pointer jobject jobject in JNIEnv*env C/C++ Calls Class Object of Native Method

extern "C"
JNIEXPORT jintArray JNICALL
Java_com_aynu_androidjni_NativeUtils_JavaCallJNIArr(JNIEnv *env, jobject jobject,
                                                    jintArray arr_) {
    //1. Get the elements of the arr array
    jint *arr = env->GetIntArrayElements(arr_, NULL);
    //2. Get the length of the arr array
    jsize arrSize = env->GetArrayLength(arr_);
    //3. Traversal arrays
    for (int i = 0; i < arrSize; ++i) {
        *(arr + i) += 10;
    }
    //4. Release memory
    env->ReleaseIntArrayElements(arr_, arr, 0);
    //5. Return arrays
    return arr_;
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_aynu_androidjni_NativeUtils_JavaCallJNISum(JNIEnv *env, jobject jobject,
                                                    jint num1,jint num2) {
    //1. Corresponding logical operations

    return num1 + num2;

}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_aynu_androidjni_NativeUtils_JavaCallJNI(JNIEnv *env, jobject jobject) {

    //3. Write specific business logic

    return env->NewStringUTF("C/C++ Say");
}

JNI/NDK Call

After we have written the java layer and C/C++ layer, we need to call them.

public class MainActivity extends AppCompatActivity {

    private TextView mMsgTxt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        mMsgTxt = (TextView) findViewById(R.id.msg_txt);

        NativeUtils nativeUtils = new NativeUtils();
        //Java calls JNI
        String msg = nativeUtils.JavaCallJNI();
        //mMsgTxt.setText(msg);

        //Java calls JNI to achieve the sum of two numbers
        int sum = nativeUtils.JavaCallJNISum(10, 5);
        //mMsgTxt.setText(String.format("10+5=%d", sum));

        //Java calls JNI to implement each element in the array plus 10
        int[] arr = new int[]{1, 2, 3, 4, 5};
        int[] jniArr = nativeUtils.JavaCallJNIArr(arr);
        StringBuilder buffer = new StringBuilder();
        for (int aJniArr : jniArr) {
            buffer.append(aJniArr).append(",");
        }
        mMsgTxt.setText(buffer.toString());
    }
}

JNI/NDK results

After invoking, we will generate the corresponding so library file, and also show our final results.

Processing results of type int

Processing the results of array types

Processing string type results

JNI/NDK Concluding remarks

_above is the project of using Android studio + CMake to build Java calling C++ code flow in JNI/NDK development. If there are misunderstandings, please leave more comments.

Posted by wilzy on Thu, 10 Jan 2019 09:21:10 -0800