最近安卓开发里面最火的是什么?NDK开发啊,之前面试的时候好几家公司都问我会不会这个,或者直接就出了这样类型的笔试题,当时的我也是一脸懵逼。恰好这段时间研究了图片压缩和视频压缩的NDK开发,话不多说,开干吧!
以往的图片压缩大家都知道无非是进行图片质量压缩和按比例压缩,但是这样不靠谱啊,压缩严重点直接就趋于马赛克(可能有点夸张)了,好伐。于是libjpeg就登场了,具体为啥,我就不说了,请看上一篇的英文介绍,而且网上一大片相同的原因介绍。今天我主要讲的是生成自己的libjpeg.so库:
一、安装NDK(硬件环境:Win10 x86, 开发工具:Android Studio)
打开android Studio的Project Structure,在Android NDK Location 填入你的NDK路径,比如我的是——D:\Android\sdk\ndk-bundle。如果你的电脑里面没有下载NDK,那应该有个Download的按钮,直接下载最新的NDK即可。
打开环境变量,在系统变量里面新增“NDK_ROOT”,把你的NDK路径填进去,然后保存之后在用户变量为“Path”的变量里面增加“%NDK_ROOT%。
检查NDK是否安装成功,成功的提示如下图:
失败的话就会提示“ndk-build不是内部命令”。
二、编译过程
1、新建一个Android Project,去https://github.com/Dm47021/libjpeg-turbo把libjpeg-turbo下载下来,解压缩后把“libjpeg-turbo-android”的文件名改为“jni”,扔进我们的app目录下,如下图所示:
2、打开cmd,cd到这个jni目录,输入命令“ndk-build”,如下图所示(E:MyJpgCompress\app\jni是我的jni文件路径),本来应该一切顺利地进行,然而你会发现报一大片了,错误如下:
很显然报错的地方在jdcolor-armv7.S,而且我发现几乎每行代码都不被支持。于是我开始查看jni目录下的Android.mk文件,也就是makefile配置文件,帮我们把C/C++的代码编译成动态库so的一个文件。里面的代码表明libjpeg.so库的生成是需要用到libsimd的,也就是下面的这行代码,而且正是这个libsimd的编译需要用到报错的那个文件,这下可怎么办呢?
只好在网上寻求帮助了,好在功夫不负有心人,有人已经在github上把这个图片压缩的一些东西抽离了出来,事情变得简单起来。附上网址:https://github.com/bither/bither-android-lib。
我把这个项目下载了下来,把他用到的libjpeg-turbo-android和我的一对比,果然少了asm文件夹,并且在Android.mk中把
asm/armv7//jdcolor-armv7.S asm/armv7/jdidct-armv7.S \这一行去掉了。干脆把jni下的asm文件夹删除,并且换成他的Android.mk,再ndk-build一下,libjpegbither.so生成了,当然如果你想给这个库换个名称也是可以的,直接在Android.mk中查找“libjpegbither”并全部修改成你要的名称即可,因为这个名称基本都是这样的,而LOCAL_SHARED_LIBRARIES就是指我们要生成一个或多个的静态库。
LOCAL_SHARED_LIBRARIES := libjpegbither
这里为了方便,我就直接在他的项目上进行编译了,这个具体的其实可以根据路径E:\bither-android-lib-master\libjpeg-turbo-android\use-libjpeg-turbo-android\jni下的README.md这个文件进行编译。当然了,既然我说要手把手教,那还是继续下面的图解编译过程。
第一步:进入jni路径下,输入命令行ndk-build进行编译,当然你也可以加上“APP_ABI=armeabi-v7a,armeabi”,这样就可以编译出这个so库的多个版本。
编译完成后在这个项目下的libs文件夹会生成相应的文件夹armeabi和armeabi-v7a,里面分别有一个我们需要的“libjpegbither.so”的文件。
第二步:
把这两个生成的文件夹文件放入“use-libjpeg-turbo-android”的jni文件夹下,cd到这个jni文件夹下,输入ndk-build命令进行编译,不过我运行到这里的时候却报错了,错误如下:
E:\bither-android-lib-master\libjpeg-turbo-android\use-libjpeg-turbo-android\jni>ndk-build APP_ABI=armeabi-v7a,armeabi
[armeabi-v7a] Compile thumb : bitherjni <= bitherlibjni.c
E:/bither-android-lib-master/libjpeg-turbo-android/use-libjpeg-turbo-android//jni/bitherlibjni.c:18:28: fatal error: and
roid/bitmap.h: No such file or directory
#include <android/bitmap.h>
这个该怎么办呢?我查阅了资料后找到了解决方法,请查看网址https://stackoverflow.com/questions/11656833/android-ndk-wont-build-library-because-bitmap-h-is-missing中的解答,最终我通过下面这个命令行编译出了自己想要的so库——libbitherjni.so和libjpegbither.so。
ndk-build APP_PLATFORM=android-8
把生成的so库放进我们需要用到的工程里面,对应新建相关的包名类名和方法名,也就是net.bither.util包下的NativeUtil类中的compressBitmap方法,参数也一定要对应上。
在NativeUtil类中加上下面的引用,然后我们就可以调用相应的图片压缩方法了。
static { System.loadLibrary("bitherjni"); System.loadLibrary("jpegbither"); }
因为是要生成自己的so库,很多时候大家的项目包名甚至图片压缩工具类名都已经是确定的了,不愿意再加上上面这个包名,这时候只需要在第二步的时候,把jni路径下名为“bitherlibjni.c”的文件中代码进行小小的修改,重新编译即可。
在这个文件中请找到如下图的一段代码:
其中net_bither_util就对应着包名net.bither.util,NativeUtil对应着工具类名,compressBitmap对应着方法名,可以根据个人的需要进行修改,比如我的包名是com.sherry.jpegcompress,在ImageUtil工具类中调用方法compressBtp进行图片压缩,那就可以直接把上面这个方法改为com_sherry_jpegcompress_ImageUtil_compressBtp,然后再进行ndk-build的操作。
好的,我的图片压缩生成相关so库的教程到这里就结束了,后续会附上自己图片压缩相关的全部代码和对应打包成功的so库。如果大家图方便可以直接修改上面那个包名和方法名,然后在项目里面使用,不过还是建议大家自己玩一遍。