作者: 朕小猫与GPT4
1 | cmake_minimum_required(VERSION 3.4.1) |
Q: 这样写完之后,apk 安装包中有两个so文件 libDualVectorFoilLib 和 libassimp,都占用 14m,但其实,libDualVectorFoilLib 中包含的就是libassimp,不应该再占用这么大体积
A: 为了减少 APK 中的体积,你可以将 libassimp
静态链接到 DualVectorFoilLib
中,这样只会生成一个包含 assimp
的 libDualVectorFoilLib.so
文件,而不会包含独立的 libassimp.so
文件。这种方式可以避免重复打包和减小 APK 的体积。具体修改如下:
修改 CMakeLists.txt 配置,将 assimp
静态链接
1 | cmake_minimum_required(VERSION 3.4.1) |
解释
**禁用
BUILD_SHARED_LIBS
**:将BUILD_SHARED_LIBS
设置为OFF
,使 Assimp 以静态库(.a
文件)形式生成,这样 Assimp 将不会生成独立的.so
文件,而是将代码直接打包到libDualVectorFoilLib.so
中。**静态链接
assimp
**:在target_link_libraries
中链接assimp
,这会将 Assimp 的代码直接合并进libDualVectorFoilLib.so
,避免生成和打包独立的libassimp.so
。结果:这样可以减小 APK 体积,因为不再包含重复的库文件。
之后重新构建项目,确保 APK 中只包含 libDualVectorFoilLib.so
文件,不再包含 libassimp.so
文件。
Q: 为什么改成静态连接之后小了好多
A: 改成静态链接之后 APK 大小减少,主要原因在于静态链接和动态链接的工作原理不同,以及 Android 应用打包时如何处理库文件:
避免重复加载的冗余文件:动态链接时,
libassimp.so
作为独立的动态库被单独打包,并在运行时加载。而静态链接则将libassimp
的代码直接整合到libDualVectorFoilLib.so
中,避免了多余的.so
文件。因此,只生成一个完整的.so
文件,而不是两个重复的文件,节省了空间。优化与裁剪:静态链接时,链接器会自动去除 Assimp 库中未使用的代码,只保留
DualVectorFoilLib
需要的部分。这意味着生成的libDualVectorFoilLib.so
体积更小,因为一些多余的功能不会被包含进去。而动态链接时,通常整个库都被打包,即使项目不使用 Assimp 的所有功能,APK 也会包含整个库的内容。减少符号表与动态加载信息:动态库需要额外的符号表和动态加载信息,以便在运行时进行地址解析和符号加载。静态链接的
.so
文件则不需要这些额外的信息,因此最终生成的文件会更小。加载性能提升:除了体积减小,静态链接也会带来性能上的提升,因为它省去了动态加载库时的解析步骤,在某些场景下可以略微缩短应用启动时间。
通过静态链接,代码体积优化和去重工作会更加有效,因此可以显著减小 APK 大小。
Q: 如果我只想引入 assimp 不想引入 libDualVectorFoilLib.so 怎么处理
A: 如果只想引入 assimp
库,不需要 libDualVectorFoilLib.so
,可以直接在 CMake 中只构建 assimp
,而不创建其他自定义的 .so
库文件。这样可以实现只生成 libassimp.so
,并确保它在你的 APK 中被正确引用。以下是可以实现的步骤:
直接构建 Assimp 并禁用其他库的生成:
只需要assimp
,无需自定义的库文件,可以移除自定义库的定义,只保留对assimp
的配置与编译。修改 CMakeLists.txt:
1
2
3
4
5
6
7
8
9
10
11
12
13cmake_minimum_required(VERSION 3.4.1)
project(DualVectorFoil)
# 配置 Assimp:禁用测试、样例和文档生成
set(ASSIMP_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(ASSIMP_BUILD_SAMPLES OFF CACHE BOOL "" FORCE)
set(ASSIMP_BUILD_DOCS OFF CACHE BOOL "" FORCE)
# 添加 Assimp 目录并包含头文件
add_subdirectory(${CMAKE_SOURCE_DIR}/Assimp)
include_directories(${CMAKE_SOURCE_DIR}/Assimp/include)
# Assimp 将自动生成 libassimp.so,无需自定义其他库**在
build.gradle
中指定加载libassimp.so
**:
在你的 Android 项目中确保在 Java 或 Kotlin 代码中正确加载libassimp.so
,例如:1
System.loadLibrary("assimp")
**检查并确保只有
libassimp.so
**:
构建 APK 后,检查生成的 APK 文件,确认只有libassimp.so
被打包,而没有libDualVectorFoilLib.so
。
这样配置后,APK 中只会包含 libassimp.so
,并且该库可以直接使用,不再生成不必要的库文件。
Q: So 文件的 Raw File Size 和 Download Size 分别是什么?
A: 在 APK 文件的打包和发布过程中,文件会经历压缩处理,这使得 APK 下载包的体积通常小于安装后在设备上实际占用的空间。在 Android Studio 中,APK Analyzer 工具展示了两个关键指标来帮助我们理解这些差异:
Raw File Size(原始文件大小):这是文件在 APK 解压后,在设备上占用的实际存储空间大小。在您提供的截图中,
libassimpd.so
的原始文件大小为 14.4 MB,表示安装到设备后它会占用 14.4 MB 的空间。Download Size(下载大小):这是 APK 包含的文件在压缩后的大小。由于 APK 打包时会对文件进行压缩,
libassimpd.so
的压缩后下载大小仅为 3.4 MB。这个值表示用户在下载 APK 包时实际需要传输的数据量。
总结来说:
- Raw File Size 是文件在设备上解压后的实际存储空间需求。
- Download Size 是文件在 APK 压缩包中的大小,直接影响 APK 的下载体积。
因此,虽然下载 APK 时 libassimpd.so
只占 3.4 MB,但安装后在设备上会占用 14.4 MB 的存储空间。
Q: So 文件是怎么实现从14M压缩到3.4M的
A: so
文件(共享库文件)的大小可以大幅度缩小,主要是因为 Android APK 打包过程中应用了压缩算法。以下是一些关键原因和过程:
1. ZIP 压缩
APK 文件本质上是一个 ZIP 文件,打包时会对资源文件和库文件应用 ZIP 压缩。共享库文件(so
文件)通常包含大量重复数据和空白区域,这些内容在 ZIP 压缩时能够被有效地缩减。因此,像 libassimpd.so
这种大型的二进制文件,通过 ZIP 压缩可以大幅度减小体积。
2. 二进制格式的高压缩率
so
文件是二进制格式,包含大量的结构化数据和代码段。这些二进制数据在结构上非常紧密,包含许多重复的模式和数据块,非常适合被压缩算法处理。常用的压缩算法(例如 DEFLATE)能够识别这些模式,减少冗余,从而将文件压缩到较小的尺寸。
3. 去除无用数据
一些调试信息和符号信息在生成 so
文件时可能会被包含在内,但是在发布 APK 时通常会将这些调试符号信息剥离。这会进一步减少 so
文件的体积,尤其在压缩之后,对这些无用数据的移除效果显著。
4. 压缩前未使用的代码和数据区域
so
文件可能包含一些预留的数据段或对齐填充,这些部分在压缩后也会被进一步缩小。比如对齐填充区域在压缩时几乎不会占用空间,从而进一步减小了整体体积。
示例总结
在您的示例中,libassimpd.so
原始文件大小为 14.4 MB,而在 APK 中压缩后的下载大小是 3.4 MB。这种大幅缩小主要得益于 ZIP 压缩的高效性,以及 so
文件的二进制结构带来的高压缩比。
总结
APK 中的 so
文件能够实现从 14 MB 压缩到 3.4 MB,主要是由于以下原因:
- ZIP 压缩算法的高效性
- 二进制文件的结构适合压缩
- 发布时剥离调试符号信息
- 未使用的数据和对齐填充在压缩后基本不占空间
这些因素共同作用,使得 so
文件在安装包中的大小远小于其解压后的原始大小。