Unity減小安裝包的體積(210MB減小到7MB)


概述

項目簡介

由於是公司內做的項目,不方便開源,就只分享優化過程吧。

項目信息

逐日是一個移動端單機小游戲,使用Unity開發,目前已將項目使用的Unity升級到2019.4.14f1c1 (3e5991a5f6ba)版本。

項目內容

在進行優化前,項目資源目錄如下,可以看到,項目目錄命名雜亂,包含很多需求迭代產生的舊資源、無用場景、未壓縮的音視頻等內容。

由於這次主要是對於安裝包大小的一些嘗試,所以就不會特別關注游戲邏輯,整體能加載完成,不Crash就OK,沒有對游戲邏輯上花費過多精力,后面的過程中可能有小部分圖被壓糊了,有視頻無法加載等問題,不影響縮包的最終結果。

image-20201115164756651image-20201115165104789

未優化的包體大小

如圖所示,使用新版UnityEditor直接打包之后,生成的游戲Apk大小為218MB,這對於一個只有兩個關卡的小游戲而言,明顯過於臃腫了,假如上架到GooglePlay之后,光下載內容所消耗的時間和流量就勸退了一部分用戶(更何況,現在GooglePlay限制了安裝包大小不能大於100M!)。所以,對於安裝包大小的優化是勢在必行的。

image-20201115165302989 image-20201115165635615

第一步:Assembly構建優化

使用IL2CPP代替Mono

  • Mono使用即時(JIT)編譯,並在運行時按需編譯代碼。
  • IL2CPP使用提前(AOT)編譯並在運行之前編譯整個應用程序。

使用IL2CPP進行構建有助於提高運行速度,並減少包體大小,IL2CPP的工作流程如下圖:

A diagram of the automatic steps taken when building a project using IL2CPP image-20201115202035036

將ScriptingBackend設置為IL2CPP后,執行構建得到的安裝包大小為210MB,比使用Mono少了8MB(這個項目里游戲邏輯不多,腳本比較少,對於較大的項目來說,使用IL的優勢更大)

image-20201115202221885

裁剪更多未使用的代碼(不是特別推薦)

Unity有提供一個Managed Stripping Level選項,可以在構建時裁減掉未使用的代碼,這個選項又是那個可選級別,IL2CPP不能關閉這個選項並且默認級別為Low。不同的裁剪級別對應的規則不同,裁減掉游泳的代碼可能性越高,並且有可能無法檢測到通過反射引用其他代碼的情況,導致程序崩潰。

設置Managed Stripping Level=High后,安裝包大小為209M。

image-20201115203846804

關於腳本構建優化

對於Android Platform,我對於一個空的Unity3D項目進行過如下打包測試:

構建設置 ApkSize
默認(Mono_Release_DotNetStandard2.0) 16.9 MB
ScriptBackend使用IL2CPP 6.38 MB
StrippingLevel=High 6.02 MB
CompressMethod=LZ4HC 5.96 MB
GraphicApi只使用OpenGLES2(Android 2.2+都支持) 5.73 MB

再往下就很難減小了......

第二步:資源優化

分析資源大小的利器

在Editor中構建完成后,可以打開EditorLog,里面列出了在未壓縮的情況下,不同類型資源的占比以及每個資源體積從大到小的排列,我們可以直接根據Log查找哪些資源比較大,針對性地處理:

image-20201115232035753 image-20201115232139955

移除未使用的資源

為什么把這一步放在資源優化的第一位?因為先去掉無用的資源后面打包會快很多嘛。。。測試一個屬性就要重新打個包有時候甚至需要重新Import整個項目半小時的時間傷不起啊~

在GitHub上隨便找了個資源清理工具UnityAssetCleaner,對項目中的無用資源進行了清理:

image-20201115222704658

這個步驟直接讓Assets目錄的大小從1.27GB減小到192MB,由於資源沒有放在Resource下,所以未引用的資源並沒有打包到Apk中,這個步驟之后僅僅讓包體大小減少到了208MB。

但是重新Import項目會快很多啊有木有~!這也看出來當時做的時候走了多少彎路。。。

去掉無用的場景

第一次用Unity做游戲時,關卡切換、各種UI面板都是使用獨立的場景做的,明明可以用Prefab的> _ <

看了下游戲里的場景,沒有需要刪掉的。。。如果有無用的場景,刪除掉也可以減少包體大小。

image-20201115225522851

紋理尺寸壓縮、視頻音頻質量壓縮

在項目中,盡可能降低圖片和音視頻的質量,使用低質量高壓縮率的壓縮格式,不僅內存占用低、性能也更好;當出現質量不滿足要求時,再逐步的提升尺寸和壓縮格式來滿足需要。Link→官方文檔:不同平台下支持的壓縮格式

image-20210404152720376

要在不修改源文件的情況下修改尺寸,可以直接在Unity里調整:

image-20201115230648498

如上圖所示,游戲里的紋理都是按照最大尺寸來導入的,並且由於使用的是Sprite動畫,導致一個動畫就要使用很多紋理,所以首要的問題是把不同的圖片調整到適當的尺寸,比如場景地圖使用2048或1024,較大的Boss角色和樹木使用512,小怪、小火球等紋理使用256或更小。

音效以及視頻,也按照類似的方法,適當調低分辨率和碼率(視頻其實可以直接放CDN)。

image-20201115232657349

image-20201115232741122

調整完之后,重新打了個包,emmm...只有52MB了(當然,有一小部分紋理被我壓糊了,適當調整之后最終結果其實相差不大)。

image-20201115232941690

Sprite Atlas

多個NPTO的紋理拼合到一起組成一個POT型的圖集有利於Unity壓縮圖片,更能節省空間。創建方式如下(Unity2019+版本默認不使用給紋理打Tag的方式創建圖集,而是需要手動創建)

image-20201116232559659

將游戲中大小、用途類似的紋理,添加到各自的圖集中,重新打包,包體大小33M。

image-20201122203032593

AssetBundle打包

這可能是縮小Apk大小的最好方案了......

總體流程概述

如果前面的一系列縮包方法都不能達到想要的效果,就可以考慮把資源單獨打包拿出來,用戶啟動App時進行下載。

首先在Unity里給資源打標簽,把資源分到對應的Bundle中。

image-20201123000518152

然后執行構建AssetBundle腳本(腳本官網文檔有提供),把AssetBundle包輸出到指定路徑。

image-20201123000536655

詳細過程

把場景使用Prefab代替

在優化的過程中我發現,Unity通過BuildSetting中的場景列表來查找所有依賴的資源,所以為了打出來獨立的AssetBundle包並斷開AssetBundle內的資源與Apk之間的依賴關系,就需要對場景做優化。

將場景中的內容簡單粗暴地整合到一個GameObject內,制作成Prefab,用掛載Prefab的方式代替掛載場景,並刪掉原來的場景,清理BuildSetting中的場景列表。這樣就斷開了AssetBundle內的資源與Apk之間的依賴。

實現入口腳本

我的辦法是創建一個Init場景作為整個App的入口,里面只掛一個GameFramework腳本來執行一系列必要的AssetBundle加載過程、管理各個用於代替場景的Prefab。

這樣修改之后,我們構建出來的Apk就只會包含一個空的場景,以及C#腳本構建產生的dll,大小最小能有前面所說的5MB!!!

打AssetBundle包

前面我們把資源和Apk之間的依賴關系切斷了,但是我們還是要想辦法把它們動態加載回去的,這種方法就是AssetBundle包。

給資源打標簽的過程是非常繁瑣的,所以就使用腳本自動化處理了,會自動給ResForBundle下的直接子目錄按照目錄名遞歸添加標簽。

運行了BuildAssetBundle命令之后,我們就能在輸出目錄得到一系列相互依賴的AssetBundle文件了(也包括他們的manifest描述文件)。

動態加載AssetBundle

我們可以使用Unity提供的AssetBundle Api來動態把AssetBundle文件加載到內存里,並根據路徑讀取它們包含的資源,由於游戲內的資源比較少,大約20~30MB,所以我就直接放在StreamingAssets目錄下了(關於這個目錄,是和Resource一樣特殊的存在,感興趣的話可以直接查一下)

在GameFramework啟動時就加載所有的AssetBundle,並掛載Scene_Start.prefab到場景中,這樣我們的游戲流程又能正常走下去了。

當然這個過程中還有好多好多細節要處理:

  • 比如需要用宏來判斷是在編輯器中還是在移動端,從而采用不同的自定義ResourceLoad來加載資源(如果是編輯器的話直接使用AssetDatabase Api通過路徑加載資源,移動端則采用上面提到的AssetBundle內的資源);

  • 如何遞歸地給指定目錄下的內容添加標簽並自動維護它們;

優化結果

對場景進行精簡優化,只保留一個入口場景加載AssetBundle和加載入口,構建后,Apk大小只有7M。

image-20201123000627423

打出的AssetBundle可以在App啟動時通過http拉取到本地,如果不嫌資源包大的話也可以直接放在StreamingAssets目錄打到apk內。

縮包歷程

直接上圖好了:

image-20201123000745375

KeyWorkds:Unity安裝包體積優化,Unity減小安裝包體積,Unity構建更小的Apk,Unity減小構建的安裝包大小,Unity縮小安裝包


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM