詳解Android JNI的基本使用(CMake)
簡介
什么是JNI
JNI的全稱是Java Native Interface:Java本地開發(fā)接口,它提供了若干的API實現(xiàn)了Java和其他語言的通信(主要是C和C++),目的就是Java可以調(diào)用C或C++開發(fā)的函數(shù),C或C++也能調(diào)用Java的方法。這樣有很多有點,其一就是效率,C/C++是本地語言,比java更高效;其二就是可以復(fù)用已經(jīng)存在的C/C++代碼;其三是Java反編譯比C語言容易,一般加密算法都是用C語言編寫,不容易被反編譯。
什么是NDK和CMake
NDK全稱是Native Development Kit,NDK提供了一系列的工具,幫助開發(fā)者快速開發(fā)C(或C++)的動態(tài)庫,并能自動將so和Java應(yīng)用一起打包成apk。NDK集成了交叉編譯器,并提供了相應(yīng)的mk文件隔離CPU、平臺、ABI等差異,開發(fā)人員只需要簡單修改mk文件(指出“哪些文件需要編譯”、“編譯特性要求”等),就可以創(chuàng)建出so。
CMake是一個比make更高級的編譯配置工具,它可以根據(jù)不同平臺、不同的編譯器,生成相應(yīng)的Makefile或者vcproj項目。
通過編寫CMakeLists.txt,可以控制生成的Makefile,從而控制編譯過程。CMake自動生成的Makefile不僅可以通過make命令構(gòu)建項目生成目標(biāo)文件,還支持安裝(make install)、測試安裝的程序是否能正確執(zhí)行(make test,或者ctest)、生成當(dāng)前平臺的安裝包(make package)、生成源碼包(make package_source)、產(chǎn)生Dashboard顯示數(shù)據(jù)并上傳等高級功能,只要在CMakeLists.txt中簡單配置,就可以完成很多復(fù)雜的功能,包括寫測試用例。如果有嵌套目錄,子目錄下可以有自己的CMakeLists.txt。
使用流程
1、在java文件中創(chuàng)建本地方法
2、build項目后自動生成“.h”文件
3、創(chuàng)建.cpp文件,實現(xiàn).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、調(diào)用native方法nativeCalculate,傳入?yún)?shù)2。
1、獲取java對象number,初始值為0。
2、調(diào)用java方法javajavaCalculate,傳入number值,獲得返回值10。
3、將返回值加上參數(shù)2,返回,獲得12。
最終效果如下:

創(chuàng)建本地方法
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,然后進(jìn)入到app\build\intermediates\classes\debug目錄下。

在終端輸入命令javah com.example.xujiajia_sx.jnitest.JNITest(即帶有native方法的類)
效果如下:
自動生成的“.h”文件如下,可以根據(jù)自己要求對其重命名或者增減內(nèi)容。
/* 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
創(chuàng)建cpp文件實現(xiàn)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);
}
主要邏輯是獲取到j(luò)ava中number的值,然后調(diào)用javaCalculate()方法,接著再加上這個native方法的參數(shù)num。
設(shè)置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.
# 制定目標(biāo)庫.
jni_test
# Links the target library to the log library
# included in the NDK.
${log-lib} )
配置完cmake,rebuild項目,即可以運行test。“.so”文件生成如下:

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android通過bin二進(jìn)制程序調(diào)用jar原理
最近在研究monkey測試,發(fā)現(xiàn)monkey測試的代碼都是JAVA編寫的,通過編譯生成jar包,而我們在執(zhí)行測試時直接執(zhí)行/system/bin/monkey這個二進(jìn)制程序的,那么它是如何能調(diào)起java程序的呢,本文小編給大家介紹了Android通過bin二進(jìn)制程序調(diào)用jar原理,需要的朋友可以參考下2023-10-10
Android使用Notification實現(xiàn)寬視圖通知欄(二)
這篇文章主要為大家詳細(xì)介紹了Android使用Notification實現(xiàn)寬視圖通知欄,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12
android TextView不用ScrollViewe也可以滾動的方法
這篇文章主要介紹了android TextView不用ScrollViewe也可以滾動的方法,很簡單實用的代碼,大家參考使用吧2013-11-11
Android 異步獲取網(wǎng)絡(luò)圖片并處理導(dǎo)致內(nèi)存溢出問題解決方法
Android異步獲取網(wǎng)絡(luò)圖片并處理圖片Out Of Memory內(nèi)存溢出如何解決呢?本文介紹了操作步驟,感興趣的朋友可以了解下或許對你有所幫助2013-02-02
Android學(xué)習(xí)之SharedPerference存儲詳解
這篇文章主要為大家詳細(xì)介紹了Android學(xué)習(xí)之SharedPerference存儲的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08
Android實現(xiàn)滑動加載數(shù)據(jù)的方法
這篇文章主要介紹了Android實現(xiàn)滑動加載數(shù)據(jù)的方法,實例分析了Android通過滑動實現(xiàn)動態(tài)加載數(shù)據(jù)的技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07

