使用 Addressables 來管理資源
一、安裝
開啟Package Manager
,在Unity Technologies
的目錄下找到Addressables
,更新或下載。
二、配置
依次開啟Windows/Asset Management/Addressables/Groups
選單。
首次開啟後會提示需要建立配置檔案,點選Create Addressables Settings
。
Assets
目錄下會生成AddressableAssetsData
資料夾。
Ⅰ. 認識資源組(AssetGroups)與組策略(AssetGroups Schemas)概念
-
點選
Manage Groups
,返回剛才的Addressables Groups
皮膚。此時已經有了兩個內建的組。 -
Built In Data
儲存的是工程中Resources
資料夾下的資源,隨App構建的場景資源,以及其他一些必要的資源等。 -
Default Local Group (Default)
組儲存的是工程中被標記為Addressables
的資源,假如不對其進行手動分組,則預設放在這個組中。 -
點選
Create
,可以指定模板來複制一個組或者建立一個全新的組。模板儲存在AddressableAssetsData/AssetGroupTemplates
資料夾下,預設有一個名為Packed Assets
的模板,新建立的組儲存在AddressableAssetsData/AssetGroups
資料夾下。我們手動建立一個名為Remote
的新組。
-
點選
Remote
組的Add Schema
按鈕,新增Content Update Restriction
和Content Packing & Loading
策略。注意不要額外新增Resources and Built In Scene
策略,這個已經由Built In Data
組負責了。在
AssetGroups
資料夾中有一個Schemas
資料夾,存放著所有資源組的組策略序列化檔案,命名規則為$"{組名}_{策略型別}"
。
-
配置
Remote
組策略。-
修改在
Content Update Restriction
下的Update Restriction
選項。Can Change Post Release
的意思是,當前資源組進行最終構建時會完全覆蓋上一次構建結果(打包出的檔名與上一次不同,上一次的包徹底無效化,部署時可以直接刪掉),一般這種方式叫做 全量更新而
Can not Change Post Release
則意味著,當前資源組構建時需要與上一次構建結果進行比對(Addressables Groups/Tools/Check for Content Update Restrictions
),上一次構建出的包不發生變化,新構建的包則建立在舊包的基礎上(相同的資源儲存在舊包內,修改和新增的資源儲存在新包內,部署時需要將新包和舊包一起發到伺服器上),這種方式一般叫做 增量更新。 -
修改
Content Packing & Loading
下的Build Path
和Load Path
選項。-
LocalBuildPath
本地構建路徑,當App釋出時,會將這個路徑下的包拷貝到App的StreamingAssets
裡。 -
LocalLoadPath
本地載入路徑,當App執行時,會從這個路徑下讀取資源包,一般也是在App的StreamingAssets
裡。Local___Path
說明這個組中的資源包會包含在App的安裝包內。如果所有資源組都設定為Local
,則這個App安裝包是 全資源包 (全資源包一般是設定為Can not Change Post Release
的)。 -
RemoteBuildPath
遠端構建路徑,當構建資源包後,需要將這個路徑下的包拷貝到伺服器上。 -
RemoteLoadPath
遠端載入路徑,當App執行時,會從這個地址下載catalog,並與本地catalog對比來判斷是否需要更新資源。
如果想對 全資源包 進行更新,可以點選
Addressables Groups/Tools/Check for Content Update Restrictions
,會自動生成差異化資源組,將這些資源組設定為遠端並構建部署,則可以將App內包含的舊資源進行覆蓋。 -
-
Advanced Options
是更精細化控制資源包構建與載入流程的選項,無特殊情況保持預設即可。需要注意的是Include in Build
選項,可以控制當前資源包是否參與本次構建。
-
Ⅱ. 總體配置
AddressableAssetSettings
負責整體配置資源包的構建引數。
設定資源包地址的Profiles
Profiles/Profiles In Use
控制了當前資源包路徑設定。
我們剛才對資源包的路徑進行了本地與遠端的設定,但是並沒有深入瞭解這些路徑是如何拼接而成的。比如為什麼本地資源包會在構建到StreamingAssets
資料夾中呢。
點選Manage Profiles
,彈出上圖的Addressables Profiles
皮膚,之前我們設定的本地路徑與遠端路徑就是在這裡定義的。總體上路徑由固定的字串、中括號與花括號組成,中括號內包含了釋出時編輯器所確定下來的變數,比如執行平臺等;花括號則包含了App執行時所獲取的變數,也可以在程式碼內手動指定一個自定義的變數。
這就解釋了為什麼我們將資源包指定為Local___Path
時,最終會存在於App的StreamingAssets
資料夾中,是因為[UnityEngine.AddressableAssets.Addressables.BuildPath]
這個地址就是編輯器釋出App時所指定目錄下的StreamingAssets
資料夾地址,而{UnityEngine.AddressableAssets.Addressables.RuntimePath}
這個地址則是App執行時的StreamingAssets
資料夾地址。
我們也可以新建一個測試用的Profile
和一個釋出用的Profile
,只需要把RemoteLoadPath
中的http地址指向測試用伺服器地址和正式版伺服器地址即可。
設定是否需要遠端更新
假如我們的App不需要進行遠端資源載入和更新,則保持Content Updata/Build Remote Catalog
不勾選即可,否則則需要將其勾選。
而Disable Catalog Update on Startup
則決定是否在App啟動時自動更新catalog。
假如我們希望App啟動時將所有的更新包先行下載下來,則可以將其勾選,並在程式碼中手動呼叫Addressables.InitializeAsync()
、Addressables.CheckForCatalogUpdates()
、Addressables.UpdateCatalogs()
等方法,獲取到需要更新的資源包列表,並對其依次進行手動更新。
假如我們希望在App執行中需要某個資源時才會去從遠端下載,則可以保持其不勾選的預設狀態。這種方式下Addressables
系統會在App啟動時自動呼叫上述的一系列方法將本地catalog與遠端同步,但是並不會更新資源包。
三、資源管理
-
將資源匯入工程中
-
此時
Inspector
皮膚上新新增了一個Addressable
選項。
將需要打包的資源勾選,出現一長串的資源路徑,這個路徑就是我們載入這個資源時所需要的路徑引數 -
點選
Select
按鈕,彈出資源組皮膚,剛新增的資源會位於預設組員組Default Local Group (Default)
中。
-
如果能保證不衝突的話,我們也可以將這個路徑手動簡化,或者讓編輯器自動對其進行簡化。在資源組皮膚右鍵資源並點選
Simplify Addressable Names
,可以將複雜的路徑簡化為不帶型別字尾的檔名,方便使用。
-
也可以為資源指定標籤。將一系列資源指定為同一個標籤後,則可以在App執行時將其以按標籤載入的方式同時載入進來。比如我們將工程中的Lua指令碼全部指定一個
Scripts
的標籤等。
四、構建資源包
Ⅰ. 首次構建
首次構建資源包需要點選資源組皮膚的Build/New Build/Default Build Script
。
打包成功後在AddressableAssetsData
資料夾下生成一個儲存當前資源狀態的bin檔案,這個檔案是後續資源增刪改時用來與前一次打包做對比用的,並且它儲存了至關重要的catalog檔案資訊。
同時在RemoteBuildPath
位置生成catalog以及遠端資源包。
此時我們可以隨即進行App的構建。
每次構建資源包,都需要重新構建App。
如果希望更新資源包,不能使用Build/New Build
方式。
Ⅱ. 更新包
將資源增刪改完畢之後,點選Tools/Check for Content Update Restrictions
。
選擇首次構建時生成的bin檔案,彈出Content Update Preview
皮膚,點選Apply Changes
。
我們這裡的預設資源組的
Content Update Restriction
選項設定的是Can not Change Post Release
,因為本地資源已經跟隨App一同釋出了,修改本地資源是沒有意義的,除非重新構建App。
編輯器替我們自動生成了新的遠端資源組,並將有變動的資源放了進去。
這裡不要混淆 遠端資源組 和 Content Update Restriction 兩個概念,遠端資源組既可以標記為不可修改,也可以標記為可修改。
我們可以把這些資源放到其他遠端組裡,也可以保持不變,這方面的策略應該顧及資源包的粒度,檔案大小等,嚴格執行起來還是比較燒腦的。
資源組重新設定完畢後,點選Build/Update a Previous Build
,並再次選擇首次構建時生成的bin檔案,以更新方式構建資源包。
切勿以
Build/New Build
的方式構建,如果不小心點了,兩個解決方式,git reset --hard
或者重新打包App……
此時開啟遠端構建目錄(RemoteBuildPath),發現已經生成了由新的遠端資源組構建的資源包,而catalog檔案的修改日期也已經發生了變化,說明雖然catalog檔名沒有發生變化,但是其內容已經更新了。
我這裡截圖的catalog檔名發生了變化,是寫文測試的時候把之前的構建結果給刪了,實際上應該是不會發生變化的,請忽略。o_0
我們允許的流程是:構建資源包->構建App->以更新方式構建資源包->以更新方式構建資源包...
我們不允許的流程是:...->構建App->構建資源包...
原因是每次點選Build/New Build/***
,catalog檔名都會發生變化,而App只記錄上一次構建資源包時的catalog檔名,假如我們在構建App之後重新構建了資源包,則舊的App無法識別新的catalog,從而更新失敗。
五、部署
將RemoteBuildPath
目錄下的檔案上傳至伺服器,包括資源包以及catalog檔案,保證RemoteLoadPath
可訪問即可。
實際部署還是比教程寫的要麻煩很多的。許可權,跨域,負載能力,加密,防止各種網路攻擊等,各種手段都要用上。我們僅僅是驗證技術路線,麻煩事就先不考慮啦。
如果僅僅是測試的話,其實編輯器還提供了一個Host功能
點選Create/LocalHosting
,新建一個服務端,指定埠,勾選Enable
即可。
注意我們需要將
Profiles/RemoteLoadPath
修改為http://本機IP或者localhost:埠號
,預設Profiles
的遠端載入地址多了一個[BuildTarget]
,這是訪問不到的。
六、載入
新建一個指令碼,用來測試資源的載入。
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.UI;
public class SwitchSprites : MonoBehaviour
{
[SerializeField] private RawImage _emojiImage;
[SerializeField] private Text _infoText;
private int _indicator;
private AsyncOperationHandle<IList<Texture>> _operation;
private async void Start()
{
_operation = Addressables.LoadAssetsAsync<Texture>("emoji", null);
await _operation.Task;
_infoText.text = "Emoji Load Completed";
GetComponent<Button>().onClick.AddListener(() =>
{
_indicator++;
if (_indicator >= _operation.Result.Count)
{
_indicator = 0;
}
_emojiImage.texture = _operation.Result[_indicator];
});
}
private void OnDestroy()
{
Addressables.Release(_operation);
}
}
這裡一上來直接就可以
Addressables.LoadAssetsAsync<Texture>()
,是因為我測試的時候沒有勾選AddressableAssetSettings/Content Update /Disable Catalog Update on Startup
,所以App在載入時自動更新了catalog,而資源包下載則類似於Lazy 模式
,即用即下載(快取中如果有匹配的資源包則直接載入)。真正使用這套系統時,一般會採用勤快一點的模式,先更新必要的資源包,讀條一波,然後App才正式執行。