從 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
#include
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))