1. 程式人生 > >Android NDK開發篇(一):新版NDK環境搭建(免Cygwin,超級快)

Android NDK開發篇(一):新版NDK環境搭建(免Cygwin,超級快)

  以前做Android的專案要用到NDK就必須要下載NDK,下載安裝Cygwin(模擬Linux環境用的),下載CDT(Eclipse C/C++開發外掛),還要配置編譯器,環境變數...

  麻煩到不想說了,Shamoo在網上查了一下資料,發現了一個超級快配置NDK的辦法。

  Step1:到Android官網下載Android的開發工具ADT(Android Development Tool的縮寫),該工具集成了最新的ADT和NDK外掛以及Eclipse,還有一個最新版本SDK。解壓之後就可以用了,非常爽!

    ADT外掛:管理Android SDK和相關的開發工具的

    NDK外掛:用於開發Android NDK的外掛,ADT版本在20以上,就能安裝NDK外掛,另外NDK集成了CDT外掛

  Step2:到Android官網下載最新的NDK,注:NDK版本在r7以上之後就集成了Cygwin,而且還是十分精簡版。比起下載Cygwin要方便多啦!下載連結見:http://developer.android.com/tools/sdk/ndk/index.html

    下載完成之後,解壓搞定!

  Step3:開啟Eclipse,點Window->Preferences->Android->NDK,設定NDK路徑,例如Shamoo的是E:\android-ndk-r9c

  Step4:新建一個Android工程,在工程上右鍵點選Android Tools->Add Native Support...,然後給我們的.so檔案取個名字,例如:my-ndk

  這時候工程就會多一個jni的資料夾,jni下有Android.mk和my-ndk.cpp檔案。Android.mk是NDK工程的Makefile,my-ndk.cpp就是NDK的原始檔。

  Step5:接下來仿著NDK的demo,Hello-JNI工程寫一下。使用Alt + '/'可以程式碼提示!很爽!有木有?之前用CDT時候死活都按不出程式碼提示,鬱悶...

  JNI介面的命名規範是:Java_ + 呼叫該方法的包名(包名的點用_代替) + _ + 呼叫該介面的類名 + _ + 方法名,對於例項方法,有兩個引數是必要的,一個JNI的環境指標JNIEnv *,另一個是呼叫該方法的Java例項jobject

  my-ndk.cpp:

#include <jni.h>

JNIEXPORT jstring JNICALL Java_com_shamoo_activity_TestActivity_stringFromJNI(JNIEnv *env,
		jobject thiz) {
	return env->NewStringUTF("Hello jni");
}

  TestActivity.java:
public class TestActivity extends Activity {

	static {
		System.loadLibrary("my-ndk");
	}
	
	// 宣告JNI層的原生方法,使用native關鍵字
	public native String stringFromJNI();
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		TextView tvText = new TextView(this);
		tvText.setText(stringFromJNI());
		setContentView(tvText);
	}

}

  使用ndk庫必須在static程式碼塊裡面用System.loadLaibrary載入.so庫

  Step6:完成了,然後執行。執行之前先編譯NDK,然後在編譯JAVA程式碼。編譯也許會遇到Unable to launch cygpath. Is Cygwin on the path?錯誤,解決辦法如下:

    1.工程右鍵,點Properties->C/C++ Build的Building Settings中去掉Use default build command,然後輸入${NDKROOT}/ndk-build.cmd

    2.在C/C++ Build中點選Environment,點Add...新增環境變數NDKROOT,值為NDK的根目錄

    3.再編譯,問題就解決啦!

  執行時崩潰,遇到java.lang.UnsatisfiedLinkError: stringFromJNI錯誤,解決辦法:在C++檔案中函式定義前新增extern "C"修飾

extern "C" {
JNIEXPORT jstring JNICALL Java_com_shamoo_activity_TestActivity_stringFromJNI(JNIEnv *env,
		jobject thiz);
}

JNIEXPORT jstring JNICALL Java_com_shamoo_activity_TestActivity_stringFromJNI(JNIEnv *env,
		jobject thiz) {
	return env->NewStringUTF("Hello jni");
}

  原因是:使用extern "C"修飾,編譯器會按C語言的方式編譯和連線。在C語言中,函式編譯之後函式名與C++函式編譯之後不同,例如foo(int x, int y),C可能會編譯成_foo的名字,而C++因為支援過載,所以會編譯成像_foo_int_int這種帶引數的函式名。如果是按照C語言的編譯方式,呼叫foo函式是找不到_foo的函式名就會報出函式名找不到的錯誤。所以要新增extern "C"修飾。