渲染包体积概述:APK里到底藏着什么?

做渲染优化前,我们得先搞清楚一个事儿——APK 包里的“渲染资源”究竟长什么样。说白了,APK 就是一个 zip 压缩包,解压后能看到一堆文件夹和二进制文件。但哪些文件跟渲染沾边?它们又占了多少体积?这就是这章要聊的核心。

APK 结构速览

一个典型 APK 的内部大致长这样:

APK.zip
├── classes.dex          (Java/Kotlin 代码)
├── resources.arsc       (资源索引表)
├── AndroidManifest.xml  (清单文件)
├── res/                 (打包后的资源,如布局、图片)
│   ├── drawable-xxhdpi/ (位图纹理)
│   ├── raw/             (原始文件,如 .glb、.spv)
│   └── ...
├── assets/              (游戏资源常用目录)
│   ├── models/          (Mesh 文件)
│   ├── textures/        (纹理贴图)
│   ├── shaders/         (着色器代码或二进制)
│   └── ...
├── lib/                 (原生库)
│   ├── arm64-v8a/
│   │   └── librendering.so
│   └── ...
├── META-INF/            (签名信息)
└── manifest

关键点:游戏或渲染密集型应用,体积大头往往在 assets/ 和 lib/ 里。我自己分析过几个 Unity 项目,assets/ 下面的纹理和 Mesh 经常占到 APK 总大小的 50%~70%。

渲染资源的三大“吞体积”大户

渲染资源可不是铁板一块,它们分三类,每一类的体积特征完全不同。咱们一个个说。

1. Shader(着色器)—— 小而精,但花样多

Shader 本质是 GPU 上运行的代码片段。比如 Vertex Shader、Fragment Shader,如果你用 Vulkan/OpenGL,它们可能是 GLSL 源码,或者编译后的 SPIR-V 二进制。单个 shader 文件很小,几 KB 到几十 KB。但为什么最后能膨胀?

  • 变体爆炸:Unity 里一个材质可能触发几十个 shader 变体(keyword 组合),全打包进去体积就上来了。
  • 多后端冗余:一个 .glsl 文件 + 对应 .spv 文件同时保留,双倍体积。
  • 注入库:很多引擎把 shader 编译成 .so 库代码,混在 lib/ 目录里。

我建议:用 AGP 的 shaderCompression 选项或者 Unity 的 Strip Engine Code 可以大幅削减 shader 体积。我曾经碰到过一个项目,shader 变体从 3000 个压到 400 个,APK 直接瘦了 15 MB。

2. Mesh(网格)—— 顶点数据堆出来的

Mesh 就是模型的“骨架”,由顶点位置、法线、UV、切线等缓冲区组成。数据格式一般是 float16 或 float32,未经压缩时很吃空间。一个高精度角色模型可能有 10 万个顶点,每个顶点按 (位置3 + 法线3 + UV2) 共 8 个 float,就是 32 字节,总共 3.2 MB。十几个角色加上场景,几十 MB 就出去了。

  • 引擎常用 Draco 压缩 或 meshoptimizer 来减体积,压缩率可达 50%~80%。
  • AGP 里可以配置 aaptOptions.cruncherEnabled 和 android.enableDexingArtifactTransform 间接影响 Mesh 的打包方式。

避坑提醒:我过去把 Draco 压缩开到最大解压时间暴增,导致手机上加载场景卡好几秒。后来改成默认压缩比,体积只多了 10%,加载流畅多了。不要只盯着体积,性能也要平衡。

3. Texture(纹理)—— 的主角

纹理往往是 APK 里最“重”的东西。一张 2048×2048 的 RGBA 未压缩纹理 = 16 MB!现代游戏项目动不动几百张贴图,如果不加处理,光纹理就能撑爆应用商店的 150 MB 限制。

常见的体积优化手段:

  1. 选择压缩格式:ASTC(Android 10+)、ETC2、BC7 等。比如 ASTC 8×8 能将 RGBA 压缩到 0.5 bpp,20 倍压缩比。
  2. Mipmap:会增加约 1/3 体积,但能提升渲染质量和性能。
  3. 尺寸降级:没必要用 4K 贴图的地方,降成 2K 或 1K。
  4. 基础纹理 + 法线贴图分离:法线贴图可以用 DXT5nm 等专用格式。
资源类型 典型单文件体积 常见压缩后体积 在渲染资源中的占比(常见)
Shader 1 KB – 100 KB 0.5 KB – 50 KB 1% – 5%
Mesh 100 KB – 10 MB 30 KB – 3 MB 10% – 30%
Texture 1 MB – 32 MB 0.3 MB – 8 MB 60% – 85%

你看表格最后一列,纹理占了渲染资源的六到八成。所以当你盯着 APK 体积发愁时,第一时间应该去查纹理。

渲染资源在 APK 里的分布占比

我说一个实际案例。以前接手过一个 RPG 项目,APK 总共 180 MB,拆开看:

  • 代码+库:35 MB(19%)
  • 纹理:110 MB(61%)
  • Mesh:28 MB(16%)
  • Shader:7 MB(4%)

纹理占了大头,这很正常。但你知道吗?这里面有 30 MB 是没被引用的“废弃纹理”,因为版本迭代时美术上传了旧资源,构建脚本又没清理。我后来加了 AGP 的 shrinkResources true 和 lint 检查,直接砍掉 30 MB。

核心结论:APK 体积优化 ≈ 纹理优化 + 网格压缩 + Shader 瘦身。其中纹理优化效果最猛,但 Mesh 和 Shader 的“变体膨胀”容易被忽略。

APK 结构与渲染资源组成 APK 文件 其他资源 渲染资源 Shader 变体、编译产物 Mesh 顶点、索引缓冲区 Texture 压缩格式、mipmap 渲染资源典型体积占比 纹理 60%~85% | Mesh 10%~30% | Shader 1%~5% 常见陷阱 废弃资源未清理 | shader变体爆炸

这张图帮你理清 APK 里渲染资源的位置和分类。后面几章我们会逐个击破:Shader 的 AGP 构建配置、Mesh 的压缩策略、Texture 的格式选择。但今天你只需要记住——APK 瘦身第一步,去 assets/ 和 res/ 里翻翻纹理和 Mesh。