從 Android NDK | Android Developers 下載 Android NDK (我在 Ubuntu 所以下載 android-ndk-r5c-linux-x86.tar.bz2) 並挑選一個地方解壓縮(此例爲 ~/android-ndk-r5c),除此之外要把 Android SDK 更新至最新版,如果已經安裝好 Android 開發環境,更新方式透過 Eclipse -> [Window]-> [Android SDK and AVD Manager] -> [Installed packages] -> [Update All...]
接着要進行 NDK 環境設置,可查看 android-ndk-r5c/docs/INSTALL.html,可以得知 Android NDK 至少需使用 Android 1.5 系統,而編譯環境至少是 GNU Make 3.8.1,除此之外還需要 Nawk 或 GNU Awk 工具,而常見的 awk 則不適用。
在 Ubuntu 10.04 64-bit desktop 環境上:
$ awk -W version
GNU Awk 3.1.6
Copyright (C) 1989, 1991-2007 Free Software Foundation.
~$ make -version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc
透過Eclipse 建立一個 android 2.3.3 project,例如 MyNDK:
Project name: MyNDK
Build Target: Android 2.3.3/Android Open Source Project/2.3.3/10
Application name: MyNDK
Package name: com.example.ndk
Create Activity: MyNDK
Min SDK Version: 3
接著,在 Eclipse 左邊 Project Explorer 建立 jni 和 libs 兩個目錄,位置擺在剛剛的 Project 裏(點一下 MyNDK,接着按右鍵選 New -> Folder 輸入 jni,之後在建立 libs 目錄):
MyNDK/jni
MyNDK/libs
在 MyNDK/jni 裏頭新增兩個檔案,分別是 JNI 程式碼和 Android.mk,結構如下:
MyNDK/jni
MyNDK/jni/Android.mk
MyNDK/jni/my-jni.c
其中 Android.mk 和 .c 可以從 android-ndk-r5c/samples/hello-jni/jni 裏頭尋得範例:
MyNDK/jni/Android.mk (參考 android-ndk-r5c/samples/hello-jni/jni/Android.mk)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my-jni
LOCAL_SRC_FILES := my-jni.c
include $(BUILD_SHARED_LIBRARY)
MyNDK/jni/my-jni.c (參考 android-ndk-r5c/samples/hello-jni/jni/hello-jni.c)
#include <string.h>
#include <jni.h>
jstring Java_com_example_ndk_MyNDK_stringFromJNI( JNIEnv* env, jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello from My JNI !");
}
其中要留意 function name,裏頭包括 packages name 和 Activity name 等信息,此例是 com_example_ndk 和 MyNDK。
接著要透過 android ndk 去編譯 my-jni.c,除了在 Command line 可以切換到 MyNDK 目錄,用 android-ndk-r5c/ndk-build 進行編譯外,還可以透過 Eclipse 設定好,讓你每次自動編譯好:
在 Eclipse 左邊 Project Explorer 點選 MyNDK,選右鍵 -> Properties -> Builders -> New -> Program
在 Main 分頁:
Name: NDK_Builder
Location(ndb-build位置): /home/user/android-ndk-r5c/ndk-build
Working Directory:(project位置): ${workspace_loc:${project_path}}
在 Refresh 分頁:
將 Refresh resources upon completion 打勾,並且在 Specific resources 選擇 MyNDK/libs 目錄
在 Build Options 分頁:
勾選 Allocate Console(necessary for input)、Launch in backgroud、After a "Clean"、During manual builds、During auto builds 和 Specify working set of relevant resources
在 Specific resources 選擇 MyNDK/jni
如此一來,只要編譯或清除時,自動會編譯jni 的部份,可以使用 Build all(快捷鍵Ctrl+B) 試試,可以看到 Console 的輸出:
Compile thumb : my-jni <= my-jni.c
SharedLibrary : libmy-jni.so
Install : libmy-jni.so => libs/armeabi/libmy-jni.so
接着,才正式要寫 Java 程式部份,切換到 MyNDK.java:
package com.example.ndk;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class MyNDK extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
TextView tv = new TextView(this);
tv.setText( stringFromJNI() );
setContentView(tv);
}
public native String stringFromJNI();
static {
System.loadLibrary("my-jni");
}
}
其中特別的是要宣告 jni 使用到的函數,這跟 my-jni.c 的宣告有關,以及 System.loadLibrary 的部份,跟 jni/Android.mk 設定的編譯結果也有關係,如果都不相符,執行時會出現 exception。
最後跑起來的效果:
整個Project結構:
One Error on NDK-r8d
failed. d:/Development/android/android-ndk-r8d/build/gmsl/__gmsl:512: *** non-numeric second argument to `wordlist' function: ''. Stop.
Solution:
int_encode = $(__gmsl_tr1)$(wordlist 1, $1,$(__gmsl_input_int))
=>
int_encode = $(__gmsl_tr1)$(wordlist 1,$(words $1),$
(__gmsl_input_int))