AndroidNDK Native Development Kit )实际上属于 JNI Java Native Interface )的一部分, JNI 就是允许 Java 代码和其他语言写的代码进行交互。 Android 基于 Java 平台,自然也是支持这个特征了,因此 Android NDK 就是支持在 Android 平台上使用 Java 语言调用采用 C/C++ 编译的库文件的一系列工具。

1. 下载: NDK 的下载页面为:http://developer.android.com/sdk/ndk/index.html ,当前最新版本为r8 ,如下图所示: Android小白成长之初级篇:NDK配置_第1张图片 2012-6-20 18:17 上传 下载附件 (21.93 KB)

前面我们说过Android SDK支持三种平台,这里相应的Android NDK也是分为三种平台WindowsLinux Mac OS X。其中Mac OS X 后面的括号中给出Intel。说明仅支持英特尔的硬件平台,即在英特尔的电脑上安装的Mac OS X系统才能使用该NDK,早期的苹果电脑使用的是非英特尔的硬件平台,所以这个对于苹果电脑用户而言需要是注意的。Linux平台后面的括号中给出x86,说明只支持运行在x86体系上的Linux平台。当然Windows平台早期还支持Alpha处理器,后来的版本就只支持x86体系了。鼠标点击链接后就开始下载相应的版本了。对Windows平台有特殊情结的可以使用Windows版本的NDK,当然需要Linux系统的模拟环境,最常用的就是Cygwin。苹果迷就直接用Mac OS X版本的NDK就行了。大多数用户,我们还是推荐使用Linux平台的NDK,下面我们就以Linux平台的NDK来配置NDK的开发环境。对于Linux环境,Google官方推荐平台是Ubuntu,我们这里用的是CentOS6.2版本,Linux不同版本对于开发来说大同小异,下面我们就以CentOS6.2来进行配置NDK。



2.NDK 的目录结构说明 下载Linux 平台的NDK 文件解压缩后看到的目录结构如下所示:
Android小白成长之初级篇:NDK配置_第2张图片 2012-6-20 18:25 上传 下载附件 (11.63 KB)

build :进行编译时用到的脚本和一些补丁 docs :有关NDK 的相关文档 platforms :针对不同Android 发行版本进行编译用到的头文件和库文件 prebuilt :一些小工具,用于真正编译前的预处理阶段 samples :给出了一些NDK 的例子 sources :一些在编译过程中被脚本或其它工具用到的头文件和库文件 tests :执行NDK 的自动化测试,确保NDK 正式发布后能够正常运行

toolchains:具体进行编译时的工具,包括对三种架构armmipsx86的支持



3.NDK 配置 这个版本NDK的配置比较简单,前面的老版本还需要设置许多环境变量,这个版本不需要设置,直接解压缩就可以了。主目录android-ndk-r8下有一个脚本文件ndk-build,这个就是进行编译用的脚本程序。当然,如果运行脚本时不想输入ndk-build的路径的话可以将其所在路径加入到PATH环境变量中,具体的加入方式我们在前面的“Linux平台JDK安装”一文中已经讲过,在此就不重复了。要编译的文件放在一个目录下,一般就叫jni(也可以叫别的名字),把这个目录放在Android工程下,编译后的库文件缺省会自动放到Android工程的库文件目录libs中。我们以NDK自带的例子程序hello-jni为例,如下图所示:
peixun_3.PNG 2012-6-20 18:34 上传 下载附件 (11.5 KB)

在jni的目录中,包括编译配置用的脚本文件和C/C++两种文件,C/C++除了少量遵循JNI规范外,主要实际上都是Linux环境中C/C++编程而已。配置文件主要有两个:Android.mk和Application.mk。我们简单说一下这两个文件,一般的NDK开发就足够了,想详细了解的话可以阅读NDK中的相关文档。 hello-jni例子中Android.mk文件为例,如下图所示:
Android小白成长之初级篇:NDK配置_第3张图片 2012-6-20 18:36 上传 下载附件 (4.34 KB)
上面两条是相关的参数和环境变量设置,我们不用管它。LOCAL_MODULE 右边的hello-jni 是编译后库的名字,LOCAL_SRC_FILES 右边的hello-jni.c C/C++ 源文件的名字,如果有多个源文件,只需要放在后面用空格隔开就行了,不需要把头文件放进来。最下面的BUILD_SHARED_LIBRARY 表示编译为动态库,如果要编译为静态库的话就应该是BUILD_STATIC_LIBRARY 文件Application.mk主要是对编译的补充,以native-plasma例子中的Application.mk为例,如下图所示:

APP_ABI ”的右边指定了所支持的处理器架构,本次版本的NDK 支持arm x86 mips 三种。缺省是按arm 架构编译。APP_PLATFORM 的右边指定的是Android 平台的版本。缺省是按Android SDK 1.5 版本编译,版本越高所提供的特性也越多,不过能适配的Android SDK 版本也就越少,意味着能够使用该应用的用户也越少。 当然,NDK既支持C语言环境,也支持C++语言环境,不过对C++的特性支持要少一些,具体可以看文档中对C++支持的相关说明。另外在Android.mkApplication.mk中都可以加入对C/C++进行编译的一些编译选项,以例子san-angeles中的Android.mk文件为例,如下图所示:
Android小白成长之初级篇:NDK配置_第4张图片 2012-6-20 18:44 上传 下载附件 (6.94 KB)

和前面的相比,这里上边多了LOCAL_CFLAGS,它的右边就是编译选项,这个例子中包括两个ANDROID_NDKDISABLE_IMPORTGL,每个选项前加上-D作为标识符。下边多了LOCAL_LDLIBS,它的右边是编译中用到的库,每个库名前加上-l作为标识符。


本版本的NDK 中有多个例子,我们简要说明一下这些的例子的具体作用,便于大家对这些例子有一个初步认识,至少知道每个例子引入的目的。 bitmap-plasma 如何在NDK 中使用bitmap 的例子,早期的NDK 版本不能直接使用bitmap ,后来的版本中增加了对bitmap 的支持。 hello-gl2 NDK 中如何使用OpenGLES 的运用 hello-jni 最基本的NDK 使用方式,通过NDK 获取字符串然后在Android 应用中显示出来 hello-neon NDK 中有关neon 的优化 module-exports 多个库的调用方式。foo 被编译为静态库,bar 被编译为动态库并调用了库foo zoo 被编译为动态库并调用了库bar native-activity 完全用NDK 实现整个Android 程序 native-audio NDK 中有关音频的操作 native-media NDK 中对视频的操作 native-plasma 完全用NDK 实现整个Android 程序并且提供了涉及plasma 的优化 san-angeles 移植到Android 平台的OpenGL ES 的例子 test-libstdc++ C++ 的支持,但并非支持C++ 的全部特征

two-libs:两个库的使用,first为静态库,second为动态库,并且second库调用first


4.C 语言代码实现: 我们以NDK开发包中自带的例子hello-jni来进行演示和说明。进入jni目录下,运行ndk-build就可以进行编译了,如下图所示:
Android小白成长之初级篇:NDK配置_第5张图片 2012-6-20 18:55 上传 下载附件 (73.71 KB)
编译后得到库libhello-jni.so ,以lib 字符作为前缀,so 作为后缀。实际在程序加载时要去掉这两部分,即文件名称在lib .so 中间的部分为真正的库名称。需要说明的是和libhello-jni.so 文件在一起的还有两个文件gdb.setup gdbserver ,这两个是用于NDK 调试的,在最后正式发布apk 文件时这两个文件时不需要的。具体NDK 的调试方法,我们在后面会将,现在在这里暂时不讲。
Eclipse中加载该例子,由于该例子最开始不是Eclipse项目,需要创建新项目,选择从源代码方式创建,如下图所示:
Android小白成长之初级篇:NDK配置_第6张图片 2012-6-20 19:02 上传 下载附件 (54.01 KB)

创建后,如下图所示:
Android小白成长之初级篇:NDK配置_第7张图片 2012-6-20 19:03 上传 下载附件 (122.06 KB)

Jni 目录下文件hello-jni.c 如下图所示:
Android小白成长之初级篇:NDK配置_第8张图片 2012-6-20 19:03 上传 下载附件 (9.13 KB)

从上面两幅图可以看到,hello-jniJava环境中的类HelloJni中声明的函数名为stringFromJNI,前面要用到修饰符native,类HelloJni所在的包名为com.example.hellojni,需要用函数System.loadLibrary加载liblibhello-jni.so,采用static修饰符确保只加载一次。然后按正常函数使用就行了。而在NDK这边,即C语言这层,函数命名要遵循Java___函数的命名方式,中间用下划线_进行连接,如上面所示,在包com.example.hellojni中的类HelloJni声明为stringFromJNI,则在C/C++文件中定义的函数名为Java_com_example_hellojni_HelloJni_stringFromJNI,注意区分大小写。函数可以传参数,本例子中没有传入参数,只是有返回参数,返回参数的数据类型为jstring,即Java中的String类型。对于C/C++中与上面的Java环境打交道的数据类型可以参照JNI,具体可访问官方网站http:// java.sun.com/docs/books/jni/。对于函数Java_com_example_hellojni_HelloJni_stringFromJNI中的两个参数envthiz是系统必须的,如果需要输入参数,必须再增加参数。这个例子运行的结果就是在文本控件(TextView)上面显示Hello from JNI by C !,如下图所示:
peixun_10.PNG

5.C++ 语言代码实现: 我们对上面的例子 hello-jni 稍微改动,改名为 hello-jni-ex ,为了以示区别把类名和包名也稍微修改了一下。 C++ 语言这种方法灵活性更好,当然,具体采用哪一种根据自己的喜好选择。 Hello-jni-ex 如下图所示:
Android小白成长之初级篇:NDK配置_第9张图片 2012-6-20 19:08 上传 下载附件 (184.74 KB)

程序运行结果如下图所示: peixun_13.PNG 2012-6-20 19:09 上传 下载附件 (25.33 KB)

有关NDK 的实现部分如下图所示: Android小白成长之初级篇:NDK配置_第10张图片 2012-6-20 19:10 上传 下载附件 (205.04 KB)

函数registerNativeMethods registerNatives ,以及JNI_OnLoad 里边的东西,我们这边暂时不讲述,后面进一步讲述NDK 开发时再详细讲述。我们真正自己定义的NDK 函数是testStringFromJNI ,这个函数名称不需要和上层Java 类中的native 声明函数保持一致。需要保持一致的是对应的包名和类名,这个在变量classPathName 中定义了,定义为:com/example/hellojniex/HelloJniEx 。在JNINativeMethod 类型的数组filterMethods 中建立上层Java 层面函数调用和NDK 层函数之间的映射关系。第一个变量stringFromJNI 为在Java 层进行调用的函数名称,第二个变量()Ljava/lang/String; 为函数的参数和返回值,第三个变量(void*)testStringFromJNI NDK 层函数名称(实际就是函数指针)。第一个变量和第三个变量都很容易理解,第二个变量理解起来麻烦一些。()中表示的是函数的参数类型,()后面表示的是函数的返回参数类型。例如本例中的()Ljava/lang/String; 就表示没有参数,返回String 类型。类型说明如下: 字符 Java类型 C类型 V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short
数组则以"["开始,用两个字符表示
[I jintArray int[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]
[D jdoubleArray double[]
[J jlongArray long[]
[Z jbooleanArray boolean[]
上面的都是基本类型。如果Java 函数的参数是class ,则以"L" 开头,以";" 结尾中间是用"/" 隔开的包及类名。而其对应的C 函数名的参数则为jobject. 一个例外是String 类,其对应的类为jstring Ljava/lang/String;String jstring
Ljava/net/Socket; Socket jobject 如果JAVA 函数位于一个嵌入类,则用$ 作为类名间的分隔符。 例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"


6 .总结: 本次有关 NDK 的配置到此就讲完了,看完本文后,用户应该能够基本掌握 NDK 的配置和开发。对于进一步有关 NDK 的开发,我们将在后面的高级开发中详细讲解。

更多相关文章

  1. 完美Android Cursor使用例子(Android数据库操作)
  2. 修改Android中的文件权限
  3. Android录音文件在IOS上播放不出来的问题
  4. 几行代码看程序员的水平——Android文件命名规范
  5. Android — 创建文件及文件夹
  6. Android文件选择器的实例分享
  7. Android的程序解码与XML文件解码
  8. 在Android上调用OpenCV 2.4.10库函数

随机推荐

  1. 基于android平台开发的计算器
  2. Creating Release Keys and Signing Buil
  3. 按返回键返回到主界面
  4. 编译android源码前的准备
  5. android项目中单实例数据库类
  6. IOS 实现android Toast效果
  7. 自定义view之自定义圆角矩形imageview
  8. android 获取本机IP地址
  9. Android实现图片上传
  10. PhoneWindow源码