Android NDK初探

之前对NDK开发一直是个小白,最近花了几天时间研究得到的一些理解在此做个记录分享。结论不足之处拒绝反驳,所有观点仅单方面宣布,后果自负。*.*,本文出处:http://www.jianshu.com/p/201046751a7c

一、什么是NDK?

NDK全称是Native Development Kit(原生开发工具包),NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。也就是说它是一个“开发工具包”,就像SDK一样,区别就在于SDK是面向java开发者的工具集合,而NDK面向的则是C/C++开发者的工具集合(包括对c/c++源码的打包编译工具ndk,一些h头文件等)。附上官方NDK工具包的下载路径:官网ndk下载,需要翻墙。

二、为什么需要使用NDK?

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

三、JNI、SO介绍

JNI 全称Java Native Interface,这套技术的机制是用于java访问c/c++代码而产生的,说白了NDK开发的核心就是JNI开发,利用java代码来调用遵循JNI规范的c/c++的方法实现某个功能。

so全称Shared Object,本地原生库,先暂时理解为java中的jar包,所有的c/c++的代码在android(Linux)平台中最终都会编译成so库,然后才能被调用。所以ndk开发所编写出的c/c++代码最终的目的都是为了获得这个so库,与java方法形成jni的映射关系从实现调用。

四、开始撸码

本文使用Android Studio2.0进行演示HelloJni

  大概步骤:

     1. java文件中声明native方法,和java方法声明一样,在此基础上加了natvie修饰。
     2. 利用javah命令生成与该类对应的头文件(包含方法信息)
     3. 根据头文件的信息编写c源代码文件
     4. 在app\build.gradle文件中配置ndk的编译信息
     5. 配置NDK工具包路径,编译运行

创建项目:HelloJni

图 1

1. 定义一个java类SayHello,并在里面声明一个静态无参native方法speak,并且创建jni文件夹

图 2

2. 利用javah命令生成与该类对应的jni头文件,生成的头文件的目的主要是用来编写c/c++源文件

图 3

3.根据.h头文件的信息编写c源代码文件 : 创建SayHello.c文件,把头文件里的方法copy到该文件中,并修改成实体方法,下面则是返回一段字符串。如果熟悉了jni方法名称命名规范,完全可自己手写,生成头文件的步骤也可跳过。亲测发现如果包名带有数字的命名规则不好把握,所以建议用javah生成。

图 4

4.在build.gradle中配置ndk的编译信息,配置完成保存同步之后可能出现错误,添加 android.useDeprecatedNdk=true 到gradle.properties 文件中即可解决。

图 5

5.配置下载好的NDK工具包:File->Project Structure->SDK Location(文件路径\android-ndk-r14b目录配置到系统环境变量中,以备后面使用)

图 6

然后回到在java文件中,加载buil.gradle中配置的moduleName的类库名称,这里配置为:SayHello

图 7

最后在MainActivity中测试该方法。

图 8

运行。

图 9


至此,体验了一把基本的ndk开发过程。不过洗脑还没有结束:

在运行完成之后,我们并没有发现工程目录中有so库文件,其实这个so库文件是在运行之后直接打包到了apk文件中的lib目录下了

图 10

由于我们在build.gradle配置了abiFilters打包时只打包x86的文件夹中的so库。所以我们在apk中只看到x86的文件夹,里面存放的就是so库,如果不配置abiFilters,那么将会出现android支持的7种abi,可参见该文章理解ABI。

因为我们可以调用so这个库,显然这个so库是根据我们在jni文件夹下编写的源文件编译生成的,如果我们没有配置,gradle默认就会去编译jni的文件夹下的c/c++的代码生成so库,这个路劲就是src/main/jni,如果这个文件夹没有文件即使配置了ndk{...}信息也不会生成so库,当然gradle还提供自定义配置,下面就看看如何配置:

sourceSets{
  main{
    jin.srcDirs=["src/mian/jni"]  //默认路径,jin.srcDirs指的是需要加入编译的jni的路径,可以自己修改路径的
  }
}
图 11

这个apk安装到x86 abi手机上之后,so库会安装在data\app\包名-数值\ib目录下(可通过Device Monitor工具查看),所以由此可判断System.loadLibrary()加载的库默认是这个路径下的库,也可以调用System.load(data\app\包名-数值\ib\abi\libxx.so)加载绝对路径的so库。

图 12

所以java代码能不能正确的执行so库里的内容取决于so库能否被正确的安装。如果未能正确安装,当虚拟机去System.loadLibrary时就会报错java.lang.UnsatisfiedLinkError

上面的做法只有在打包时才能得到so库,下面就介绍通过ndk开发工具包里的ndk-build单独来编译出so库,这种方式就无需在build.gradle中配置ndk{...}了。

1. 在jni文件家中新建android.mk编译配置文件,参见Android.mk详细配置

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := SayHello
LOCAL_SRC_FILES := SayHello.c

include $(BUILD_SHARED_LIBRARY)

2.在jni文件家中新建application.mk配置需要生成支持的abi so库,参见Application.mk详细配置

APP_CFLAGS += -Wno-error=format-security
APP_ABI := all

这里配置支持所有的abi。

3.在terminal中调用ndk-build工具生成so库

图 13

我们可以看到在main文件夹下生成了libs目录,并且生成了支持所有abi的so库,到此生成so完毕;现在任务就是要让这些so库打包到apk文件中的libs目录下,在build.gradle中配置sourceSets的另一个属性jniLibs.srcDirs,配置的路径下的so库文件都会打包到apk文件中,其默认值为app/libs,所以也可以把这些so文件拷到app/libs中而不配置这个属性用其默认值。

图 14

上图中不配置jni.srcDirs的路径的作用是为了打包时不让编译系统再去编译得到so库(因为我们已经单独生成),虽然上面ndk没有被配置,但是只要的配置这个路径下有c文件就会生成so库,并且名字为libapp.so,这样一来就造成了相同的包存在两个增加app的体积。

最后build apk看看apk里有没有so库:


图 15

运行,大功告成。

下一篇文章介绍:第三方so库的调用

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,279评论 25 707
  • 一、NDK产生的背景 Android平台从诞生起,就已经支持C、C++开发。众所周知,Android的SDK基于J...
    Ten_Minutes阅读 3,467评论 1 27
  • 本人为初学者,文章写得不好,如有错误,请大力怼我 或者看这里 如何使用jni进行开发 本文主要针对Android环...
    AlbertHumbert阅读 4,555评论 2 12
  • Android游戏开发实践(1)之NDK与JNI开发02 承接上篇Android游戏开发实践(1)之NDK与JNI...
    AlphaGL阅读 3,734评论 0 24
  • 若你愿献祭 我会在你的乳上 划一道伤口 轻轻舔起 若你愿献祭 我会在皮鞭和你之间 铺散乌贼的气息 图画现代性的随机...
    主修寂静阅读 209评论 0 0