簡介
什么是JNI
JNI的全稱是Java Native Interface:Java本地開發接口,它提供了若干的API實現了Java和其他語言的通信(主要是C和C++),目的就是Java可以調用C或C++開發的函數,C或C++也能調用Java的方法。這樣有很多有點,其一就是效率,C/C++是本地語言,比java更高效;其二就是可以復用已經存在的C/C++代碼;其三是Java反編譯比C語言容易,一般加密算法都是用C語言編寫,不容易被反編譯。
什么是NDK和CMake
NDK全稱是Native Development Kit,NDK提供了一系列的工具,幫助開發者快速開發C(或C++)的動態庫,并能自動將so和Java應用一起打包成apk。NDK集成了交叉編譯器,并提供了相應的mk文件隔離CPU、平臺、ABI等差異,開發人員只需要簡單修改mk文件(指出“哪些文件需要編譯”、“編譯特性要求”等),就可以創建出so。
CMake是一個比make更高級的編譯配置工具,它可以根據不同平臺、不同的編譯器,生成相應的Makefile或者vcproj項目。
通過編寫CMakeLists.txt,可以控制生成的Makefile,從而控制編譯過程。CMake自動生成的Makefile不僅可以通過make命令構建項目生成目標文件,還支持安裝(make install)、測試安裝的程序是否能正確執行(make test,或者ctest)、生成當前平臺的安裝包(make package)、生成源碼包(make package_source)、產生Dashboard顯示數據并上傳等高級功能,只要在CMakeLists.txt中簡單配置,就可以完成很多復雜的功能,包括寫測試用例。如果有嵌套目錄,子目錄下可以有自己的CMakeLists.txt。
使用流程
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 __cplusplusextern "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 JNICALLJava_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.txtcmake_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”文件生成如下:

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。
新聞熱點
疑難解答