解释微信小游戏分包与Unity Code Stripping

解读

面试官把“微信小游戏分包”与“Unity Code Stripping”放在一起,是想一次性验证候选人对国内真机上线瓶颈的完整认知

  1. 微信小游戏首包 4 MB 硬限制,如何拆包、如何与 Unity 的 Assembly 划分联动;
  2. Unity 默认会把整包 Mono 与 IL2CPP 产物全部打进首包,不做 Stripping 极易超限
  3. 两者必须协同设计,否则拆完包仍然超限,或者拆包后运行时缺失类导致闪退。
    回答时要体现“国内上线流程视角”:从微信开发者工具、小游戏后台配置,到 Unity PlayerSettings、Link.xml、Addressables 分组策略,再到真机调试、性能回归,形成闭环。

知识点

  1. 微信小游戏分包规则

    • 主包 ≤ 4 MB(压缩后),分包 ≤ 4 MB,总包体 ≤ 20 MB;
    • 分包只能异步加载,首次进游戏必须保证主包可独立跑通核心逻辑
    • 分包路径在 game.json 中 subpackages 字段声明,微信 API wx.loadSubpackage 触发下载;
    • 资源分包与代码分包可叠加,但代码分包必须走 Unity 的 Assembly Definition + Build Scripting Define 方式,否则 IL2CPP 仍会把所有方法编译进主包。
  2. Unity Code Stripping 层级

    • Mono 托管层:通过 IL2CPP 的 ByteCode Stripping 移除未用类、方法、字段;
    • C++ 层:IL2CPP 生成的 C++ 代码再被 Xcode/Android NDK 的 LTO/Strip 二次裁剪;
    • 引擎层:PlayerSettings 的 Strip Engine Code 会丢弃未用模块(Unity 子系统、第三方静态库),可减 1~3 MB 不等
    • 控制手段:Link.xml 白名单、Preserve 特性、Assembly Definition 的 Override 策略。
  3. 协同落地关键点

    • Assembly Definition 拆分优先级:大厅、战斗、SDK、第三方插件各自成库,确保微信分包与 Unity Build Report 的“Scenes/Scripts” size 一一对应;
    • Scripting Define 隔离:主包只保留 INIT 与 UPDATE 宏,其余玩法宏在分包 Assembly 中定义,防止 IL2CPP 把全量泛型模板编译进主包;
    • 资源侧用 Addressables + LZMA 压缩,把纹理、音频、ShaderVariant 独立分组,与代码分包同名,方便 wx.loadSubpackage 一次性拉起;
    • 首包空场景启动:主场景仅放下载进度条与版本比对脚本,把真正的首场景打成首个分包,避免微信审核时因首包资源过大被拒;
    • 出包后必跑微信开发者工具“代码依赖分析”,确认无“红色未引用”项,同时用 nm -C libil2cpp.so | grep Strip 检查裁剪比例,低于 65% 需回炉优化

答案

“微信小游戏分包解决的是首包 4 MB 硬门槛,Unity Code Stripping 解决的是引擎与脚本体积膨胀,两者必须在同一套 Assembly 与资源分组策略下联动
我的做法是三步:
第一步,用 Assembly Definition 把业务纵向切成大厅、战斗、SDK、更新器四个模块,每个模块对应微信的一个 subpackage,并在 PlayerSettings 里给主包只保留 INIT 宏,确保 IL2CPP 不会把战斗逻辑编译进首包;
第二步,开启 Strip Engine Code,配合 Link.xml 把热更框架、反射调用入口显式 Preserve,同时把 Addressables 的 ShaderVariant、音频、UI Atlas 按分包同名分组,用 LZMA 压缩后放到远程 CDN;
第三步,出包后用微信开发者工具做依赖分析,主包脚本压缩后 3.2 MB、资源 0.6 MB,总 3.8 MB 通过审核;首场景只放下载进度条,真正场景放在首个分包,用户首次进入 1.3 秒完成分包下载与场景加载,整包裁剪率 68%,内存占用下降 28%,线上崩溃率低于 0.1%。”

拓展思考

  1. 若项目使用 HybridCLR 热更,热更 dll 本身不能参与微信分包,需把 dll 当资源放到远程 CDN,通过 wx.downloadFile 缓存到用户本地;此时要在 Link.xml 中 Preserve 所有热更类型,防止 IL2CPP 把元数据裁掉导致解释执行失败。
  2. 微信即将开放的动态库分包(*.wasm 分包) 会允许把 IL2CPP 生成的 wasm 切片,届时可进一步把主包脚本降到 2 MB 以下,但需要 Unity 2022.3 LTS 以上版本并在 Build Settings 中开启 WebAssembly Streaming,提前升级管线可避免后续返工
  3. 对于重度 3D 项目,GPU Instancing 与 ShaderVariant 爆炸 也会挤占首包,可自定义 ScriptableRenderPipeline 的 Shader Stripper,在 BuildPipeline 阶段按场景剔除无用 Variant,再与 Code Stripping 一起跑 CI 自动化,每晚上报包体曲线,实现“包体增长可预警”。