開發環境下載:

JDK

cywin

eclipse: plugin ADT(for android) + CDT(for C/C++)

android sdk

android ndk

 

編輯/home/your_account/.bash_profile,並加入以下環境變數宣告(請依sdk的存放位置改變路徑)

ANDROID_TOOLS=/android/android-sdk/tools/ANDROID_PLATFORM_TOOLS=/android/android-sdk/platform-tools/NDK_ROOT=/android/android-ndk-r8b/NDK_SAMPLE=/android/android-ndk-r8b/samples/ export PATH=ANDROID_TOOLS:NDK_ROOT:$NDK_SAMPLE  

打開Cygwin Bash Shell,在windows下,因為換行的格式不同(\r\n),因此在存檔後需將格式換回unix,請執行以下指令:dos2unix .bash_profile

這樣子在每次打開Cygwin Bash Shell的時候,因為系統就會自動去執行.bash_profile這個檔案,所以便能夠自動將正確的路徑導入到環境變數之中。

試著執行: adb version,如果可以執行便表示環境變數順利載入,shell可以找到ANDROID_PLATFORM_TOOLS底下的工具。

android hello world:

新建一個android application project,然後run as Android application.

那麼,我們到底該怎麼使用NDK來呼叫C/C++呢?

首先,在專案目錄下建立一個資料夾:jni,接著在這個資料夾中加入三個檔案:

Android.mk:

LOCAL_PATH := (CLEAR_VARS) LOCAL_LDLIBS := -llog LOCAL_MODULE := myNativeLOCAL_SRC_FILES := native.cpp include $(BUILD_SHARED_LIBRARY)  

Application.mk:

APP_STL := stlport_static  

native.cpp (這個可以隨自己高興命名,但必須命名一致其中functin的命名規則必須遵照一定的格式):

#include <jni.h>#include #include <android/log.h>#include <stdlib.h>#include #include #define DEBUG_TAG “NDK_AndroidNDKMainActivity” #ifdef __cplusplusextern “C” {#endif using namespace std;void Java_com_horizon_AndroidHelloWorld_MainActivity_helloLog(JNIEnv * env, jobject obj, jstring logThis){ jboolean isCopy; std::vectorstd::string vec;  const char * szLogThis = envGetStringUTFChars(logThis, &isCopy);  __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, “NDK:LC: [%s]”, szLogThis);  envReleaseStringUTFChars(logThis, szLogThis);} #ifdef __cplusplus}#endif  

Java端如下:

package com.horizon.AndroidHelloWorld; import com.horizon.AndroidHelloWorld.R; import android.os.Bundle;import android.app.Activity;import android.view.Menu;import android.view.View; public class MainActivity extends Activity {  @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }  @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } private native void helloLog(String logThis); public void onClickButton(View v){ helloLog(“This will log to LogCat via the native call.”); } static { System.loadLibrary(“myNative”); }  }  

 

之後打開cygwin bash shell,到project的目錄底下,執行以下指令:

ndk-build

如果執行成功,則會產生檔案至project/obj/local/armeabi/libmyNative.so

名稱則是Android.mk中LOCAL_MODULE中加上前綴lib及後綴.so,由於這個特性,因此在命名LOCAL_MODULE的時候,千萬不能以lib作為開頭,因為NDK會沒辦法產生正確的.so檔。

 

之後,就可以執行android程式來進行測試。

 

另外,請注意任何在android.mk中的space都會導致路徑無法找到

例如:

“LOCAL_PATH := (call my-dir)                    “是不同的,後者會導致 no rule to make target的錯誤。

 

如果產生

expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘.’ token 之類的錯誤 則表示我們用到gcc去編譯C++的檔案了,解決方法有二種:

1.改用g++來編譯:.c的檔案會使用gcc而.cpp會使用g++。

2.加入extern “C”在C的CODE中來兼容C的語法

只是,在jni中,其提供了二個不同的界面給C及C++使用,例如同樣一個function:

在C中:(*env)NewStringUTF(env, “Hello from JNI”);

在C++中:envNewStringUTF(“Hello from JNI”);

請參閱:JNI programming in C++.

由於C是C++的子集合,而C++在語法規則上又比C更加的嚴格,因此在開發上最好統一用C++來進行開發。(意即所有的檔名都是以.h或.cpp結尾)

在初始的設定上,其實NDK並不支持stl,為了效能的問題,在預設計只會使用最少的C++函式庫。如果要使用stl的話,我們就必須在Application.mk中加入以下的宣告:

APP_STL                 := stlport_static

其實還有其他的stlport,各有不同特性的支援:

stlport_static :目前推薦的方法,但在現時點並不支援exception及RTTI

stlport_shared:作為動態函式庫,可能會有兼容性的問題,目前不推薦使用。

gnustl_static:其使用GNU libstdc++作為靜態庫,可支援exception及RTTI,但由於這個library的license是基於GPLv3,因此在使用前要多加考慮。

參考:http://www.open-open.com/bbs/view/1319209398468