安卓集成7z极限压缩

2,211 阅读4分钟
原文链接: mp.weixin.qq.com

为什么使用7z压缩?

7z官方源码:https://sourceforge.net/projects/p7zip/files/  7z和其他压缩库相比拥有最大的压缩率,占用的磁盘空间最小,所以传输占用的带宽也就最小。

7z、7zr和7za的关系

官方的解析是这样子的:考研英文能力的时候来了

  1. 7z uses plugins to handle archives.

  2. 7za is a stand-alone executable that handles fewer archive formats than 7z.

  3. 7zr is a stand-alone executable.It is a "light-version" of 7za that only handles 7z archives.In contrast to 7za, it cannot handle encrypted archives.

如何使用

有两种方式,一种是编译成可执行文件,放在assets目录中打包,  应用启动的时候将assets中的可执行文件拷贝到应用私有目录/data/data/包名下,  然后通过Runtime.getRuntime().exec()运行可执行文件。 还有一种就是编译成静态库或动态库通过jni的方式调用。

可执行文件的方式

值得注意的是:这在Android中并不是官方推荐的。但这种方式在某些不需要干涉过程的处理需求中是最方便的。美酒虽好,但不要贪杯哦!!!从 Android 4.1(API 级别 16)开始,Android 的动态链接器支持位置独立的可执行文件 (PIE)。 从 Android 5.0(API 级别 21)开始,可执行文件需要 PIE。要使用 PIE 构建可执行文件,  请设置 -fPIE 标志。此标志增大了通过随机化代码位置来利用内存损坏缺陷的难度。 默认情况下,如果项目针对 android-16 或更高版本,ndk-build 会自动将此值设置为 true。 当然您可以手动将其设置为 true 或 false。此标志仅适用于可执行文件。7z库很贴心,NDK所需的mk文件都给我们写好了,我们只需要跑ndk-build命令即可,这点必须点赞 (当然,你需要配置好你的NDK环境)首先,我们cd进去7z源码目录的CPP/CPP\ANDROID\7zr\jni下,mk文件默认的是编译可执行文件,我们直接 ndk-build跑起来…编译成功后是这样子的:

在jni的同级目录下生成了一个libs目录,里面就是我们所需的执行文件。我们拷贝到assets目录中打包,应用启动的时候拷贝到应用私有目录/data/data/包名下,然后通过Runtime.getRuntime().exec()执行命令行即可。

动态库/静态库方式

要编译动态库或者静态库,我们需要修改一下Android.mk文件:在文件的最后,注释掉这两句

#LOCAL_CFLAGS += -fPIE  #LOCAL_LDFLAGS += -fPIE -pie

然后将include $(BUILD_EXECUTABLE)修改为 include $(BUILD_STATIC_LIBRARY)或者include $(BUILD_SHARED_LIBRARY),这取决于你要编译成静态库还是动态库。这里以静态库为例,最终文件如下:

# Needed since ANDROID 5, these programs run on android-16 (Android 4.1+)# pie是给可执行程序使用的flag# ndk读取mk文件编译动态库不需要指定pie# LOCAL_CFLAGS += -fPIE# LOCAL_LDFLAGS += -fPIE -pie# 生成可执行文件#include $(BUILD_EXECUTABLE)# 生成动态库include $(BUILD_SHARED_LIBRARY)# 生成静态库# include $(BUILD_STATIC_LIBRARY)

跑一下ndk-build,编译成功后是这样子的,so文件同样在libs目录下。

开始ndk集成

  1. 将编译出来的lib7zr.so拷贝到项目/main/jniLibs目录下。

  2. 然后在cpp目录下创建lib7zr目录,将7z源码目录中的 C目录和CPP目录拷贝到项目的 lib7zr目录下.

  3. 编辑CMakeLists.txt:这里有一个问题,我们要使用编译出来的so库,怎么知道需要哪些头文件呢?这里有一个方法就是查看Android.mkLOCAL_CFLAGS所有-I指定的目录就是所需的头文件。

#根据Android.mk引入头文件#设置头文件查找目录include_directories(        lib7zr/CPP/7zip/Archive        lib7zr/CPP/7zip/Archive/7z        lib7zr/CPP/7zip/Archive/BZip2        lib7zr/CPP/7zip/Archive/Common        lib7zr/CPP/7zip/Archive/GZip        lib7zr/CPP/7zip/Archive/Cab        lib7zr/CPP/7zip/Archive/Lzma        lib7zr/CPP/7zip/Archive/Tar        lib7zr/CPP/7zip/Archive/Zip        lib7zr/CPP/7zip/Archive/Split        lib7zr/CPP/7zip/Archive/Z        lib7zr/CPP/7zip/Compress        lib7zr/CPP/7zip/Crypto        lib7zr/CPP/7zip/UI/Console        lib7zr/CPP/7zip/UI/Common        lib7zr/CPP/Windows        lib7zr/CPP/Common        lib7zr/CPP/7zip/Common        lib7zr/C        lib7zr/CPP/myWindows        lib7zr/CPP        lib7zr/CPP/include_windows)

然后设置查找库的路径:

#Android 6.0以后使用这种方式,设置库查找目录set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")

安卓6.0以前,我们可能会用以下这种方式链接动态库,但是6.0之后动态库可能不行了,静态库库可以

#6.0及以后 动态库不行,静态库可以#add_library(#        7zr#        SHARED#        IMPORTED#)#set_target_properties()

然后就是NDK层编码实现:主要是

a、声明main函数 b、解析指令 c、调用main函数(int MY_CDECL main)

遇到的问题

1.尝试使用最新版本的NDK编译,但是编译不通过,demo中的库是使用ndkr14编译通过的;2.尝试编译7z,但是在安卓中运行命令行的时候报错,时间问题没有查找原因,7zr是可以的。

gitHub Demo 7z极限压缩:https://github.com/feiflyer/growing