AndroidStudio如何配置NDK/JNI開發環境
參考文章:
http://www.th7.cn/Program/Android/201509/550864.shtml
http://www.open-open.com/lib/view/open1451917048573.html
http://blog.csdn.net/sodino/article/details/41946607
http://www.codes51.com/article/detail_197383.html
AndroidStudio沒有像Eclipse那樣的一鍵add native support,相對來說比較麻煩,下面就介紹在AndroidStudio中如何實現類似於Eclipse的add native support功能(也就是進行NDK開發的步驟)。
1、新建一個Android工程,這一步就不多說了;
2、在AndroidStudio中配置NDK路徑,方法是:
(1)先下載NDK並安裝(這句基本是廢話);
(2)點選單欄的File->ProjectStructure…->在開啟的視窗中左側選中SDKLocation->在右側Android NDK Location中填入NDK目錄所在路徑,如下圖所示:
3、編譯生成.class檔案,方法是:
點選單欄的Build->Make Project,如下圖所示;
這時,在工程的app/build/intermediates下就會生成classes資料夾,開啟classes目錄下的debug目錄就會看到以你的包名命名的各級資料夾,最裡邊資料夾下有你的Java類對應的.class檔案;
4、確定你要引用本地方法的類:
其實你也可以先生成jni目錄,再去建立這個類,但是先Google顯然建議先建立要引用C程式碼的Java類,因為AndroidStudio可以根據你在java類中定義的native方法的名稱來自動生成.h標頭檔案。
比如你想在MainActivity中引用本地方法,那麼你先用
static {
System.loadLibrary("myNativeLib");
}
來宣告原生代碼庫,然後定義幾個natvie方法,比如
public native String getStringFromNative();
做完這些工作就可以進行下一步了。
5、使用javah命令列生成jni目錄及對應的標頭檔案:
我用的是AndroidStudio 2.1.1,在主介面最下邊就能找到Terminal,點一下就能開啟系統的命令列工具,並且已經為你自動cd到當前工程所在目錄,如下圖所示:
如上圖所示,開啟命令列編輯工具後,cd到工程的src/main/java目錄,輸入
javah -d ../jni 你的包名.引用本地方法的類的名稱
javah意思是生成一個.h標頭檔案,-d ../jni的意思是生成一個名字叫做jni的資料夾(directory),位置是在當前目錄(src/main/java)的上一級目錄(即src/main目錄);比如我的工程下,這條命令是
javah -d ../jni com.example.lixinyu.myapplication2.MainActivity
我直接用了MainActivity類做為呼叫JNI的Java類,你也可以寫一個自己的類,之後就等吧,構建完成後就會在工程的src/main目錄下生成一個jni目錄,下邊還包含.h標頭檔案,如下圖所示:
如果你事先在java程式碼中定義了native方法,那麼這裡還會自動生成方法對應的.h標頭檔案。當然,要執行javah命令的前提是你的電腦已經安裝過java,並且已經配置了java環境變數。
這裡再多說幾句,很多網友說要使用javah -d jni -classpath命令來構建jni目錄並生成.h標頭檔案,但是我親測是不行的,會報bash: ../../build/intermediates/classes/debug:is a directory錯誤,大概是版本不同吧,感謝碼蟻之家的網友提供的不一樣的答案。
至此,我們就基本完成了相當於Eclipse中的add native support功能了,接下來還要配置gradle和一大堆其它的配置檔案;
6、配置build.gradle檔案
這裡的build.gradle是指app模組下的build.gradle,不是整個工程的build.gradle檔案。在模組的build.gradle的defaultConfig下加入以下idk配置:
ndk {
moduleName"myNativeLib"
ldLibs "log", "z", "m"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
其中moduleName是隨便寫的,與將來在Java類中使用System.loadLobrary(“本地庫名稱”);以及生成的.so檔名稱對應;
ldLibs是要用到的jni庫,一般由google提供,比如上邊引入的log庫可以讓我們在C程式碼中使用LogCat日誌;
abiFilters指的是我們要生成哪些平臺的so檔案,這裡生成arm平臺和x86平臺;
配置後的build.gradle檔案如下圖所示:
至此build.gradle檔案就配置完了,其實這一步有點像我們eclipse中配置.mk檔案;
7、配置local.properties檔案
開啟工程目錄下的local.properties,感覺這一步是自動配置的,或者說在你一開始在AndroidStudio中指定NDK目錄時已經自動生成了。我的AndroidStudio在開啟local.properties已經有了
ndk.dir=/Develop/Android/android-ndk-r10e
這一行,所以就不用配了;
8、配置gradle.properties
開啟工程目錄下的gradle.properties檔案(注意不是build.gradle,而是gradle.properties),在檔案的最後一行加入
android.useDeprecatedNdk=true
這句的作用是允許我們使用已經過時的NDK版本,不知道AndroidStudio要求使用哪個版本的NDK才不會報錯,總之只要配置了這一句就可以使用比較舊的NDK版本了,我用的r10;
至此我們在AndroidStudio中就完成了NDK環境的配置,接下來就可以寫Native程式碼了;
9、寫一個.c檔案測試一下是否執行正常
(1)在我們之前生成src/main/jni目錄下新建一個.c檔案,方法是在jni資料夾上點滑鼠右鍵,選擇New->C/C++ Source File,然後在彈出的對話方塊中填入.c或.cpp檔案的檔名就可以了,比如說mail.c,名字可以隨便起;
(2)在main.c中隨便寫一段JNI程式碼,比如如下所示的一段程式碼:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <android/log.h>
#ifndef LOG_TAG
#define LOG_TAG"ANDROID_LAB"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#endif
/* Header for class lab_sodino_jnitest_MainActivity */
#ifndef _Included_com_example_lixinyu_myapplication2_MainActivity
#define _Included_com_example_lixinyu_myapplication2_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:lab_sodino_jnitest_MainActivity
* Method: getStringFromNative
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstringJNICALL Java_com_example_lixinyu_myapplication2_MainActivity_getStringFromNative
(JNIEnv *env, jobject jObj){
LOGE("log string from ndk.");
return (*env)->NewStringUTF(env,"HelloFrom JNI!");
}
#ifdef __cplusplus
}
#endif
#endif
JNI基礎就不多說了;
(3)在Java中呼叫:
比如我在MainActivity中加入以下程式碼:
package com.example.lixinyu.myapplication2;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.widget.TextView;
public class MainActivityextends FragmentActivity {
private TextViewmTextView;
static {
System.loadLibrary("myNativeLib");
}
publicnative String getStringFromNative();
@Override
protected voidonCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView= (TextView) findViewById(R.id.main_textview);
mTextView.setText(getStringFromNative()+"");
}
}
至此NDK/JNI程式碼就算是完成了,可以再次點選單欄的Build->Make Project編譯一下工程,看看在工程目錄下app/build/intermediates/ndk/debug/lib目錄下是否成功生成了相應的.so檔案,如果以上配置都正確的話這裡是會生成對應平臺的.so檔案的,debug目錄下還自動生成了Android.mk檔案,這個確實還不錯,相當於我們用build.gradle檔案的配置替代了Android.mk檔案的配置,執行一下,正常的話是可以執行的,至此就算是在AndroidStudio中配置了NDK/JNI開發環境。