一點點筆記:
就算code都是用c style寫的, 但只要用了STL之類的c++ library就要視為c++處理, 以下是編譯步驟.
1. 和往常一樣在project之中建立jni資料夾, 關鍵是資料夾中的c++檔案要以.cpp附檔名,
如此一來使用ndk-build script的時候就會自動選用c++的compiler來編譯. 不然build的時候會先遇到找不到header的error. 因為c++ compiler和c compiler 的搜尋header路徑不同.
2. 建立Android.mk在jni資料夾中, 內容大概像這樣
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := temp_jni
LOCAL_SRC_FILES := test.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS) -> 開始一段全新乾淨的編譯
LOCAL_MODULE := temp_jni -> 指定編出來的library名稱, 這樣會編出 libtemp_jni.so
LOCAL_SRC_FILES := test.cpp -> 當然就是要編譯的source file了
LOCAL_LDLIBS := -llog -> 在這邊我們多link一個log的library之後debug用,不是必須但是很方便,等等介紹怎麼用.
include $(BUILD_SHARED_LIBRARY) -> 最後呼叫Android負責編譯shared library的script開始編譯
3(Optional). 使用liblog.so的print log debug 功能: (即上述LOCAL_LDLIBS := -llog)
在.cpp source file內加入以下內容
#define LOG_TAG "TEST_JNI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
之後只要在c++ Code中使用 LOGE("hello world");就可以像在android java program 中使用Log.e(LOG_TAG,"hello world")一樣印log在logcat中! 同理LOGI,LOGV等.
4.在jni資料夾下建立一個Application.mk檔案, 內容如下面一行
APP_STL := stlport_static
目的是這樣的, 因為Android NDK預設只會link一份最簡陋的STL, 但其實NDK中有還是有放一份完整的STL, 所以要告訴編譯器編譯時去使用這份完整的STL.
附帶一提APP_STL的值有以下四種:
system -->預設,簡陋
stlport_static
stlport_shared
gnustl_static
system -->預設,簡陋
stlport_static
stlport_shared
gnustl_static
5. 寫一個使用STL的 .cpp file吧!
像這樣
像這樣
#include <vector>
#include <jni.h>
#include <android/log.h>
//見第3點
#define LOG_TAG "FEATRUEEXTRACTION"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
using namespace std;
void runTest(const char* in)
{
vector<const char*> tt;
tt.push_back("hello");
tt.push_back("world");
tt.push_back(in);
LOGE(tt[2]);//會在logcat中印出從java端呼叫JNITestFunction時所傳入的String
}
extern "C"{ //注意
void
Java_com_example_temp_MainActivity_JNITestFunction( JNIEnv* env,
jobject thiz , jstring inString)
{
//should be released
const char *in = (env)->GetStringUTFChars(inString,0);
runTest(in);
}
} //注意
有兩點要特別注意:
一,一定要用extren "C"{}包住jni function,不然runtime會找不到這個jni function.
二,使用C++的時候jni.h的function會被一層wrapper包住,所以呼叫的方法和使用c的時候不一樣,
如上面使用GetStringUTFChars function 在c的版本會是這樣使用:
(*env)->GetStringUTFChars(env,inString,0);
細節只要去NDK的platforms/android-(隨便一個版本)/arch-arm/usr/included/jni.h中看就瞭解.
6.java的部分大概長這樣
package com.example.temp;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
public static native void JNITestFunction(String inString);
static {
System.loadLibrary("temp_jni");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
JNITestFunction("cyy");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
7.切換目錄到jni/下面使用 <NDKROOT>/ndk-build 指令.
這樣會編出shared library. 這些編出來的library之後會被包進.apk中一併燒進手機中
8. 在Eclipse中像平常一樣執行這個app, 搞定收工!