第10章AndroidNDK开发本章结构:AndroidNDK的概念及用途AndroidNDK编译环境的建立与配置AndroidNDK的开发10.1NDK简介AndroidNDK(AndroidNativeDevelopmentKit)包含一系列的开发工具,允许程序开发人员在Android应用程序中嵌入C/C++语言编写的非托管代码AndroidNDK优势解决了核心模块使用托管语言开发执行效率低下的问题允许程序开发人员直接使用C/C++源代码,极大的提高了Android应用程序开发的灵活性AndroidNDK不足增加程序的使用非托管代码复杂性,增加了程序调试的难度CPU运算量大和内存消耗较少的部分运行效率最高,(例如信号处理或物理仿真)因此并不是所有的核心部分都适合使用C/C++语言编写10.1NDK简介AndroidNDK目前AndroidNDK的最新版本是7c,集成了交叉编译器,支持ARMv5TE处理器指令集、JNI接口和一些稳定的库文件AndroidNDK仅支持AndroidSDK1.5及以上版本,因此1.0和1.1版本的应用程序不能够使用AndroidNDKAndroidNDK提供一系列的说明文档、示例代码和开发工具,指导程序开发人员使用C/C++语言进行库文件开发,并提供便捷工具将库文件打包到apk文件中10.2NDK编译环境AndroidNDK编译环境支持WindowsXP、Linux和MacOS,这里仅介绍Windows系统的编译环境配置方法Windows系统的编译环境配置方法版本7以下NDK版本,需要安装Cygwin下载AndroidNDK的安装包下载并安装Cygwin配置Cygwin的NDK开发环境测试开发环境是否可以正常工作版本7及以上版本,无需安装Cygwin只要为EclipseAndroid工程添加一个Builder,就能实现Eclipse的自动编译NDK。10.2NDK编译环境下载AndroidNDK的安装包在Google的官方网站下载AndroidNDK的安装包,下载地址是,打开下载页面后选择的下载文件为android-ndk-r7c-windows.zip10.2NDK编译环境下载AndroidNDK的安装包将下载的ZIP文件解压缩到用户的Android开发目录中,作者将AndroidNDK解压到D:\Android目录中,ZIP文件中包含一层目录,因此AndroidNDK的最终路径为D:\Android\android-ndk-r7c10.2NDK编译环境为EcllipseAndroid工程添加一个Builder步骤一、创建或打开一个Android项目步骤二、为该项目添加一个Builder点击Project-Properties-Builders-New,新建立一个Builder。在弹出的对话框上面点击Program10.2NDK编译环境在弹出的对话框【EditConfiguration】中,配置选项卡【Main】:Location中需要填入nkd-build.cmd的路径(NDK安装目录下)。WorkingDiretcoty中需要填入Android的工程根目录。10.2NDK编译环境在弹出的对话框【EditConfiguration】中,配置选项卡【Refresh】:勾选“Refreshresourcesuponcompletion”,勾选“Theentireworkspace”,勾选“Recuresivelyincludesub-folders”。10.2NDK编译环境在弹出的对话框【EditConfiguration】中,配置选项卡【BuildOptions】:勾选“Aftera“Clean””,勾选“Duringmanualbuilds”,勾选“Duringautobuilds”,勾选“Specifyworkingsetofrelevantresources”。点击“SpecifyResources…”勾选Android工程的“jni“目录,Finish!10.2NDK编译环境在弹出的对话框【EditConfiguration】中,配置选项卡【BuildOptions】:勾选“Aftera“Clean””,勾选“Duringmanualbuilds”,勾选“Duringautobuilds”,勾选“Specifyworkingsetofrelevantresources”。点击“SpecifyResources…”勾选Android工程的“jni“目录,Finish!10.2NDK编译环境右键点击Android工程,BuildProject。当在console里面看到如下图六所示的信息,则表示一切正常,此时就已经是自动编译代码了。10.2NDK编译环境AndroidNDK的目录结构build目录保存了交叉编译工具、编译脚本和配置文件docs目录是帮助文档的保存目录samples目录是Android工程的保存目录,子目录hello-jni和tow-libs是NDK自带的两个示例目录ndk-build.cmd文件是非托管代码编译脚本文件GNUmakfile文件是make工具的配置文件README.TXT文件NDK的说明文件10.2NDK编译环境AndroidNDK自带两个示例hello-jni和tow-libshello-jni是一个非常简单的例子,非托管代码实现了一个可以返回字符串的共享库,Android工程调用这个共享库获取字符串,然后显示在用户界面上tow-libs是稍微复杂一些的例子,使用非托管代码实现了一个数学运算的共享库,Android工程动态加载这个共享库,并调用其中的函数,函数功能是通过使用静态库实现的10.3NDK开发示例在进行NDK开发时,一般需要同时建立Android工程和C/C++工程,然后使用NDK编译C/C++工程,形成可以被调用的共享库,最后共享库文件会被拷贝到Android工程中,并被直接打包到apk文件中进行AndroidNDK开发一般要经过如下的步骤:建立Android工程建立Android.mk文件建立C源代码文件编译共享库模块10.3NDK开发示例例子:AndroidNdkDemo是一个进行加法运算的示例,程序会随机产生两个整数,然后调用C语言开发的共享库对这两个整数进行加法运算,最后将运算结果显示在用户界面上AndroidNdkDemo示例的界面10.3NDK开发示例建立Android工程在project目录中建立Android工程时,需要取消复选框“Usedefaultlocation”,并指定预先建立的project文件夹作为工程文件夹在建立AndroidNdkDemo工程后,修改main.xml文件,添加一个id为display的TextView和一个id为add_btn的Button按钮10.3NDK开发示例建立Android工程程序中的生产随机数和调用的代码在AndroidNdkDemo.java文件中,下面是AndroidNdkDemo.java文件的核心代码1.publicclassAndroidNdkDemoextendsActivity{2.@Override3.publicvoidonCreate(BundlesavedInstanceState){4.super.onCreate(savedInstanceState);5.setContentView(R.layout.main);6.finalTextViewdisplayLable=(TextView)findViewById(R.id.display);7.Buttonbtn=(Button)findViewById(R.id.add_btn);8.btn.setOnClickListener(newView.OnClickListener(){9.@Override10.publicvoidonClick(Viewv){11.doublerandomDouble=Math.random();10.3NDK开发示例建立Android工程12.longx=Math.round(randomDouble*100);13.randomDouble=Math.random();14.longy=Math.round(randomDouble*100);15.16.//System.loadLibrary(add-module);17.longz=add(x,y);18.Stringmsg=x+++y+=+z;19.displayLable.setText(msg);20.}21.});22.}23.//publicnativelongadd(longx,longy);24.25.publiclongadd(longx,longy){26.returnx+y;27.}28.}10.3NDK开发示例建立Android工程上面的代码有一个NDK开发的小技巧,在开发C/C++的共享库前,可以使用具有相同和相近功能的Java函数进行替代。在代码第17行本应该调用共享库的add()函数,但为了便于开发和调试,在代码第25行到第27行,使用Java代码开发了一个功能相同的add()函数,这样即使在没有完成C/C++的共享库开发前,也可以对这个Android工程进行界面部分的调试第16行和第23行注释掉的代码,就是在C/C++的共享库开发完毕后需要使用的代码,其中第16行是动态加载共享库的代码,加载的共享库名称为add-module;第23行用来声明共享库的函数,使用C/C++开发的共享库必须有同名的函数。在共享库开发完毕后,取消第16行和第23行代码的注释,并注释掉第25行到第27行代码,这样程序就可以正常调用共享库内的函数进行加法运算10.3NDK开发示例本地调用加载本地模块本地函数声明与调用System.loadLibrary(“);publicnativelongadd(longx,longy);10.3NDK开发示例建立Android.mk文件建立C/C++源代码文件前,首先需要在sources目录中建立模块目录,AndroidNdkDemo示例的模块目录为add-module,这个模块目录的名称与Application.mk文件中声明的模块名称相同add-module目录中包含两个文件,Android.mk和add-module.c,目录结构如下(+)sources(+)add-module(-)Android.mk(-)add-module.c10.3NDK开发示例建立Android.mk文件Android.mk是为NKD编译系统准备的脚本文件,用来描述模块需要编译C/C++文件的信息通常NKD编译系统会搜寻$NDK/sources/*/目录中的所有Android.mk文件,但如果程序开发人员将Android.mk文件放置在下一级目录中,则需要在上一级目录中的Android.mk文件添加如下代码include$(callall-subdir-makefiles)10.3NDK开发示例建立Android.mk文件下面来分析AndroidNdkDemo示例的add-module模块的Android.mk文件Android.mk文件的代码如下1.LOCAL_PATH:=$(callmy-dir)2.3.include$(CLEAR_VARS)4.5.LOCAL_MODULE:=add-module6.LOCAL_SRC_FILES:=add-module.c7.8.include$(BUILD_SHARED_LIBRARY)10.3NDK开发示例建立Android.mk文件每个Android.