Android Studio add jni code

Yesterday I had to write an apk to practice drawing with OpenGL ES. I didn’t want to adjust OpenGLS directly in Java. I wanted to adjust it in CPP through JNI, so I needed to add JNI code. It took me 3 hours to complete it. I felt that there were a lot of pitfalls, so Record the steps for later use. There are many ways to add jni. I only record the one I made here.

1. Write a java file that declares the native interface

Declare 3 native interfaces

   public  native  void initImpl();
    public  native  void resizeImpl();
    public  native  void doDrawImpl();

Draw.java

//Draw.java

package com.example.test1;

public class Draw {

    public void init(){
        initImpl();
    }

    public void resize() {
        resizeImpl();
    }

    public void doDraw() {
        doDrawImpl();
    }

    static {
        System.loadLibrary("draw");
    }



    public  native  void initImpl();
    public  native  void resizeImpl();
    public  native  void doDrawImpl();

}

Among them, System.loadLibrary() above fills in the name of the so library that our cpp code will be compiled through Android.mk. For example, because it is named libdraw.so, I fill in draw. 

2. Use javac to generate .class files 

 

3. Use javah to parse .class to generate .h file 

 Pit 1: Here you need to pay attention to the path to execute javah as app/src/main/java, followed by the package name + class name.

The generated .h looks like this: 

com_example_test1_Draw.h

//com_example_test1_Draw.h


/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_test1_Draw */

#ifndef _Included_com_example_test1_Draw
#define _Included_com_example_test1_Draw
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_test1_Draw
 * Method:    initImpl
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_test1_Draw_initImpl
  (JNIEnv *, jobject);

/*
 * Class:     com_example_test1_Draw
 * Method:    resizeImpl
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_test1_Draw_resizeImpl
  (JNIEnv *, jobject);

/*
 * Class:     com_example_test1_Draw
 * Method:    doDrawImpl
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_test1_Draw_doDrawImpl
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

4. Create jni folder and cpp file

Select the app folder with the mouse, then File ==> New ==> Folder ==> Jni Folder,

Then select src/main/jni as the path, as follows: 

After creation, it is as follows. It is an empty folder. Then we create the .cpp file and add the compilation script.

 

 

Add a .cpp file inside and name it according to your needs, such as Draw.cpp here. 

Then copy the entire .h content generated previously, add the implementation to the function, and you can discard the .h after writing it, such as the Draw.cpp I added here 

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <android/log.h>


#define TAG "======>lkh" 
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型

/* Header for class com_example_test1_Draw */

#ifndef _Included_com_example_test1_Draw
#define _Included_com_example_test1_Draw
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_test1_Draw
 * Method:    initImpl
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_test1_Draw_initImpl
  (JNIEnv *, jobject) {
        LOGI("Java_com_example_test1_Draw_initImpl");
  }

/*
 * Class:     com_example_test1_Draw
 * Method:    resizeImpl
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_test1_Draw_resizeImpl
  (JNIEnv *, jobject) {
    LOGI("Java_com_example_test1_Draw_resizeImpl");
  }

/*
 * Class:     com_example_test1_Draw
 * Method:    doDrawImpl
 * Signature: ()V
 */
 static bool printLogFirstTime = false;
JNIEXPORT void JNICALL Java_com_example_test1_Draw_doDrawImpl
  (JNIEnv *, jobject) {
  if (printLogFirstTime == false) {
    LOGI("Java_com_example_test1_Draw_doDrawImpl");
    printLogFirstTime  = true;
   }

  }

#ifdef __cplusplus
}
#endif
#endif

  

5. Add Android.mk, Application.mk 

Add the mk file for compiling cpp in the jni directory.

Android.mk, I want to generate a library called libdraw.so, so LOCAL_MODULE is assigned the value draw.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := draw
LOCAL_SRC_FILES := Draw.cpp
LOCAL_LDLIBS += -llog
LOCAL_LDLIBS += -lGLESv2
# use GL ext model
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES


include $(BUILD_SHARED_LIBRARY)

 Application.mk 

APP_ABI := all
APP_PLATFORM := android-17

Among them, 17 need version adjustment according to their actual situation.

6. Use ndk-build to compile and generate .so

Use ndk-build to compile and generate .so files in the jni directory, as follows:  

 If this error is reported 

Android NDK: WARNING: APP_PLATFORM android-17 is higher than android:minSdkVersion 1 in

Solve the problem by adding the following code to AndroidManifest.xml, 
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23"/>

Among them, 17 and 23 need version adjustment according to their actual situation.

7. Add various ndk configurations

Build.gradle adds the so packaging path. If you don't add it, so will not be packaged. The apk will crash as soon as it runs to the jni code, and an error that the so library cannot be found will be reported.

    sourceSets {
        main {
            jni {
                srcDirs 'src/main/jni'
            }
            jniLibs.srcDirs = ['src/main/libs']
        }
    }

gradle.properties add 

android.useDeprecatedNdk=true

local.properties add ndk path 

ndk.dir=/home/XXX/Android/Sdk/ndk-bundle


 

8.make project, run hahaha

Guess you like

Origin blog.csdn.net/goodnight1994/article/details/122103512