1. 前言

         Android 平台支持C/C++开发,也可以说支持本地(Native)开发。Android的SDK是基于Java实现的,但是并不意味着第三方应用只能使用Java编写程序,在SDK首次发布时,Google就宣称其虚拟机支持JNI编程方式,也就是第三方应用完全可以通过JNI调用自己的C/C++动态库,即在Android平台上,可以实现“Java+C/C++”编程方式。

它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。

Google也表示使用Native开发相较于原生SDK编程有一些劣势,Android SDK文档里找不到任何JNI方面的帮助。即使第三方应用开发者使用JNI完成自己的C/C++动态链接库(.so文件)开发,但是so文件如何和应用程序一起打包成apk并发布?还有程序更加复杂,平台兼容性难以保障,无法访问FrameWork API,Debug难度较大等。但是NDK的出现,很好解决了上面的问题。

        NDK的发布,实现了“Java+C”的开发方式,成为Google官方支持的开发方式。NDK将是Android平台支持C/C++开发的开端。


2. NDK简介


    NDK,即Native Development Kit,原生开发工具包,允许用户使用类似C / C++之类的原生代码语言执行部分程序。NDK提供了一份稳定、功能有限的API头文件声明,包含有C标准库(libc)、标准数学库(libm)、压缩库(libz)以及Log库(liblog)等等。


     NDK提供了一系列的工具。帮助开发者快速开发C/C++的动态库,并能自动将so和java应用一起打包成apk。NDK集成了交叉编译器,并提供了相应的mk文件隔离平台、CPU、API等差异,开发人员只需要简单修改mk文件,就可以编译出so文件。NDK可以自动地将so和Java应用一起打包。




      NDK包括了:


  •  从C/C++生成原生代码库所需要的工具和 build files。
  •  将一致的原生库嵌入可以在Android设备上部署的应用程序包文件(application package files,即apk文件中) 。
  • 支持所有未来Android平台的一系列原生系统头文件和库    


     NDK使用有以下优点:


  1.  代码的保护。由于apk的Java层代码很容易别反编译,C/C++库反编译难度较大;
  2.  可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的;
  3.  提高程序的执行效率。对要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率;
  4.  便于移植。用C/C++写的库可以方便地在其他嵌入式平台上再次使用。




3. NDK安装和配置



            


      这几篇博客详细介绍了NDK的安装和配置过程,并通过一个简单的项目演示了NDK的使用过程。



4. 几个重要的文件



1. Android.mk文件


     


         Android.mk 文件是GNU Makefile的一小部分,会被编译系统解析一次或多次。可以在每个Android.mk 文件中定义一个或多个模块,也可以在几个模块中使用同一个源代码文件。Android.mk 使用很多宏定义头,可以参考Android的源代码文件。


         几个常见的语法规则:


  • LOCAL_PATH := $(call my-dir),Android.mk首先必须定义好LOCAL_PATH变量,用于在开发树中查找源文件。宏函数‘my-dir’ 由编译系统提供,用于返回当前路径,即Android.mk文件所在的目录。
  • include $(CLEAR_VARS),CLEAR_VARS 由编译系统提供,指定让GNU Makefile 为你清除除 LOCAL_PATH 外的许多LOCAL_XXX变量(例如LOCAL_MODULE、LOCAL_SRC_FILES、LOCAL_STATIC_LIBRARIES等等)。这是必要的,因为所有的编译控制文件都在同一个GNU Make执行环境中,所有的变量都是全局的。
  • LOCAL_MODULE := demo,LOCAL_MODULE必须定义,以标识你在Android.mk 文件中描述的每个模块。名称必须是唯一的,而且不包括任何空格。注意编译系统会自动产生合适的前缀和后缀,也就是说,一个被命名为demo的共享库模块,将会生成libdemo.so文件。
  • LOCAL_SRC_FILES := demo.c,LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,不用在这里列出头文件和包含文件,因为编译系统将会自动找出依赖型的文件,仅仅列出直接传递给编译器的源代码文件就好。通常路径相对于当前的LOCAL_PATH。

      2. Application.mk文件




        Application.mk文件描述了应用程序需要哪些动态库和静态库。Application.mk文件通常放在项目目录的jni文件夹下。由于Application.mk文件说到底是作为GNU makefile 的一个片段,其中也需要定义一些变量。


几个常见的语法规则:


  • APP_ABI :默认条件是armeabi,在默认情况下,NDK会使用‘armeabi’ ABI来生成二进制机器码,这是基于ARMv5TE 的浮点运算CPU,这可以通过使用此变量来选择不同的ABI(Application Binary Interface)。

        支持基于armv7 FPU 指令集的设备:APP_ABI := armeabi-v7a;



APP_ABI := x86;



APP_ABI := armeabi armeabi-v7a x86;



  • APP_STL:默认条件下,NDK编译系统会使用Android系统提供的轻量级C++运行时库 /system/lib/libstdc++.so,NDK本身为用户提供了可供选择的C++库,用户可以使用或是连接到自己的应用。例如:

        APP_STL := stlport_static   -->以静态链接的方式使用stlport版本的STL;


APP_STL := stlport_shared   -->以动态链接的方式使用stlport版本的STL;



        APP_STL := system -->系统默认的最小支持的C++运行时库;



        APP_STL := gnustl_static   -->以静态链接的方式使用gnu版本的STL;



       官方提供stlport版本不支持RTTI和异常,即如果你使用了stlport版本的STL,则不能使用-fexceptions和-frtti这两个编译选项。