您的位置:首页 > 移动开发 > Android开发

Android NDK开发使用以及so文件生成和注意事项

2017-12-26 15:02 309 查看
Android NDK开发使用以及so文件生成和注意事项

1. NDK以及.so文件简介

本文主要是介绍在Androidstudio中结合NDK开发需要注意的事项以及一些比较重要的知识点,众所周知,so文件在Android的开发中起到很重要的作用,无论是在与底层设备调用还是一些第三方的SDK调用都经常使用到,可以看出so文件的重要性,在Android中NDK就是Android用于编译so文件的一套工具, 提到NDK就很容易联想到SDK,那么我们简单对两种名词进行一下解释区分,AndroidSDK(AndroidSoftware Development kit)就是 Android软件开发工具包,使用Java代码开发Android就必须要使用SDK,对于SDK不需要过多的解释,而NDK跟SDK名词上解释差不多NDK(NativeDevelopment kit)只是加了一个原生开发工具包,用它开发C/C++是很方便的,他有一个强大的编译集合,Java调C/C++,它会把C代码编译成一个so的动态库,通过jni接口用Java代码区调用它,有了它我们可以直接在Android代码中添加C代码。

使用NDK开发的好处,或者说使用so包的好处主要有以下几种情况:

1. 代码的保护,由于apk的Java层代码很容易被反编译,但是C/C++库反编译的难度就比较大。

2. 在NDK中调用第三方的C/C++库,因为大部分的开源库都是C/C++代码编写的。

3. 便于移植,用C/C++写的库可以方便的在其他的嵌入式平台上再次使用,跨平台性比较强。

4. 在使用过程中发现如果将客户端的敏感信息存储在so文件中将极大的提高安全性,即使APK被反编译也很难将so进行破译。

在使用so文件时我们先了解一下so文件在AndroidStudio 中的使用架构以及一些基本概念,只有理解了这些才能在使用时知道他的大体的流程以及排查问题时能快速定位。

2.ABI的基本概念

早期的Android系统几乎只支持ARMv5的CPU架构,而发展到现在,Android系统现在已经可以支持7种不同的CPU架构,如下图所示:



图1.Android系统CPU架构图

每一种架构关联着一种ABI,那么什么是ABI呢,ABI是ApplicationBinary Interface的缩写,即应用程序二进制接口,定义了二进制文件(Android平台上专指so文件)如何运行在相应的系统平台上,包括使用的指令集,内存对其到可用的系统函数库,在Android系统上,每一个CPU架构对应一个ABI,上面介绍到Android系统的7中架构,那么对应的Android工程中的七种ABI就是:



图2.Android工程ABI目录

在当前手机硬件更新换代频繁的时代,目前很多设备支持多于一种的ABI。比如ARM64和x86设备也可以同时运行在armeabi-v7a和armeabi的二进制包也就是so文件,但最好还是针对特定平台提供相应平台的so文件,因为如果不是当前平台的so文件,在运行时就会生成一个模拟层比如x86设备上模拟arm的虚拟层,这样性能肯定是会稍微差一些的。我们在使用so文件时不需要自己判断设备是哪一种架构然后进行调用,Android包管理器会在你安装APK的时候自动选择APK包中对应系统ABI的so文件。

3引入预编译的二进制C/C++函数库(so文件)

介绍完ABI的目录结构以及组成,接下来我们就进入项目中,首先我们需要知道怎么使用so文件,添加so文件很简单,默认情况下,Androidstudio会到jniLibs目录中查找并拷贝上所有的二进制库(so文件),假设我们在上面每一个ABI目录中都有一个名为libBls.so的二进制库,在Android中要使用这个库很简单。

首先导入:



图3.导入so文件位置

然后在Java代码中写到:



图4.java代码中引用so

这里添加的位置默认是放在jniLib/ABI目录下,也可以自己指定,只需要在build.gradle中设置:



图5.build.gradle中设置.so位置

使用时需要注意的是使用NDK编译名为jary的静态库时,生成的静态库文件名为libjary.so,因此,在Java中使用loadLibrary加载libjary.so这个库时,需要把头部的lib以及尾部的后缀.so去掉。

4 AS生成编译二进制C/C++函数库(.so文件)

引入so文件操作十分简单,但是如果自己生成so的文件的话就需要使用到Android进阶知识中的NDK开发,限于篇幅原因我们只对其进行简单的流程描述以及将传统的NDK开发流程与Androidstudio2.2之后的方式进行对比。

4.1两种NDK目录比较

这是普通传统的NDK目录,在8700项目中有一个车牌识别的功能使用的就是传统的方式,与cMake相比效果一样,但是流程会复杂一些需要生成很多的.h,.mk,.cpp文件:

;



图6.传统方式使用NDK

这是Androidstudio 2.2以后的最新的cMake方式:


图7.cMake方式使用NDK

4.2cMake方式搭建NDK

可以看到结构上是有区别的;我们直接按照步骤搭建起来:

首先需要下载如下图的工具:



图8.Androidstudio工程下载NDK工具

在创建项目的时候记得将此处打上勾,其他地方默认就行:



图9.创建项目时勾选项

现在我们想要做一个so包这个so包里面存放的是我们的敏感信息微信的AppId,我们将获取他的方法写到so文件中,那么即使我们的APK被别人反编译,也很难破解我们的C/C++代码中的敏感信息

我们在cpp文件夹下面的native-lib.cpp文件中写C/C++代码,如同所示:



图10.cpp文件中C/C++代码

App项目中调用这段C/C++的代码位置为:



图11.App项目中java代码

之后我们重新编译项目在build->cMake->debug->obj下面各个目录的下的so文件拷贝出来就可以了之后放到项目libs中就可以直接使用so文件了。

我们运行项目可以看见效果图:



图12.App演示效果图

到此为止一个完整的so文件生成过程已经介绍完成,利用so文件我们不仅可以使用C/C++文件与系统层或者底层硬件之间打交道,我们还可以利用so文件的破译难度大的优点将我们apk中敏感信息放在其中,安全性比市面上的放在string文件夹或者放在buildConfig等等安全性更高。

5使用.so文件的注意事项

处理.so文件时有一个重要的规定,那就是如果可以的话尽可能的提供为每一个ABI优化过的so文件,要么全部支持,要么全部都不支持,最好不要混合着使用,而应该为每个ABI目录提供对应的so文件。

当一个应用安装在设备上是,只有该设备支持的CPU架构对应的so文件会被安装,在x86设备上,libs/x86目录中如果存在so文件的话,会被安装,如果不存在,则会选择armeabi-v7a中的so文件,如果也不存在的话,则选择armeabi目录中的so文件(因为x86设备也支持armeabi-v7a和armeabi)。

使用.so文件的时候有一些需要注意的事项如下:

5.1使用高平台版本编译的so文件运行在低版本的设备上

使用NDK时,很多人都会喜欢使用最新的编译平台,但这样是会容易出现兼容问题,因为NDK平台是向上兼容的而不是向下兼容的,所以我们使用最好使用App的最小的SDK版本号minSdkVersion对应的编译平台,因此我们使用so文件时需要检测他被编译所用的平台版本号。

5.2混合使用不同的C++运行时编译的so文件

so文件可以依赖与不同的C++运行时,静态编译或者动态加载,混合使用不同版本的C++运行时可能导致很多奇怪的问题,所以在只有一个so文件时,静态编译C++运行时是没有问题的,但存在多个so文件时,应该是让所有的so文件都动态链接相同的C++运行时。

5.3没有为每个支持的CPU架构提供对应的.so文件

现在很多android第三方SDK是以aar形式提供的,甚至是远程aar,如果这个SDK对abi的支持比较全,可能会包含armeabi,armeabi-v7a,x86, arm64-v8a,x86_64五种abi,而你应用的其它so只支持armeabi,armeabi-v7a,x86三种,直接引用SDK的aar,会自动编译出支持5种abi的包。但是应用的其它so缺少对其它两种abi的支持,那么如果应用运行于arm64-v8a,x86_64为首选abi的设备上时,就会CRASH,所以这就是我们开始说的要么全部支持要么就全部不支持不要混合使用,比如微信就是一个armeabi文件夹。

在遇到这种问题时我们可以使用build.gradle进行全部设置。



图13.build.gradle设置ABI输出类型

5.4将.so文件放在错误的地方

我们有时候很容易对so文件应该放在那里而疑惑,下面是一个总结

1. AndroidStudio工程一般是放在jniLib/ABI目录下也可以通过在build.gradle文件中设置jniLibs.srcDir属性自己指定

2. Eclipse工程放在libs/ABI目录中这也是ndk-build命令默认生成的so文件的目录

3. AAR压缩包中位于jni/ABI目录中so文件会自动包含到引用AAR压缩包的APK中。

4.通过PackageManager安装后,在小于Android5.0的系统中,so文件位于App的nativeLibraryPath目录中;在大于等于Android5.0的系统中,so文件位于App的nativeLibraryRootDir/CPU_ARCH中 。

5.5只提供armeabi架构的.so文件而忽略其他他的ABIs的

所有的x86/x86_64/armeabi-v7a/arm64-v8a设备都支持armeabi架构的so文件,因此似乎移除其他ABIs的so文件时一个减少APK大小的好技巧,但事实上并不是这样的因为这会印象到函数库的性能和兼容性,x86设备能够很好的运行ARM类型函数库但也并不是说能百分百的不发生crash,特别是对旧设备。64未设备能够运行32位的函数库,但是以32位模式运行在64位平台上时,这是运行的32位版本的ART和Android组件,将丢失专为64位优化过的性能,所以能够支持的话最好还是支持各种so文件不要为了减少APK大小而删除应该的so文件。

NDK以及 so文件使用总结

基于C/C++代码的移植性强的原因以及很多开源项目都是以C/C++代码编写,我们如果需要使用这些项目就会涉及到NDK的开发,所以我们作为Android开发在平时项目中经常会使用到.so文件,因为是直接引用所以一般很少关注它的实现原理,以及实现步骤,这样在遇到.so包相关Crash时才能准备的定位以及解决问题,

.so的使用也为我们将客户端敏感信息隐藏提供了一种更好的办法,对于目前敏感信息加密主要的策略一般有将敏感信息嵌套在strings.xml文件中,以及隐藏在Java源代码中以及BuildConfig中,这几种只要反编译都是可以比较容易的拿到信息,要么就是使用第三方工具DexGuard,但是这个是收费的,以及APK加固也是可以增加反编译难度,还有的会使用加密的方式,最简单的方式就是使用Base64对字符串进行编码,然后将编码后的字符串和另外一串密钥进行异或操作,从而得到加密后的字符串,但是这个用于异或的密钥怎么存放,存放在哪里等于是又回到了先有鸡还是先有蛋的问题了。以上就是对NDK以及.so文件使用的方式以及注意事项的总结,主要帮助理解和解决经常因为.so问题引起的问题的排查。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐