Android之NDK初探

转载 2015年07月07日 16:35:27

一、NDK产生的背景

  Android平台从诞生起,就已经支持C、C++开发。众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第三方应用都必须使用Java语言。但这并不等同于“第三方应用只能使用Java”。在Android SDK首次发布时,Google就宣称其虚拟机Dalvik支持JNI编程方式,也就是第三方应用完全可以通过JNI调用自己的C动态库,即在Android平台上,“Java+C”的编程方式是一直都可以实现的。

  不过,Google也表示,使用原生SDK编程相比Dalvik虚拟机也有一些劣势,Android SDK文档里,找不到任何JNI方面的帮助。即使第三方应用开发者使用JNI完成了自己的C动态链接库(so)开发,但是so如何和应用程序一起打包成apk并发布?这里面也存在技术障碍。比如程序更加复杂,兼容性难以保障,无法访问Framework API,Debug难度更大等。开发者需要自行斟酌使用。

  于是NDK就应运而生了。NDK全称是Native Development Kit。

  NDK的发布,使“Java+C”的开发方式终于转正,成为官方支持的开发方式。NDK将是Android平台支持C开发的开端。

二、为什么使用NDK

  1.代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。

  2.可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。

  3.提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。

  4.便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。

三、NDK简介

   1.NDK是一系列工具的集合

   NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。

NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。

NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。

   2.NDK提供了一份稳定、功能有限的API头文件声明

   Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。

四、NDK开发环境的搭建

1.下载安装Android NDK

  地址:http://developer.android.com/sdk/ndk/index.html

2.下载安装cygwin

  由于NDK编译代码时必须要用到make和gcc,所以你必须先搭建一个linux环境, cygwin是一个在windows平台上运行的unix模拟环境,它对于学习unix/linux操作环境,或者从unix到windows的应用程序移植,非常有用。通过它,你就可以在不安装linux的情况下使用NDK来编译C、C++代码了。下载地址:http://www.cygwin.com

  1)然后双击运行吧,运行后你将看到安装向导界面。

  2)点击下一步,此时让你选择安装方式:

Install from Internet:直接从Internet上下载并立即安装(安装完成后,下载好的安装文件并不会被删除,而是仍然被保留,以便下次再安装)。
Download Without Installing:只是将安装文件下载到本地,但暂时不安装。
Install from Local Directory:不下载安装文件,直接从本地某个含有安装文件的目录进行安装。

  3)选择第一项,然后点击下一步。

  4)选择要安装的目录,注意,最好不要放到有中文和空格的目录里,似乎会造成安装出问题,其它选项不用变,之后点下一步:

  5)上一步是选择安装cygwin的目录,这个是选择你下载的安装包所在的目录,默认是你运行setup.exe的目录,直接点下一步就可以:

  6)此时你共有三种连接方式选择:

Direct Connection:直接连接。
Use IE5 Settings:使用IE的连接参数设置进行连接。
Use HTTP/FTP Proxy:使用HTTP或FTP代理服务器进行连接(需要输入服务器地址、端口号)。

  用户可根据自己的网络连接的实情情况进行选择,一般正常情况下,均选择第一种,也就是直接连接方式。然后再点击“下一步”。

  7)这是选择要下载的站点,选择后点下一步。

  8)此时会下载加载安装包列表

  9)Search是可以输入你要下载的包的名称,能够快速筛选出你要下载的包。那四个单选按钮是选择下边树的样式,默认就行,不用动。View默认是Category,建议改成full显示全部包再查,省的一些包被隐藏掉。左下角那个复选框是是否隐藏过期包,默认打钩,不用管它就行,下边开始下载我们要安装的包吧,为了避免全部下载,这里列出了后面开发NDK用得着的包:autoconf2.1、automake1.10、binutils、gcc-core、gcc- g++、gcc4-core、gcc4-g++、gdb、pcre、pcre-devel、gawk、make共12个包

  10)然后开始选择安装这些包吧,点skip,把它变成数字版本格式,要确保Bin项变成叉号,而Src项是源码,这个就没必要选了。

  11)下面测试一下cygwin是不是已经安装好了。

  运行cygwin,在弹出的命令行窗口输入:cygcheck -c cygwin命令,会打印出当前cygwin的版本和运行状 态,如果status是ok的话,则cygwin运行正常。

  然后依次输入gcc –version,g++ --version,make –version,gdb –version进行测试,如果都打印出版本信息和一些描述信息,则cygwin安装成功!

3.配置 NDK 环境变量

  a.首先找到 cygwin 的安装目录,找到一个 home\< 你的用户名 >.bash_profile 文件,我的是:E:\cygwin\home\Administrator.bash_profile , ( 注意:我安装的时候我的 home 文件夹下面什么都没有,解决 的办法:首先打开环境变量,把里面的用户变量中的 HOME 变量删掉,在 E:\cygwin\home 文件夹下建立名为Administrator 的文件夹(是用户名),然后把 E:\cygwin\etc\skel.bash_profile 拷贝到该文件夹下 ) 。

  b.打开 bash_profile 文件,添加 NDK=/cygdrive/< 你的盘符 >/

include

ifndef _Included_com_example_hellojni_HelloJni

define _Included_com_example_hellojni_HelloJni

ifdef __cplusplus

extern “C” {

endif

/*

  • Class: com_example_hellojni_HelloJni

  • Method: stringFromJNI

  • Signature: ()Ljava/lang/String;

    */

JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI

(JNIEnv *, jobject);

/*

  • Class: com_example_hellojni_HelloJni

  • Method: unimplementedStringFromJNI

  • Signature: ()Ljava/lang/String;

    */

JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_unimplementedStringFromJNI

(JNIEnv *, jobject);

ifdef __cplusplus

}

endif

endif

上面代码中的JNIEXPORT 和 JNICALL 是jni的宏,在android的jni中不需要,当然写上去也不会有错。从上面的源码中可以看出这个函数名那是相当的长啊。。。。 不过还是很有规律的, 完全按照:java_pacakege_class_mathod 形式来命名。

  也就是说:

  Hello.java中 stringFromJNI() 方法对应于 C/C++中的 Java_com_example_hellojni_HelloJni_stringFromJNI() 方法

  HelloJni.java中的 unimplementedStringFromJNI() 方法对应于 C/C++中的 Java_com_example_hellojni_HelloJni_unimplementedStringFromJNI() 方法

  注意下其中的注释:

  Signature: ()Ljava/lang/String;

  ()Ljava/lang/String;()表示函数的参数为空(这里为空是指除了JNIEnv , jobject 这两个参数之外没有其他参数,JNIEnv, jobject是所有jni函数必有的两个参数,分别表示jni环境和对应的java类(或对象)本身),Ljava/lang/String; 表示函数的返回值是java的String对象。

b. 编写相应的.c文件:

  hello-jni.c :
 #include

include

Licensed under the Apache License, Version 2.0 (the “License”);

you may not use this file except in compliance with the License.

You may obtain a copy of the License at

#

http://www.apache.org/licenses/LICENSE-2.0

#

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an “AS IS” BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.

#

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hello-jni

LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)

 这个Androd.mk文件很短,下面我们来逐行解释下:

    LOCAL_PATH := $(call my-dir)

  一个Android.mk 文件首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数’my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。

    include $( CLEAR_VARS)

  CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等…), 除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。

    LOCAL_MODULE := hello-jni

  编译的目标对象,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。

注意:编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为’hello-jni’的共享库模块,将会生成’libhello-jni.so’文件。

  重要注意事项:如果你把库命名为‘libhello-jni’,编译系统将不会添加任何的lib前缀,也会生成 ‘libhello-jni.so’,这是为了支持来源于Android平台的源代码的Android.mk文件,如果你确实需要这么做的话。

    LOCAL_SRC_FILES := hello-jni.c

  LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。

  注意,默认的C++源码文件的扩展名是’.cpp’. 指定一个不同的扩展名也是可能的,只要定义LOCAL_DEFAULT_CPP_EXTENSION变量,不要忘记开始的小圆点(也就是’.cxx’,而不是’cxx’)

    include $(BUILD_SHARED_LIBRARY)

  BUILD_SHARED_LIBRARY表示编译生成共享库,是编译系统提供的变量,指向一个GNU Makefile脚本,负责收集自从上次调用’include (CLEARVARS)LOCALXXXBUILDSTATICLIBRARYlib(LOCAL_MODULE).a, BUILD_EXECUTABLE 表示生成可执行文件。

b. 生成.so共享库文件

  Andro文件已经编写好了,现在可以用android NDK开发包中的 ndk-build脚本生成对应的.so共享库了,方法如下:

    braincol@ubuntu:~/workspace/android/NDK/hello-jni/jnicd..    braincol@ubuntu: /workspace/android/NDK/hellojni ls
    AndroidManifest.xml assets bin default.properties gen jni libs obj res src
    braincol@ubuntu:~/workspace/android/NDK/hello-jni$ ndk-build
    Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
    Gdbsetup : libs/armeabi/gdb.setup
    Install : libhello-jni.so => libs/armeabi/libhello-jni.so

  可以看到已经正确的生成了libhello-jni.so共享库了, 我们去 libs/armeabi/ 目录下看看:

    braincol@ubuntu:~/workspace/android/NDK/hello-jnicdlibs/    braincol@ubuntu: /workspace/android/NDK/hellojni/libs ls
    armeabi
    braincol@ubuntu:~/workspace/android/NDK/hello-jni/libscdarmeabi/    braincol@ubuntu: /workspace/android/NDK/hellojni/libs/armeabi ls
    gdbserver gdb.setup libhello-jni.so

4)在eclipse重新编译HelloJni工程,生成apk

  eclipse中刷新下HelloJni工程,重新编译生成apk,libhello-jni.so共享库会一起打包在apk文件内。在模拟器中看看运行结果。
参考资料:

http://blog.csdn.net/hhao137/article/details/4304664

http://www.cnblogs.com/hibraincol/archive/2011/05/30/2063847.html

http://yueguc.iteye.com/blog/946724

http://www.cnblogs.com/hibraincol/archive/2011/05/30/2063847.html

小白...

初入软件行业,代码小白一枚...还望各位大牛指点迷津,多谢多谢.
  • taoxiaowu36
  • taoxiaowu36
  • 2016年06月25日 22:25
  • 131

maven小白

maven小白今天花了不少时间成功创建了一个maven项目,期间遇到些问题,搞到现在,头也是晕晕的 下面便将搭建过程分享下, 参照两位的分享,也是加一些自己遇到的问题,自己写了一个分享,可能有些乱...
  • wang725
  • wang725
  • 2015年11月28日 22:38
  • 244

Android之---JNI/NDK开发指南

JNI/NDK开发指南JNI/NDK开发指南
  • u010936731
  • u010936731
  • 2016年12月21日 19:29
  • 286

小白进化论

每个人都是从电脑小白进化来的,不过术业有专攻,禀赋也有不同,所以有的人锤炼成了高手,有的人还是小白,只不过多看了几部片子多玩了几个游戏而已。网上炒股和在线棋牌,吸引了岁数大的;幼齿们则专注聊天和网游。...
  • bigpeon
  • bigpeon
  • 2008年01月14日 13:43
  • 709

android ndk翻译之七:Bionic C 库一览

Bionic C 库一览: 介绍: 核心体系: Bionic设计的核心思想是:尽量简单。 这意味这这个C库只围绕着内核提供轻量级的包装,我们让它尽量小,不去处理一些细枝末页的事情。 ...
  • fyfcauc
  • fyfcauc
  • 2014年09月25日 20:15
  • 705

[Android] 环境配置之Android Studio开发NDK

NDK 开发哪家强?XX XX 找 Blue Fly . 说到 NDK 开发,其实麻烦的是配置。 在这里不用配置Cygwin ,不用额外操作;不使用 Eclipse ;使用最新的 Android St...
  • qiujuer
  • qiujuer
  • 2014年12月21日 12:01
  • 29999

Android studio下增量升级功能的NDK开发

在线升级是每个应用都要考虑的功能,而安卓为了节省流量,更是支持了增量升级这种升级方式,不需要下载整个安装包,只需要下载增量升级包(或者叫补丁),然后与本地的安装包进行合成就可以了。本文的目的就在于对增...
  • winter12071634
  • winter12071634
  • 2016年04月26日 13:29
  • 3253

Android之NDK开发初探

 总的来说ANDROID的NDK远不及其应用开发的SDK完善(虽然经过一番不算复杂的折腾发现NDK用起来很方便),而且它本身也不推荐使用这种做法,至少目前也不将此作为重点。但是某些中间层面系统测试(主...
  • quanben
  • quanben
  • 2010年02月02日 12:57
  • 3734

Android NDK之Lame初探

之前在做车载语音微信项目的时候,基于网页版微信原理,同时新增了一些功能,比如可以发送语音消息,由于微信网页版没有提供这个功能,所以在这里现将录音消息传到讯飞的车载服务服务器,然后获取URL,只发送UR...
  • wjk7186912
  • wjk7186912
  • 2016年09月19日 20:45
  • 985

Android 开发 NDK从入门到精通

NDK详解 1. 交叉编译库文件 C代码执行 : C代码被编译成库文件之后, 才能执行, 库文件分为动态库 和静态库 两种; -- 动态库 : unix环境下.so 后缀的是动态库, ...
  • jdsjlzx
  • jdsjlzx
  • 2014年02月10日 15:58
  • 3641
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android之NDK初探
举报原因:
原因补充:

(最多只允许输入30个字)