Android NDK初体验(上)

以前学了一点NDK相关的知识,这篇文章主要总结回顾一下。NDK是一种帮助我们开发C/C++代码的工具,NDK的开发包里包含很多交叉编译的工具。一般情况下我们开发Android应用,只需要用到Java代码,调用Android API即可,因此NDK在我们应用开发中很少接触,下面从几个方面详细介绍一下NDK。

一、NDK使用场景

NDK到底在什么情况下使用呢?一般用于以下三种情形:

  1. 提高效率:C/C++编写的代码较Java编写的代码效率高,例如需要对大量数据进行排序时
  2. 使用现有第三方C/C++库:大部分开源库都是用C/C++编写的,例如:人脸识别、音视频处理开源库、图形图像处理开源库,如OpenCV等。
  3. 底层程序设计,便于移植:用C/C++代码编写的库可以方便地在其他嵌入式平台上再次使用。例如想开发一个在Android和IOS平台都能使用的库,就需要用到C/C++来编写。

二、什么是交叉编译

一般我们编写的程序很容易就在电脑上编译执行,这是因为我们的电脑的内存及CPU都能提供充足的空间和处理能力,但是在一般的嵌入式设备中开发就没那么简单了。由于嵌入式设备只有有限的空间和处理资源,因此很多情况下我们无法在嵌入式设备上编译程序,由此就有了交叉编译的概念。
  交叉编译就是在一个平台上生成另一个平台上可执行的代码,例如我们的电脑是X86平台,手机是arm平台,那么我们可以在电脑的x86平台上编译出来我们的应用程序,安装到我们手机的arm平台来运行,ndk开发包中就提供了这样的交叉编译工具。

三、什么是JNI

JNI(Java Native Interface,本地调用)提供了若干的API实现了Java和其他语言的通信(主要是C&C++),JNI标准已经成为了Java平台的一部分。
JNI的实现流程如下:

四、什么是链接库

“库”是成熟的、可复用的代码,我们可以将“库”理解为一个文件,这个文件可以在编译时由编译器直接链接到可执行程序中,也可以在运行时由操作系统的runtime enviroment根据需要动态加载到内存中。
  很多时候我们程序员写代码都会依赖很多底层的的存在不仅节约了很多时间,也保证了我们开发的稳定性,很多时候我们没有那么多的精力和能力来将所有的代码从头开始写,因此库的存在是很有意义的。
  本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
  库有两种:静态库(.a、*.lib)和动态库(.so、.dll)。windows上对应的是.lib和.dll。linux上对应的是.a和.so。
  我们知道,将一个程序编译成可执行程序有如下几个步骤:


  所谓静态、动态是指链接。静态库与动态库的区别在于链接阶段如何处理库:

  • 静态链接库:将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。它的特点是体积大、可移植性好,对库的链接是编译时完成的。
  • 动态链接库:在编译时只编译自己的资源,运行时动态查找所需资源。它的特点是体积小、可共享,但可能出现所需文件找不到的情况。

五、动手试试吧

首先下载ndk开发包,可以去官网上下载相应的版本:下载地址,下载好以后配置环境,这里就不赘述了。

1.eclipse下ndk的使用##

以前用NDK都是在eclipse下,主要有以下个步骤:
(1)新建Android项目,在MainActivity中添加native方法,例如:

public static native String getStringFromC();

(2)在项目工程下创建jni目录,并借助javah命令生成C头文件到jni目录下,在cmd中敲如下指令即可生成对应头文件:


生成的头文件可以看见其中与native函数有关的函数定义:

/*
 * Class:     com_example_hellondk_MainActivity
 * Method:    getStringFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_hellondk_MainActivity_getStringFromC
  (JNIEnv *, jclass);

(3)在jni目录下写.c文件来写具体的实现代码,并在该C文件中引入(2)中生成的头文件

#include<stdio.h>
#include<stdlib.h>
#include "com_example_hellondk_MainActivity.h"//引入(2)中生成的头文件
JNIEXPORT jstring JNICALL Java_com_example_hellondk_MainActivity_getStringFromC
  (JNIEnv * env, jclass jclass){ // 函数的具体实现
    return(*env)->NewStringUTF(env,"Get Hello string from C!");
}

(4)在jni下创建Android.mk文件,指定编译哪个C文件

LOCAL_MODULE  : = hello
LOCAL_SRC_FILES  : = hello.c

(5)执行ndk-build命令,生成obj目录并生成libhello.so(在obj目录下)
(6)在MainActivity中写静态代码块:

static{
       System.loadLibrary("hello");//导入生成的库libhello.so
}

最终我们的MainActivity.java如下,调用名为“hello”的动态库里的函数getStringFromC(),获得其返回字符串显示在页面的TextView中:



最后我们运行一下我们的应用程序可以看到,我们的java层成功地调用了我们的动态库中的获取字符串函数并将我们设置的字符串显示了出来。


:我们可以编译不同平台的.so文件,通过在jni目录下建立Application.mk文件来控制。
当Application.mk文件中加入:APP_ABI := all时,生成所有四个版本的so文件,如下图所示。

若只想生成arm平台下的so文件,可将Application.mk文件中APP_ABI := all注释,如下图:


2.Android Studio下ndk的使用##

用AndroidStudio也来试试吧!我使用的Android Studio版本是1.5,gradle版本是2.8
(1)首先新建一个工程,配置好NDK路径:File->Project Structure


这样设置ndk路径的效果跟在工程的local.properties中添加如下配置语句是一样的,这样设置成功后会自动在该文件下生成这句配置语句。

ndk.dir=E\:\\androidStudio\\android-ndk-r13

(2)在app模块的build.gradle文件中配置ndk相关信息,如下图,此处配置了生成的库的名字,也可以在这里进行更多的配置,比如编译平台的选择、log功能的配置等等。



(3)在工程目录下的 gradl.properties 文件里加上android.useDeprecatedNdk=true


(4)与在eclipse下的MainActivity代码一样,调用native的getHelloStringFromC()方法,这时候这个方法会报错,因为还没有与这个方法对应的本地方法


解决办法很简单,在app>src>main目录下新建jni目录


在报错的本地方法调用函数上按Alt+Enter,便会在jni目录下自动生成对应的.c文件



修改hello.c中的代码即可,所有的都是自动生成的,是不是很方便?
若想生成对应的头文件,也很简单,借助javah命令,在Terminal中输入如下语句即可:

javah -d [生成头文件的存放路径] -jni [调用对应native方法的源文件路径]

3.ndk的使用小结##

从上面eclipse和Android Studio的使用可以看出,二者原理上并无差别,只是Android Studio的自动化程度更高,用起来更加方便,但是目前对NDK的支持仍处于试验阶段,可能不同版本的使用过程中会出现这样或者那样的错误。工具只是一种辅助,自己可以根据自己的使用习惯选择合适的工具。有关NDK使用的进阶学习可以查看我的另一篇博客:Anroid NDK初体验(下)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容