天天看點

eclipse android ndk r10d開發,Android NDK開發

一、Android NDK環境搭建

使用最新ndk,直接抛棄cygwin,以前做Android的項目要用到NDK就必須要下載下傳NDK,下載下傳安裝Cygwin(模拟Linux環境用的),下載下傳CDT(Eclipse C/C++開發插件),還要配置編譯器,環境變量,特别麻煩,新版就不需要了。

方法/步驟

Android官網下載下傳Android的開發工具ADT(Android Development Tool的縮寫),該工具內建了最新的ADT和NDK插件以及Eclipse,還有一個最新版本SDK,解壓之後就可以用了。

ADT插件:管理Android SDK和相關的開發工具的

NDK插件:用于開發Android NDK的插件,ADT版本在20以上,就能安裝NDK插件,另外NDK內建了CDT插件 。下載下傳連結見:http://developer.android.com/sdk/index.html

Android官網下載下傳最新的NDK,注:NDK版本在r7以上之後就內建了Cygwin,而且還是十分精簡版。

下載下傳連結見:http://developer.android.com/tools/sdk/ndk/index.html

eclipse配置

解壓ndk并配置環境變量:添加系統環境變量NDK_ROOT為: D:Androidandroid-ndk-r10d。

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

(如果沒有ndk選項,則可能是因為沒有ndk插件,自行下載下傳一個放入eclipseplugins下重新開機即可)

eclipse android ndk r10d開發,Android NDK開發

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

eclipse android ndk r10d開發,Android NDK開發

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

接下來仿着NDK的demo,Hello-JNI工程寫一下。使用Alt + '/'可以代碼提示!很爽!有木有?

JNI接口的命名規範是:Java_ + 調用該方法的包名(包名的點用_代替) + _ + 調用該接口的類名 + _ + 方法名,對于執行個體方法,有兩個參數是必要的,一個JNI的環境指針JNIEnv *

eclipse android ndk r10d開發,Android NDK開發

完成了,然後運作。運作之前先編譯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

(注意:這裡是正斜杠/)

eclipse android ndk r10d開發,Android NDK開發

2.在C/C++ Build中點選Environment,點Add...添加環境變量NDKROOT,值為NDK的根目錄.(注意:這裡是反斜杠)

eclipse android ndk r10d開發,Android NDK開發

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

問題二、使用c++來編寫本地庫,會有一些相容問題。

(1)直接黏貼HelloJni的stringFromJNI函數過來測試,提示Method 'NewStringUTF' could not be resolved解決方法:将(*env)->NewStringUTF(env, "Hello from JNI !")改為return env->NewStringUTF("Hello from JNI !")即可

原因是:NDK plugin預設為我們生成的是cpp檔案,而C與C++調用函數的參數不一緻,是以找不到函數,具體參考jni.h中的定義。cpp檔案中形如(*env)->Method(env, XXX)改成env->Method(XXX)即可。

(2)運作c++生成的.so庫,若報以下錯誤:(既找不到函數)

No implementation found for native Lcom/dgut/android/MainActivity;.stringFromJNI ()Ljava/lang/String;

java.lang.UnsatisfiedLinkError: stringFromJNI

at com.dgut.android.MainActivity.stringFromJNI(Native Method)

解決方法:

為供Java調用的c++函數前加入extern "C" 修飾,如:(NDK example裡面的cpp檔案也是這麼聲明的,參考hello-gl2)

extern "C" {

JNIEXPORT jstring JNICALL ava_com_wytiger_jnidemo_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz);

};

JNIEXPORT jstring JNICALL ava_com_wytiger_jnidemo_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz )

{

return env->NewStringUTF("Hello from JNI bear c++");

}

原因是:

被extern "C"修飾的變量和函數是按照C語言方式編譯和連接配接的。

首先看看C++中對類似C的函數是怎樣編譯的:作為一種面向對象的語言,C++支援函數重載,而過程式語言C則不支援。函數被C++編譯後在符号庫中的名字與C語言的不同。例如,假設某個函數的原型為:void foo( int x, int y );該函數被C編譯器編譯後在符号庫中的名字為_foo,而C++編譯器則會産生像_foo_int_int之類的名字(不同的編譯器可能生成的名字不同,但是都采用了相同的機制,生成的新名字稱為“mangled name”)。_foo_int_int這樣的名字包含了函數名、函數參數數量及類型資訊,C++就是靠這種機制來實作函數重載的。例如,在C++中,函數voidfoo( int x, int y )與void foo( int x, float y )編譯生成的符号是不相同的,後者為_foo_int_float。

同樣地,C++中的變量除支援局部變量外,還支援類成員變量和全局變量。使用者所編寫程式的類成員變量可能與全局變量同名,我們以"."來區分。而本質上,編譯器在進行編譯時,與函數的處理相似,也為類中的變量取了一個獨一無二的名字,這個名字與使用者程式中同名的全局變量名字不同。

是以,若我們沒有使用extern "C"修飾函數,按照C語言方式編譯和連接配接,Jni調用将可能找不到該函數。

問題三、Android NDK: WARNING: APP_PLATFORM android-14 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml    (這個是NDK工具的一個BUG,若build Target大于minSdkVersion,則會報這個錯誤,導緻無法運作)

解決方法:在Application.mk檔案中添加APP_PLATFORM := android-8

問題四、Type 'jint' could not be resolved, and JNIEnv, jclass

Project Properties -> C/C++ General -> Path and Symbols,選擇include标簽,Add -> $Android_NDK_HOME/platforms/android-14/arch-arm/usr/include

選中All languages.  最後Apply -> OK