为什么使用7z压缩?
7z官方源码:https://sourceforge.net/projects/p7zip/files/ 7z和其他压缩库相比拥有最大的压缩率,占用的磁盘空间最小,所以传输占用的带宽也就最小。
7z、7zr和7za的关系
官方的解析是这样子的:考研英文能力的时候来了
7z uses plugins to handle archives.
7za is a stand-alone executable that handles fewer archive formats than 7z.
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跑起来…编译成功后是这样子的:
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集成
-
将编译出来的lib7zr.so拷贝到项目
/main/jniLibs目录下。 -
然后在cpp目录下创建
lib7zr目录,将7z源码目录中的C目录和CPP目录拷贝到项目的lib7zr目录下. -
编辑CMakeLists.txt:这里有一个问题,我们要使用编译出来的so库,怎么知道需要哪些头文件呢?这里有一个方法就是查看
Android.mk的LOCAL_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是可以的。