Appearance
包体优化
包体大小主要由什么组成?
Unity 游戏的包体不是只有代码,真正的大头通常是 资源。面试里可以这样答:包体主要由 引擎运行时、代码产物、游戏资源、Shader、第三方插件 SDK、平台相关文件 组成。
1. Unity 引擎运行时
比如 UnityPlayer、底层运行库、平台适配库。 这是 Unity 程序能跑起来的基础,哪怕你项目很小,也会有一部分固定大小。
如果是 IL2CPP,还会有 native 代码相关产物。
2. 代码产物
包括:
- C# 编译后的程序集
- IL2CPP 生成的 C++ 和 native 库
- 第三方代码库
- Lua、配置解析代码、热更框架代码
一般来说,代码不是包体最大头,但如果插件很多,体积也会明显上去。
3. 游戏资源
这是最容易变大的部分,包括:
- 贴图
- UI 图集
- 模型 Mesh
- 动画 AnimationClip
- 音频 AudioClip
- 视频
- 字体
- 场景
- Prefab
- 材质
面试要重点说:贴图、音频、视频、模型通常是包体优化优先级最高的几类资源。
4. Shader 和 Shader Variant
Shader 本身可能不大,但 Shader Variant 很容易膨胀。
比如一个 Shader 支持:
- 是否开阴影
- 是否开雾效
- 是否开法线贴图
- 是否开光照
- 不同平台关键字
组合起来 Variant 数量会爆炸,导致包体变大,加载也变慢。
5. 第三方插件和 SDK
比如:
- 广告 SDK
- 登录 SDK
- 支付 SDK
- 统计 SDK
- 推送 SDK
- 崩溃收集 SDK
移动端还要注意不同 CPU 架构,比如 arm64-v8a、armeabi-v7a。如果架构库都打进去,包体会变大。
6. 平台文件和调试信息
比如 Android 的:
AndroidManifest- native so 库
- 资源表
- keystore 相关配置
- 符号文件
正式包里一般不要带多余调试信息、Development Build、未裁剪符号文件。
面试高分回答
NOTE
包体大小主要由引擎运行时、代码产物、资源文件、Shader 变体、第三方 SDK 和平台相关文件组成。Unity 项目里资源通常是最大头,尤其是贴图、音频、模型、动画和视频。优化时我不会凭感觉删资源,而是先看 Build Report 或 Build Analyzer,找出占用最大的资源类型,再做贴图压缩、音频压缩、Shader Variant 裁剪、资源去重、Addressables 拆包,以及首包和热更包拆分。
Texture 压缩格式怎么选?
Texture 压缩格式的选择,本质是在 平台兼容、显示质量、显存占用、带宽、包体大小 之间做平衡。面试里不要只背格式名,要说出“为什么这么选”。
优先看平台
不同平台 GPU 支持的纹理压缩格式不一样。
移动端现在通常优先考虑:
- Android:
ASTC优先,兼容方案可用ETC2 - iOS:现代设备优先
ASTC,老设备可能考虑PVRTC - PC:常用
DXT/BC系列,比如DXT1、DXT5、BC7
简单记法:移动端优先 ASTC,Android 兼容 ETC2,PC 用 BC/DXT。
再看有没有透明通道
如果图片不需要透明,就不要用带 Alpha 的格式,因为 Alpha 会增加体积和内存。
常见选择:
- 不透明贴图:选 RGB 格式
- 透明贴图:选 RGBA 格式
- ETC1:不支持 Alpha
- ETC2 RGBA:支持 Alpha
- ASTC:支持 RGB/RGBA,移动端很常用
- DXT1:适合无 Alpha 或 1-bit Alpha
- DXT5:适合完整 Alpha
比如 UI 图标有透明边缘,就不能随便用不支持 Alpha 的格式。
ASTC 怎么选?
ASTC 的特点是可以选择不同 block size。
常见理解:
ASTC 4x4:质量高,体积较大ASTC 6x6:比较常用,质量和体积平衡ASTC 8x8:更省空间,但画质会下降ASTC 10x10 / 12x12:更小,但容易糊,适合不重要的远景或低频纹理
面试可以说:主角、UI、重要特效可以用更高质量,场景远景、低频纹理可以用更高压缩率。
不同资源怎么选
UI、文字、图标: 优先保证清晰度,压缩太狠会出现边缘脏、文字糊、渐变断层。
场景贴图: 可以更积极压缩,因为场景图往往数量大,是包体和显存大头。
法线贴图: 不要压得太狠,否则光照会出块状、凹凸错误。PC 上常见 BC5,移动端可以根据平台选合适的 ASTC/ETC2 格式。
特效贴图: 要注意透明区域和 Overdraw,压缩格式只是其中一部分,还要控制贴图尺寸和透明面积。
Crunch 是什么
Crunch 更偏向减少包体或下载体积,不等于 GPU 直接用 Crunch 格式。
它通常会在加载时解压成 GPU 可用的压缩格式,所以:
- 好处:包体更小
- 代价:加载时 CPU 解压成本更高
- 适合:非频繁加载、对包体敏感的资源
- 不适合:战斗中临时大量加载的关键资源
面试高分回答
TIP
Texture 压缩格式我会先按平台选,移动端优先 ASTC,Android 兼容可以用 ETC2,PC 用 DXT/BC 系列。然后看贴图是否需要 Alpha,不需要透明就不用 RGBA,避免浪费。接着按用途区分,UI 和文字优先清晰度,场景贴图优先体积和显存,法线贴图要避免压缩失真。ASTC 可以通过 4x4、6x6、8x8 调整质量和体积。最后一定要真机检查,因为压缩格式不只是影响包体,还会影响显存、带宽、加载速度和最终画质。
ASTC、ETC2、PVRTC 区别是什么?
它们都是 GPU 纹理压缩格式。目的都是让贴图更省 包体、显存、带宽,但它们的 平台支持、压缩质量、适用场景 不一样。
ASTC
ASTC 是现在移动端很常用、也很推荐的压缩格式。
它的特点是 质量好、压缩率灵活、支持 Alpha。 比如你可以选:
ASTC 4x4:质量高,体积较大ASTC 6x6:质量和体积比较平衡ASTC 8x8:更省空间,但画质更糊
所以 ASTC 特别适合移动端项目里大部分贴图,比如角色、场景、UI、特效。
面试可以说:现代 Android 和 iOS 设备,优先考虑 ASTC。
ETC2
ETC2 更常用于 Android 兼容方案。
它比 ETC1 更强,因为 ETC1 不支持完整 Alpha,而 ETC2 可以支持 RGB,也可以支持 RGBA。
ETC2 的优点是:
- Android GLES3 设备支持比较普遍
- 支持透明
- 兼容性比 ASTC 在某些 Android 设备上更稳
缺点是压缩质量和灵活性通常不如 ASTC。
面试可以说:如果目标 Android 设备不一定都支持 ASTC,可以考虑 ETC2 作为兼容方案。
PVRTC
PVRTC 主要是老 iOS 设备常见的压缩格式。
它的常见规格有:
PVRTC 2bppPVRTC 4bpp
PVRTC 的问题是压缩质量限制比较明显,尤其是:
- UI 边缘容易脏
- 渐变容易糊
- 透明图可能有瑕疵
- 细节贴图容易失真
现在如果目标是较新的 iOS 设备,通常更推荐 ASTC。
面试高分回答
可以这样说:
WARNING
ASTC、ETC2、PVRTC 都是 GPU 纹理压缩格式。ASTC 是现代移动端比较推荐的格式,支持 Alpha,质量好,而且可以通过 4x4、6x6、8x8 这种 block size 在质量和体积之间做平衡。ETC2 常作为 Android 兼容方案,比 ETC1 强,因为 ETC2 支持 Alpha。PVRTC 主要用于老 iOS 设备,但质量限制比较明显,UI、渐变和透明边缘容易出问题。所以实际项目里我会优先 ASTC,Android 兼容用 ETC2,只有需要兼容老 iOS 时才考虑 PVRTC。
音频压缩怎么选?
Unity 里音频压缩不是只看“文件小不小”,而是看 包体、内存、CPU 解码、加载速度、播放延迟 的平衡。
PCM
PCM 基本可以理解成“不压缩音频”。
优点是播放时几乎不需要解码,响应快、质量高。缺点是包体和内存占用很大。
适合:
- 很短的 UI 点击音
- 打击瞬间音效
- 对延迟敏感的短音效
不适合:
- BGM
- 长语音
- 大量长音频
ADPCM
ADPCM 是一种比较适合游戏短音效的压缩格式。
它比 PCM 小,解码成本也比较低,但是压缩率不如 Vorbis。
适合:
- 技能音效
- 受击音效
- 脚步声
- 频繁播放的短音效
面试里可以说:短音效如果既想省一点内存,又不想解码太贵,可以考虑 ADPCM。
Vorbis
Vorbis 是有损压缩,压缩率高,包体小,但播放或加载时有解码成本。
适合:
- 背景音乐
- 剧情语音
- 角色长语音
- 环境音
面试里可以说:长音频通常用 Vorbis,因为包体和内存更重要。
Load Type 怎么选
Decompress On Load:加载时解压到内存。 播放最稳、CPU 压力小,但内存占用大。适合短且频繁播放的音效。
Compressed In Memory:内存里保持压缩,播放时解码。 省内存,但播放时有 CPU 解码开销。适合中等长度、播放不特别频繁的音频。
Streaming:边读边播。 内存占用低,适合 BGM 和很长的语音。但不要同一时间 Streaming 太多音频,否则可能有 IO 压力。
Sample Rate 怎么调
不是所有音频都需要 44100 Hz。
比如:
- 普通语音可以降低采样率
- 低频环境音可以降低采样率
- 很短的提示音可以适当压缩
- 高品质 BGM 可以保留更高采样率
采样率越高,数据越大;声道越多,占用也越大。
Force To Mono
很多音效其实不需要立体声,比如按钮音、普通攻击音、拾取音。
如果开 Force To Mono,双声道可以变单声道,数据量可能直接减少接近一半。
面试高分回答
可以这样说:
IMPORTANT
音频压缩我会按用途来选。短音效重视播放响应和 CPU 开销,一般用 PCM 或 ADPCM,并配合 Decompress On Load;长音乐和长语音重视包体和内存,一般用 Vorbis,并配合 Streaming。中等长度、不频繁播放的音频可以用 Compressed In Memory。除此之外,还会根据音频内容降低 Sample Rate,普通音效开启 Force To Mono,关键音效预加载,避免首次播放卡顿。总体思路是短音效用空间换速度,长音频用解码和流式加载换内存。
Mesh 压缩有什么风险?
Mesh 压缩的本质是:降低顶点数据精度。它可以减少包体和模型数据大小,但风险是模型的 顶点位置、法线、切线、UV 可能出现误差。
1. 模型可能变形
Mesh 压缩会对顶点位置做近似保存。压缩等级越高,精度损失越明显。
可能出现:
- 轮廓变歪
- 边缘抖动
- 小细节丢失
- 模型接缝裂开
- 远离原点的大场景精度问题更明显
比如细长的武器、尖角建筑、小装饰物,压缩后很容易看出形状变化。
2. 法线和切线可能出问题
法线 Normal 决定光照方向,切线 Tangent 常用于法线贴图。
如果它们被压缩得太狠,可能出现:
- 光照变脏
- 高光方向不对
- 法线贴图效果异常
- 金属材质、皮肤材质看起来怪
所以有法线贴图、PBR 材质、高光明显的模型,不建议随便开高压缩。
3. UV 可能产生误差
UV 是贴图坐标。UV 精度下降后,可能出现:
- 贴图轻微偏移
- 图集边缘串色
- 接缝明显
- Lightmap 采样错误
- UI 或标志类模型边缘变脏
尤其是使用图集、Lightmap UV、精细贴图的模型,要谨慎。
4. 骨骼动画可能出问题
角色模型是 Skinned Mesh,顶点会随着骨骼运动。
如果顶点精度下降,可能导致:
- 动画时皮肤穿插
- 面部表情变形异常
- 手指、脸部这种细节部位出问题
- BlendShape 效果不准确
所以主角、NPC、脸部模型、带 BlendShape 的模型,一般不要使用太高的 Mesh 压缩。
5. 碰撞和挂点可能不准
如果你用 Mesh 做精确碰撞,压缩后顶点位置变了,碰撞形状也可能不准。
风险包括:
- 子弹碰撞不准确
- 地形边缘卡住
- 武器挂点偏移
- 特效挂点看起来错位
所以碰撞相关 Mesh、武器、坐骑、挂点密集的模型,要特别小心。
6. 什么模型适合压缩
比较适合压缩:
- 远景模型
- 静态场景小物件
- 不重要的装饰物
- 低面数、低精度要求模型
- 玩家不容易近距离观察的模型
不太适合压缩:
- 主角模型
- 脸部模型
- 武器模型
- 精确碰撞 Mesh
- 法线贴图明显的模型
- Lightmap 要求高的模型
- 带 BlendShape 的模型
面试高分回答
可以这样说:
CAUTION
Mesh 压缩能减少模型数据和包体,但它不是无损的,本质是降低顶点属性精度。风险主要有顶点位置误差导致模型变形,法线和切线误差导致光照、高光、法线贴图异常,UV 误差导致贴图偏移、接缝和 Lightmap 问题。对于主角、脸、武器、精确碰撞、BlendShape、法线贴图明显的模型,我会谨慎压缩;对于远景、静态、不重要装饰物,可以适当开启压缩。最终一定要在真机和目标画质下检查,而不是只看包体减少了多少。
Shader Variant 为什么会爆炸?
Shader Variant 爆炸的本质是:各种开关组合在一起不是加法增长,而是乘法增长。
Variant 是什么
一个 Shader 里可能有很多功能开关,比如:
- 是否使用法线贴图
- 是否开启阴影
- 是否开启雾效
- 是否开启自发光
- 是否开启 GPU Instancing
- 是否使用额外灯光
Unity 会根据这些开关生成不同版本的 Shader,这些版本就叫 Shader Variant。
为什么会爆炸
比如一个 Shader 有 8 个二选一开关,每个开关都有开和关:
2^8 = 256如果这个 Shader 还有 3 个 Pass:
256 x 3 = 768如果还要支持 2 个平台:
768 x 2 = 1536真实项目里还会叠加光照、阴影、雾效、渲染管线、质量设置、平台 API,所以数量会非常快地膨胀。
multi_compile 和 shader_feature 的区别
multi_compile 比较危险。 它会告诉 Unity:这些变体都要准备,即使项目里没有用到,也可能被打进去。
shader_feature 更适合可选功能。 Unity 构建时可以尝试裁剪没用到的变体。
所以面试可以说:能用 shader_feature 的地方,不要无脑用 multi_compile。
爆炸有什么后果
主要有三个问题:
- 包体变大 变体越多,最终构建产物越大。
- 构建变慢 Unity 要编译大量 Shader 版本,CI 打包也会变慢。
- 运行时卡顿 如果某个变体没有提前准备,运行时第一次用到时可能出现 Shader 编译卡顿,比如放技能、切场景、换皮肤时突然卡一下。
怎么优化
常见做法:
- 减少无用 Keyword
- 少用
multi_compile - 可选功能尽量用
shader_feature - 使用 Local Keyword,减少全局关键字污染
- 裁剪不用的阴影、雾效、光照模式
- 拆分复杂 Shader,不要一个 Shader 包所有功能
- 使用 Shader Variant Collection 做预热
- 用 Build Report 或 Shader Variant Log 分析数量
- URP/HDRP 里关闭没用的管线特性
面试高分回答
NOTE
Shader Variant 爆炸是因为 Shader Keyword、Pass、光照阴影、雾效、Instancing、平台和渲染管线配置会组合生成不同版本。它不是线性增长,而是乘法增长。比如 8 个二选一 Keyword 就是 256 个变体,再乘上 Pass、平台和管线配置,数量会很快失控。后果是包体变大、构建变慢、运行时可能 Shader 编译卡顿。优化上我会减少 Keyword,少用 multi_compile,多用 shader_feature,开启变体裁剪,拆分复杂 Shader,并对必要变体做预热。
如何裁剪未使用资源?
裁剪未使用资源,不能简单理解成“项目里没看到引用就删”。Unity 里很多资源可能是 动态加载、配置表引用、热更引用、Addressables 引用,直接删很容易线上 Missing。
正确流程
第一步,找构建入口。 比如 Build Settings 里的场景、Addressables Group、AssetBundle 构建规则、Resources 目录、热更资源列表。
第二步,分析依赖链。 场景引用 Prefab,Prefab 引用材质,材质引用贴图,动画引用 Avatar、骨骼、事件,ScriptableObject 又可能引用一批配置资源。
第三步,找可疑资源。 如果一个资源不在构建入口依赖链里,也不在白名单里,也没有被配置表或代码动态加载,就可以标记为“疑似未使用”。
第四步,先隔离再删除。 不要一上来直接删,可以先移动到隔离目录,打包、启动、切场景、跑主流程,确认没有 Missing Reference 再真正删除。
Unity 里最容易误判的地方
Resources 目录: Resources 下面的资源一般都会进包,即使你没在场景里直接引用。
Addressables: 资源可能通过 Address 地址、Label、配置表加载,不能只看 Inspector 引用。
AssetBundle: 资源可能由打包规则收集进去,还要检查 Bundle 之间的依赖和重复资源。
字符串路径加载: 比如 Resources.Load("Effect/Hit01"),编辑器依赖分析不一定能准确知道它会被用到。
配置表引用: 很多项目的怪物、技能、UI、剧情资源都是配置表里写路径加载的,这类资源必须加入白名单或从配置表反查。
常用工具
可以用这些方式辅助分析:
Build Report看最终包体里资源占用Editor.log查看打包资源信息Build Analyzer找大资源和重复资源AssetDatabase.GetDependencies查依赖链Addressables Analyze检查重复打包和依赖问题- 自研资源扫描工具,反查配置表、Prefab、场景、Addressables
面试高分回答
TIP
裁剪未使用资源我不会直接按“编辑器里没有引用”删除,而是先确定所有构建入口,包括场景、Resources、Addressables、AssetBundle、配置表和动态加载路径。然后建立资源依赖图,找出没有被任何入口依赖、也不在白名单里的资源。对疑似未使用资源先隔离,不直接删除,再通过打包、启动、切场景、主流程自动化测试来验证。最后配合 Build Report、Addressables Analyze 和自研扫描工具持续检查,避免因为字符串加载、热更资源、配置表引用导致误删。
Addressables 如何分析包体?
Addressables 分析包体,重点不是只看“某个资源多大”,而是看 Bundle 大小、依赖关系、重复资源、Group 分组、Local/Remote 边界。
第一步:先看构建结果
不要只看 Project 目录里的资源大小,要看 Addressables 真正 Build 出来的结果。
重点看:
- 哪些 Bundle 最大
- 每个 Bundle 里有哪些 Asset
- Asset 依赖了哪些资源
- 哪些资源被重复打进多个 Bundle
- 哪些资源进了首包,哪些资源进了远程包
第二步:看 Build Layout Report
Build Layout Report 可以看到:
- Bundle 列表
- Bundle 大小
- 每个 Bundle 包含哪些资源
- 每个资源的依赖
- 哪些资源被哪个 Addressable Asset 带进去
- 隐式依赖是否过大
比如一个 Prefab 本身不大,但它引用了材质,材质引用了大贴图,最后真正变大的可能是贴图依赖。
第三步:用 Analyze 查重复依赖
Addressables 的 Analyze 工具可以检查重复 Bundle 依赖。
最常见的问题是:
两个不同 Group 里的 Prefab 都引用了同一张贴图。 如果这张贴图没有单独 Addressable 化,可能会被分别打进两个 Bundle,导致包体重复。
解决思路:
- 公共贴图单独放到公共 Group
- 公共材质单独管理
- 公共 Prefab、字体、Shader 单独成包
- 避免多个 Bundle 各自携带同一份依赖
第四步:检查 Group 分组是否合理
Group 分组会直接影响包体结构。
常见问题:
- 把不相关资源 Pack Together,导致一个小资源加载带出一大包
- 把强相关资源拆太散,导致加载时请求很多 Bundle
- 公共资源没有独立分组,造成重复依赖
- 首包 Group 塞了太多非必要资源
- 远程资源没有按玩法、章节、活动拆分
面试可以说:Group 设计不是越细越好,也不是越粗越好,要根据加载场景和更新粒度设计。
第五步:对比优化前后
一次优化是否有效,要用数据证明。
可以对比:
- 首包大小是否下降
- 远程包大小是否合理
- Bundle 数量是否变化
- 重复资源是否减少
- 加载请求数量是否变多
- 峰值内存是否变化
- 下载体积是否下降
不能只说“我删了一些资源”,要说“通过报告对比,首包减少了多少,重复依赖减少了多少”。
面试高分回答
IMPORTANT
Addressables 分析包体我会先 Clean Build,拿到真实构建结果,然后看 Build Layout Report,分析每个 Bundle 的大小、包含资源和依赖链。接着用 Analyze 检查 Duplicate Bundle Dependencies,找出公共贴图、材质、字体、Shader 是否被多个 Bundle 重复打包。然后根据加载场景调整 Group,比如公共资源单独成包,大资源放远程包,首包只保留启动必要资源。优化后我会保留前后两份构建报告,对比首包大小、远程包大小、重复资源、Bundle 数量和加载请求数量,避免只优化包体却把加载性能搞差。
首包和分包策略怎么设计?
首包和分包的核心目标是:首包尽量小,首次体验完整,后续资源按需下载,公共依赖不重复,热更版本可控。
首包放什么
首包只放玩家第一次打开游戏必须用到的东西:
- 启动场景
- 登录界面
- 基础 UI
- 核心代码
- 基础配置表
- 基础 Shader
- 通用字体
- 新手流程必需资源
- 首战或最早玩法必需资源
不要把后期地图、活动资源、大量皮肤、全量语音、全部角色都塞进首包。
分包怎么拆
常见拆法:
- 按场景拆:主城、战斗场景、副本场景
- 按玩法拆:PVP、PVE、公会、家园、活动
- 按章节拆:第一章、第二章、第三章
- 按角色拆:角色模型、技能特效、语音
- 按语言拆:中文、英文、日文语音和文本
- 按清晰度拆:高清资源、低配资源
- 按活动拆:限时活动单独热更包
面试里要说:不是拆得越碎越好。拆太碎会导致加载请求多、依赖复杂;拆太粗又会导致下载大包。
公共依赖要单独管理
很多包会共用资源,比如:
- 公共贴图
- 公共材质
- 公共 Shader
- 字体
- 通用 UI 图集
- 通用音效
- 通用特效
这些资源最好单独成公共包,否则多个分包可能重复打进同一份资源,包体会膨胀。
下载时机怎么设计
可以分几类:
启动前必须下载: 版本清单、基础配置、登录必要资源。
进入玩法前下载: 比如玩家要进某个副本,提前检查这个副本的场景、怪物、音效、特效是否已下载。
后台预下载: 玩家停留在大厅时,可以悄悄下载后续章节、常用资源。
按需下载: 玩家点击某个活动、皮肤、语音包时再下载。
风险控制
分包一定要考虑异常情况:
- 网络断开怎么办
- 下载失败怎么办
- Hash 校验失败怎么办
- 缓存损坏怎么办
- 版本清单和资源版本不一致怎么办
- 下载到一半退出游戏怎么办
- 资源更新失败是否能回滚
成熟一点的方案会有版本清单、Hash 校验、断点续传、失败重试、缓存清理和回滚机制。
面试高分回答
WARNING
首包和分包我会先按资源使用时机分类。首包只放启动、登录、新手流程、首战和核心系统必须用到的资源,保证玩家首次进入体验完整,但不把后期地图、活动、皮肤、语音等资源放进去。分包一般按场景、玩法、章节、活动、语言和清晰度拆分。公共贴图、字体、Shader、材质、通用 UI 会单独放公共包,避免多个分包重复依赖。下载策略上,启动阶段只拉版本清单和必要资源,进入玩法前检查并下载对应分包,空闲时后台预下载。最后通过版本清单、Hash 校验、缓存、重试和回滚机制保证热更稳定。
Android 和 iOS 包体差异有哪些?
Android 和 iOS 包体差异有哪些?
Unity 项目在 Android 和 iOS 上包体不一样,主要差异来自 包格式、原生库、纹理压缩格式、平台 SDK、商店分发机制。
Android 包体特点
Android 常见是 APK 或 AAB。
里面通常有:
classes.dexlibil2cpp.soassetsresAndroidManifest.xml- 第三方
AAR / JAR / so
Android 包体很容易被 ABI 影响。
比如同时打:
armeabi-v7aarm64-v8a
如果是 Universal APK,可能会把多个架构的 so 都放进去,包体会明显变大。 如果使用 AAB,商店可以按设备架构、语言、屏幕密度拆分下发,用户实际下载体积会更小。
iOS 包体特点
iOS 常见是 IPA。
里面通常有:
- Mach-O 可执行文件
- Frameworks
- Unity Data
- AssetCatalog
- 资源 bundle
- 插件相关 framework 或 xcframework
Unity iOS 一般使用 IL2CPP,C# 代码最终会变成 native 产物。 iOS 也有 App Thinning,商店会尽量只给用户下发当前设备需要的资源和架构。
纹理压缩差异
Android 常见:
ASTCETC2- 老设备可能涉及
ETC1
iOS 常见:
ASTC- 老设备可能涉及
PVRTC
所以同一套贴图,在 Android 和 iOS 上可能会被压成不同格式,最终包体和显存占用也会不一样。
插件 SDK 差异
Android 插件经常带:
AARJARDEXresso
这些会增加代码体积、资源体积和 native 库体积。
iOS 插件经常带:
Frameworkxcframework.bundle资源- 原生静态库或动态库
如果 SDK 接得多,比如登录、支付、广告、统计、推送,两端包体都会明显增加,但组成不一样。
面试高分回答
CAUTION
Android 和 iOS 包体差异主要来自平台打包结构。Android 是 APK 或 AAB,里面有 dex、res、assets、libil2cpp.so 和第三方 AAR、so,包体很容易受 ABI 数量影响;如果打 Universal APK,同时包含 arm64-v8a 和 armeabi-v7a,体积会变大,而 AAB 可以按设备拆分下发。iOS 是 IPA,主要包含 Mach-O 可执行文件、Framework、Unity Data 和资源 bundle,Unity iOS 通常走 IL2CPP。资源方面,两端纹理压缩格式也不同,Android 常用 ASTC 或 ETC2,iOS 常用 ASTC,老设备可能用 PVRTC。优化时两端都要看贴图、音频、Shader Variant、插件 SDK,但 Android 重点关注 ABI 和 AAB,iOS 重点关注 Framework、架构裁剪和 App Thinning。