Android JNI的基本使用(CMake)

許佳佳233發表於2017-12-22

#使用流程
1、在java檔案中建立本地方法
2、build專案後自動生成“.h”檔案
3、建立.cpp檔案,實現.h檔案中的方法
4、配置Cmake檔案,生成“.so”檔案

筆者專案目錄如下:
這裡寫圖片描述
##測試例項

public class MyJNI {
    private static final String TAG=MyJNI.class.getName();
    @Test
    public void test(){
        JNITest jniTest=new JNITest();
        Log.d(TAG,jniTest.nativeCalculate(2)+"");
    }
}

1、呼叫native方法nativeCalculate,傳入引數2。
1、獲取java物件number,初始值為0。
2、呼叫java方法javajavaCalculate,傳入number值,獲得返回值10。
3、將返回值加上引數2,返回,獲得12。

最終效果如下:
這裡寫圖片描述
#建立本地方法

public class JNITest {

    private int number = 0;

    public int javaCalculate(int num){
        number=num+10;
        return number;
    }
    public native int nativeCalculate(int num);

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

#自動生成“.h檔案”
首先make Project,然後進入到app\build\intermediates\classes\debug目錄下。
這裡寫圖片描述

在終端輸入命令javah com.example.xujiajia_sx.jnitest.JNITest(即帶有native方法的類)
效果如下:
這裡寫圖片描述
自動生成的“.h”檔案如下,可以根據自己要求對其重新命名或者增減內容。

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

#ifndef _Included_com_example_xujiajia_sx_jnitest_JNITest
#define _Included_com_example_xujiajia_sx_jnitest_JNITest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_xujiajia_sx_jnitest_JNITest
 * Method:    nativeCalculate
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_example_xujiajia_1sx_jnitest_JNITest_nativeCalculate
  (JNIEnv *, jobject, jint);

#ifdef __cplusplus
}
#endif
#endif

#建立cpp檔案實現native方法
筆者cpp檔案如下:

#include "jni_test.h"

JNIEXPORT jint JNICALL
Java_com_example_xujiajia_1sx_jnitest_JNITest_nativeCalculate(JNIEnv *env, jobject obj,jint num) {
    //獲取obj中物件的class物件
    jclass clazz = env->GetObjectClass(obj);
    //獲取clazz中的number欄位的id
    jfieldID id_number = env->GetFieldID(clazz, "number", "I");
    jmethodID id_java_calculate=env->GetMethodID(clazz, "javaCalculate", "(I)I");
    //次獲取java中number的值
    jint number = env->GetIntField(obj, id_number);
    jint result=env->CallIntMethod(obj,id_java_calculate,number);

    env->SetIntField(obj,id_number,result+num);
    //再次獲取java中number的值並返回
    return env->GetIntField(obj, id_number);
}

主要邏輯是獲取到java中number的值,然後呼叫javaCalculate()方法,接著再加上這個native方法的引數num。
#設定Cmake檔案,生成".so"檔案
首先,在build.gradle中新增Cmake配置:

android {
    ...
    defaultConfig {
        ...
        externalNativeBuild {
            cmake {
                cppFlags ""
                //生成多個版本的so檔案
                abiFilters 'armeabi','armeabi-v7a','x86'
            }
        }
    }
    buildTypes {
        ...
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

編寫Cmake檔案:

#CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)

add_library( # Sets the name of the library.
       jni_test

       # Sets the library as a shared library.
       SHARED

       # Provides a relative path to your source file(s).
       src/main/jni/jni_test.cpp)

include_directories(src/main/jni/)

find_library( # Sets the name of the path variable.
       log-lib

       # Specifies the name of the NDK library that
       # you want CMake to locate.
       log )

target_link_libraries( # Specifies the target library.
            # 制定目標庫.
            jni_test

            # Links the target library to the log library
            # included in the NDK.
            ${log-lib} )

配置完cmake,rebuild專案,即可以執行test。“.so”檔案生成如下:
這裡寫圖片描述

相關文章