摘要
基本原理:為什么要用jni,此處就不講了,網(wǎng)上已經(jīng)很詳細(xì)了殊鞭。寫本文的原因是在網(wǎng)上沒有發(fā)現(xiàn)用最新版AS2.3進(jìn)行ndk開發(fā)的,所以拋磚引玉一下尼桶。在java代碼中調(diào)用c代碼操灿,大致步驟如下:
1.在需要調(diào)用c代碼的地方聲明native方法。
2.在c代碼中對(duì)該native方法進(jìn)行實(shí)現(xiàn)泵督。
3.通過ndk開發(fā)工具包和gradle進(jìn)行編譯趾盐。
4.在調(diào)用的地方,加載生成的so庫文件小腊,調(diào)用方法救鲤。
5.下面詳細(xì)講解,寫的不對(duì)的地方歡迎大家提出來秩冈。
第一步:修改Project的build.gradle文件
首先修改project工程文件的build.gradle文件蜒简,把gradle換成實(shí)驗(yàn)gradle-exprimental。具體請(qǐng)看詳情圖漩仙。
接下來需要修改這個(gè)文件,見圖:
第二步:修改app的build.gradle文件
此處修改較大犹赖,先上一個(gè)效果圖队他,然后直接上代碼:
// 注意:此處已修改,原來為apply plugin: 'com.android.application'
apply plugin: 'com.android.model.application'
// 用model包裹android的內(nèi)容
model{
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "com.wangjin.hellondkdemo"
minSdkVersion.apiLevel 19 // 此處需要修改峻村,添加 .apiLevel 原來為minSdkVersion 14
targetSdkVersion.apiLevel 25 // 此處需要修改麸折,添加 .apiLevel
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
// 此處需要修改,原來為 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
// 修改成下面這句話
proguardFiles.add(file('proguard-android.txt'))
}
}
ndk {
moduleName "hello"
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'com.android.support.constraint:constraint-layout:1.0.0-beta2'
testCompile 'junit:junit:4.12'
}
第三步:配置項(xiàng)目的NDK開發(fā)工具包
話說粘昨,還是圖片深得我心垢啼,直接上圖最可靠。张肾。芭析。
關(guān)鍵代碼來了:
編譯完成后,打開local.propertices文件吞瞪,顯示如下圖 則成功
此時(shí)馁启,說明項(xiàng)目的ndk配置基本完成。
接下來芍秆,需要在app的build.gradle文件中添加要生成的so庫文件的文件名惯疙,代替Android.mk文件翠勉,也就是說,以后直接在gradle中配置一句話霉颠,直接省略了mk文件的編寫对碌,是不是很爽。
至此蒿偎,配置的終于完成了 朽们,哇咔咔,不過話說回來酥郭,也不是特別難嗎华坦,相信第二次只要3分鐘絕對(duì)能配置完成。
第四步:關(guān)鍵點(diǎn)來了不从,新建jni文件夾惜姐,編寫c文件
還是貼圖把吧,最后會(huì)把代碼demo地址發(fā)出來
1.首先在app/src/main文件夾下新建一個(gè)和java同級(jí)的jni文件夾
2.在jni文件夾下新建c文件
3.各種扯皮結(jié)束了椿息,是時(shí)候開始擼代碼
大家都知道歹袁,第一步肯定是手撕native方法。我們?cè)贛ainActivity中新建了兩個(gè)方法寝优,第一個(gè)helloFromJni条舔,調(diào)用c代碼返回一個(gè)字符串;第二個(gè)callBackJavafromC乏矾,是調(diào)用c代碼孟抗,然后在c代碼中調(diào)用我們定義好的logout方法在控制臺(tái)打印一句話。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 調(diào)用native方法
}
static {
// 加載so庫文件钻心,這個(gè)是固定寫法凄硼,需要調(diào)用so庫文件的方法,首先需要加載so庫
System.loadLibrary("hello"); // hello是我們?cè)赽uild.gradle中定義的捷沸,要一致
}
public native String helloFromJni();
public native void callBackJavafromC();
public void logout() {
System.out.println("hahahahahahahahahah===");
}
}
4.定義了native方法后摊沉,方法名會(huì)報(bào)紅,是因?yàn)闆]有在c代碼中實(shí)現(xiàn)痒给,所以接下來是實(shí)現(xiàn)c代碼说墨,并處理相應(yīng)的邏輯,此處需要一定的c語言基礎(chǔ)苍柏,
只要看懂就行尼斧,基本的操作也不難,大家找個(gè)速成的c語言視頻look一下试吁。先上兩張圖突颊,解釋一下怎樣快速生成c代碼。
5.此時(shí),在我們新建的hello.c中就實(shí)現(xiàn)了我們的方法律秃,只需要處理相應(yīng)的邏輯就行了爬橡。
6.上面4和5兩步基本上講清楚了我們native方法的聲明和c代碼的實(shí)現(xiàn),下面貼一下 我們自己定義的兩個(gè)方法的實(shí)現(xiàn)棒动,一個(gè)是返回一個(gè)字符串糙申,另一個(gè)是回調(diào)java的方法,打印一句話船惨。下面看c代碼的實(shí)現(xiàn)柜裸,在我們新建的hello.c文件中:
#include <jni.h>
/**
* 這個(gè)是返回一個(gè)字符串的c代碼
*/
JNIEXPORT jstring JNICALL
Java_com_wangjin_hellondkdemo_MainActivity_helloFromJni(JNIEnv *env, jobject instance) {
char* c ="hello from c";
return (*env)->NewStringUTF(env, c);
}
/**
* 這個(gè)是回調(diào)java方法打印一句話的代碼
*/
JNIEXPORT void JNICALL
Java_com_wangjin_hellondkdemo_MainActivity_callBackJavafromC(JNIEnv *env, jobject obj) {
// 1.通過反射找到類
jclass clazz = (*env) -> FindClass(env, "com/wangjin/hellondkdemo/MainActivity");
// 2. 找到方法ID
jmethodID methodId = (*env) -> GetMethodID(env, clazz, "logout", "()V");
// 3.調(diào)用方法,obj就是調(diào)用的類實(shí)例粱锐,所以不用再次創(chuàng)建了
(*env)->CallVoidMethod(env, obj, methodId);
}
7.此時(shí)疙挺,native方法和c的實(shí)現(xiàn)都寫好了,只需要在oncreat()方法diao用就行了怜浅。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 調(diào)用c中的方法彈出Toast
Toast.makeText(this, helloFromJni(), Toast.LENGTH_LONG).show();
// java調(diào)用c然后回調(diào)java方法铐然,在logcat中打印 hahahahaahah====
callBackJavafromC();
}
大功告成
看到此處是不是覺得jni的邏輯也是很簡(jiǎn)單的,有什么不明白的隨時(shí)留言聯(lián)系恶座,我會(huì)很快處理的搀暑。最后讓我打一波廣告,我的淘寶店順利開業(yè)跨琳,地址程序員潮流店鋪地址
自点,大家點(diǎn)擊進(jìn)去瞅一瞅,多多支持脉让,謝謝各位猿猿們桂敛。
最后github地址:
GitHub地址,點(diǎn)我就行
為了第一時(shí)間獲取最新文章溅潜,請(qǐng)關(guān)注公眾號(hào) -- 程序員指北埠啃,每一個(gè)關(guān)注都能讓作者多搬一塊磚。