除了SDK,Android 还提供了一套可以直接用 C/C++ 编程的 NDK。这里将会介绍如何用 NDK 编写 JNI。
Google Android 文档里面有一个简单的 NDK 教程,大致的过程是:
-
把你的C/C++代码放到路径 <project>/jni/...
-
为 NDK 编译系统创建 <project>jni/Android.mk
-
可选:创建 <project>/jni/Application.mk
-
用 ndk-build 编译你的工程:
cd <project> <ndk>/ndk-build
-
编译工具会把 stripped, shared libraries 放到应用工程的正确路径。最后,用 SDK 编译你的应用,SDK 编译工具会把 shared libraries 打包到应用的 .apk 文件里。
Google 这个教程描述得非常简单,这里结合一个具体的工程讨论一些细节。
C++ 代码
如果 JNI 是用 C++ 编写的,需要声明 extern "C"。
#ifdef __cplusplus
extern "C" {
#endif
// JNI code here...
#ifdef __cplusplus
}
#endif
不然运行时会报 java.lang.UnsatisfiedLinkError 异常。
在 C++ 里面,JNIEnv* 的用法跟 C 不一样:
env->NewStringUTF("Hello from JNI !");
Android.mk
我的工程的 Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CPPFLAGS += -fexceptions -frtti -DTIXML_USE_TICPP # enable exception/rtti, 自定义宏
LOCAL_MODULE := xmpp2ber # 目标库
LOCAL_SRC_FILES := xmpp2ber.cpp ticpp.cpp tinystr.cpp tinyxml.cpp tinyxmlerror.cpp tinyxmlparser.cpp
LOCAL_CFLAGS := -ggdb # 包含 gdb 调试信息,发行版本需要关掉
include $(BUILD_SHARED_LIBRARY)
Application.mk
指定要使用静态 gnu stl 库:
APP_STL := gnustl_static
ndk-build
NDK 编译时,为了看到详细的编译过程,可以加开关:
ndk-build V=1 -B
如果想编译 DEBUG 版本:
ndk-build NDK_DEBUG=1
PS: 如果要支持 ndk-gdb,还需要在 AndroidManifest.xml 加 <application android:debuggable="true"...
这里要注意的是,jni 的代码更新后,eclipse Android SDK 插件并不会自动重新生成 .apk,一般刷新(右击->Refresh)一个工程就可以了。
下一次我们来讨论一下用 Android NDK 调试方法。