Unity资源热更-Addressables总结

Posted 一脸懵逼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity资源热更-Addressables总结相关的知识,希望对你有一定的参考价值。

Addressables是Unity官方推出的用于资源热更的系统,可在Package Manager里面下载,我这里分两部分讲解,第一部分是操作入门,第二部分是代码编程以及注意事项

一、入门

选择合适的Addressables版本下载安装完成后,选择Groups

 点击Create Addressables Settings

它会默认给你创建一个本地的Group,选中这个Group,可以在Inspector面板看到如下图示:

​​​​​​​

 这五个红框是我会经常设置的地方(从上到下):

1.点击之后会跳转到Settings面板,Settings面板等会讲

2.更新形式,一种是Can,一种是Cannot,这两种的更新操作会有些区别,Unity官方是建议将用作增量更新的AB包使用Cannot形式,比如有一些ab包是要放进App的包体里的,这时候我们一般第三个框会选择Local,也就是说这个Group下的资源会被打包成ab包然后在build app的时候,会复制到我们的StreamingAssets文件夹里,这样如果这些ab包里面有资源要更新,那么就可以操作将这些资源导出来放到一个新的Group里来进行热更(至于怎么操作,等会会在更新环节讲)

3.Local or Remote,如果是选择Remote的话,那么你还需要到Addressables Profiles里去设置你的远程资源地址,Remote.BuildPath我们通常不改,一般只改Remote.LoadPath,即使用你自己的资源服务器地址

 4.这里我通常会勾上

5.Cache Clear Behavior:这里如果是Local的话我一般用默认第一个,如果是Remote的话,我通常会选择第二个,第二个意思就是如果有资源更新了,加载了新资源的时候就会把本地的旧资源删除掉,自测很好用,避免本地下载的旧资源堆积太多 

Bundle Mode:我个人喜欢分开打包,这样的好处就是如果只是一个很小的资源需要热更,那么下载的时候就只需要下载这个小资源,不用下载很多不必要的资源,对用户体验会比较好

接下来是Addressables Settings面板:

 这四个红框是我会修改的地方(从上到下):

1.通过设置不同的Profiles,我们可以管理不同资源服务器的下载,比如内网、审核服、外网等等

2.Disable Catalog Update on Startup:这个勾选的话是说这个catalog不要在应用启动的时候就自动更新,等我们到了主界面,点击屏幕再更新,看看是否有更新,这个catalog保存的就是我们的资源信息,一般要做这种需要玩家确认下载的时候我会勾选这个,我也尝试过不勾选然后做无感更新也是可以的,即在App运行过程中有资源更新了,不需要退出再重新打开App或者返回主界面再更新,可以直接后台更新,然后再加载这个资源就是最新的资源了

3.这个我通常会勾选,如果是想加载远程的资源,path选Remote,如果是只想加载local group里的资源(即放在StreamingAssets),没有加载远程资源的需求,选择Local即可

4.初始化Objects,这里我通常会右键Create一个Cache Initialization Settings,改好之后放到这里面

 

然后就是Cache Directory Override这一栏填上UnityEngine.Application.persistentDataPath,相信了解这个地址的同学知道它的含义,简单来说这个地址就是用来热更的,这样可以方便我们管理资源,否则Addressables会将资源下载到另外一个缓存文件夹里

 这些都设置好了之后,就是更新的操作了,接下来是一个示例:

我们先随便在场景里创建一个cube,然后让它变成一个prefab 

 再随手创建两个材质球,一个红色一个黄色,将红色材质球拖给Cube,通过改变这个cube的材质球来对它进行热更

1.勾选Build Remote Catalog,取消勾选Disable Catalog Update on Startup,取消之后这样每当我们重新打开App,调用Addressables.InstantiateAsync生成这个Cube的时候Addressables都会先检查catalog更新然后下载最新的Cube到本地,最终在场景里生成最新的Cube

 2.将Cube拖到这个默认的Group下,然后单击或者右键选择下图简化名字,这个Name:"Cube"就是我们之后使用Addressables API加载Cube需要传入的参数名

 3.Group设置里选择Remote,红框里使用你自己的资源服务器地址,在Addressables Profiles里设置

 4.点击Build->New Build->Default Build Script,Unity会自动为我们将资源打出成ab包

 5.在Assets同级的ServerData里面,可以找到打出来的ab包

 大概有这些文件:

.hash文件内容是.json文件的md5 ,一般更新的时候都是先对比这个md5有没有发生改变,有再比对.json里面的内容,最终确定要下载的资源

然后将这些资源放到我们的资源服务器上

6.接着在工程的场景里随便创建一个GameObject,再随便创建一个脚本,在Start方法里只做一件事,那就是输入这行代码:

Addressables.InstantiateAsync("Cube");  

这个方法会生成最新的Cube,编译好了build and run一个exe,你就能在场景里看到这个红色的Cube了

7.接下来我们把yellow材质球拖给Cube,如图

 然后我们对这个黄色Cube打包

 这里需要注意,当我们选择的更新形式是Can Change Post Release时,我们就采用上图的Update a Previous Build,然后选择你对应平台里的addressables_content_state.bin文件就可以打出新的ab包了

如果是Cannot,那我们就需要点击Tools->Check for Content Update Restrictions,它会生成一个新的Group,如下图:

再执行Update a Previous Build,然后选择你对应平台里的addressables_content_state.bin文件才可以打出新的ab包

 8.我这里采用的是Can Change Post Release方式,再把这些资源都上传到资源服务器

重新打开exe,是不是变成了黄色了?到这里相信你们对这个操作流程就熟悉了,至于一些高阶的用法,我会在下一章详细讲解

游戏开发探究Unity Addressables资源管理方式用起来太爽了,资源打包加载热更变得如此轻松(Addressable Asset System | 简称AA)

一、前言

嗨,大家好,我是新发。
之前就有看过UnityAddressable Asset System,简称AA,但那时候这个功能刚出来,出于稳定性考虑,所以暂时没有去使用它。现在,它已经迭代到1.16.19 Release版本了(中国版是1.19.16),经过了时间考验,可以拿出来讲讲啦,网上其实已经有不少讲Addressables系统的文章,不过很多不是最新版的教程,今天我就来写一下最新版的Addressables系统的使用教程吧~

二、为什么推荐使用Addressables

我在之前的好几篇文章中都介绍过Unity加载资源的几种方式,我还画过一个图,详细可以看我之前写的这篇文章:《Unity游戏开发——新发教你做游戏(三):3种资源加载方式》

可以看出来,资源的加载方式要根据应用场景进行区分,要注意资源存放的文件夹,要注意不同平台下的差异,如果使用AssetBundle形式,加载的时候要小心AB包之间的依赖关系,我之前也写了一篇文章讲如何去加载AB的依赖资源,《Unity 打包与加载AssetBundle(加载对应的依赖)》
如果要做资源热更新,也要自己去写工具实现增量资源包的打包,然后自己实现热更检测、资源下载、MD5比对,解压等等逻辑,我之前还专门写了一篇文章讲了热更新的流程,《【游戏开发高阶】从零到一教你Unity使用ToLua实现热更新(含Demo工程 | LuaFramework | 增量 | HotUpdate)》

相信你看完我的这些文章,就会吐槽,哇,好麻烦啊,对于新手来说,可能就是劝退,现在呢,不用怕了,Addressables系统统统搞定,用起来实在是太香了,本博主强烈推荐!

三、Addressables基础操作教程

1、下载Addressables插件

点击菜单Window / Package Manager,打开插件包管理界面,

搜索addressables,可以看到有两个插件包,带.CN结尾的是中国增强版,

这里要补充说一下,Addressables的打包方式其实也是AssetBundle格式,只是在此基础上做了一层封装,方便进行管理(比如打包、加载、依赖等)。而我们知道,没有加密的AssetBundle是可以使用AssetStudio等工具轻易进行资源逆向的,

注:AssetStudio资源逆向工具开源地址:https://github.com/Perfare/AssetStudio

Addressables.CN版本会对AssetBundle做加密处理,

为了方便下文演示资源逆向,我这里就先下载不带.CN结尾的版本,

注:实际项目中,建议大家下载Addressables.CN版本。

安装成功后,可以看到多出了一个Window / Asset Management / Addressables菜单,

2、创建Addressables Settings

点击Groups菜单,

点击Create Addressables Settings按钮,

此时工程目录中会生成一个AddressableAssetsData文件夹,里面有很多设置文件,

我们看回Addressables Groups窗口,可以看到它默认创建了一个组:Default Local Group (Default)

Addressables默认是按Group为颗粒进行AssetBundle打包的,比如我把资源A、B、C都放在这个Default Local Group组里,那么它们会被打在同一个AssetBundle中(我们也可以修改成按单独的资源文件为颗粒进行打包,下文我会讲如何设置),下面我演示一下如何给Group添加资源。

3、给Group添加资源

我这里先随便制作两个预设,


放在Prefabs文件夹中,

文件名字可以任意起,注意不要跟Unity默认的文件系统文件夹名字相同,比如ResourcesStreamingAssets等,除非你真的是想使用这些特定目录的功能,

接着我们把预设文件直接拖到对应的Group中即可,如下,

注:我演示的是预设资源,你也可以是其他任意的资源,比如声音、图集、动画、材质等等)

选中资源文件,在Inspector窗口中勾选Addressable,它也会自动添加到默认的Group中,如下

4、创建新的Group

上面的默认Group一般是作为包内资源,现在我们创建一个新的Group作为包外资源的组(通过远程加载资源)。
如下,在Addressables Groups窗口中,点击左上角的Create按钮,点击Group / Packed Assets菜单,

此时会创建一个新的Group,如下,

我们右键它,可以对它进行重命名,

这里我就将其重命名为RemoteGroup吧,

其实每个Group都是一个配置文件,可以在AddressableAssetsData / AssetGroups目录中找到对应的文件,如下

如果你用文本编辑器打开它,就会看到它里面是YAML格式的配置,比如打开Default Local Group,可以看到它里面记录了包含的资源文件,

继续我们的操作,下面我们给这个RemoteGroup添加资源,我找了一张柯南的图片,

把柯南图片拖到RemoteGroup中,如下,

现在RemoteGroup如何打成一个包体外的资源包呢?又如何去加载这些Group资源包呢?请继续往下看~

5、设置Build Path与Load Path

我们选中RemoteGroup,在Inspector窗口中,将Build Path改为RemoteBuildPath,将Load Path改为RemoteLoadPath,如下,

这样子,RemoteGroup打出来的资源就不会在包体内了,它会被打到工程目录的ServerData/Android目录中,

而加载的时候,会去远程http://localhost/Android这个地址加载(这里是localhost,我们可以改成别的IP或域名地址)

画个图

6、修改RemoteBuildPath和RemoteLoadPath

如果你想修改RemoteBuildPathRemoteLoadPath,可以在Addressables Groups窗口中点击Manage Profiles菜单,

也可以点Window / Asset Management /Addressables / Profiles菜单,

此时会打开Addressables Profiles窗口,我们可以修改修改RemoteBuildPathRemoteLoadPath

这里我先不修改,下文搭建Web服务器后再来改RemoteLoadPath

7、打Addressable资源包

Addressables Groups窗口中,点击Build / New Build / Default Build Script,就会开始打Addressable资源包了,等它打包完毕即可,

上文中我们建了两个Group,其中Default Local Group作为包体内的资源包,RemoteGroup作为包体外的资源包,

现在我们去看看它们分别Build到哪里去了吧~
首先看下Default Local Group,可以看到它的Build Path是在Library/com.unity.addressables/aa/Android/Android中,

我们进如到这个目录中,可以看到对应的.bundle文件,

其实它就是一个AssetBundle格式的文件,我们可以使用AssetStudio对它进行逆向,可以看到逆向后,里面正是我们上文中添加的两个预设文件,

接着我们看下Remote Group打出来的资源包,它是在ServerData/Android目录中,

我进入工程目录的ServerData/Android目录中,可以看到RemoteGroup的资源包,
画个图

同样使用AssetStudio对它进行逆向,可以看到我们的柯南就在里面~

8、打Android APK

现在,我们打个AndroidAPK包看看,

正常打出APK

我们把.apk改为.zip,然后使用7z等解压工具解压它,

进入文件夹里面asset/aa/Android目录,可以看到我们的Default Local Group资源包就在里面,

没错,其实Unity就是把整个Library/com.unity.addressables/aa/Android目录塞到包内的assets/aa目录中,

我们的RemoteGroup因为是远程资源包,它被留在了工程目录的ServerData/Android中,没有进入包体内,

好了,现在Addressable包也打了,APK包也打了,还没讲如何加载资源,接下来就来讲讲如何加载Addressable资源吧~

9、加载Addressable资源

我们创建一个C#脚本,我这里就创建一个Main.cs脚本吧,

9.1、方式一:通过Addressable Name来加载资源

我们加载资源的时候,并不需要知道目标资源到底是在哪个Group中,也不需要知道这个Group到底是本地资源包还是远程资源包,统一通过资源的Addressable Name来加载,资源的Addressable Name在哪里看呢?
比如Cube预设,在Inspector窗口中,可以看到它的Addressable NameAssets/Prefabs/Cube.prefab,这个Addressable Name默认是资源被加入Group时的相对路径,

我们可以修改Addressable Name,比如我改成HelloCube也是可以的,它仅仅是作为一个索引的字符串,当我们把Cube预设移动到其他的目录中,这个Addressable地址并不会变,

这里我们还是保持为Assets/Prefabs/Cube.prefab吧,

开始写代码,首先引入命名空间

using UnityEngine.AddressableAssets;

然后使用Addressables.LoadAssetAsync接口进行资源,监听Completed回调中,在回调中拿到资源然后进行操作,示例:

using UnityEngine;
using UnityEngine.AddressableAssets;

public class Main : MonoBehaviour

    void Start()
    
        Addressables.LoadAssetAsync<GameObject>("Assets/Prefabs/Cube.prefab").Completed += (obj) =>
        
            // 预设物体
            GameObject prefabObj = obj.Result;
            // 实例化
            GameObject cubeObj = Instantiate(prefabObj);
        ;
    

Addressables还提供了InstantiateAsync接口,方便直接一步到位实例化,示例:

Addressables.InstantiateAsync("Assets/Prefabs/Cube.prefab").Completed += (obj) =>

    // 已实例化的物体
    GameObject cubeObj = obj.Result;
;

有些人可能不喜欢使用回调的方式,喜欢使用asyncawait的方式,示例:

using UnityEngine;
using UnityEngine.AddressableAssets;
using System.Threading.Tasks;

public class Main : MonoBehaviour

    void Start()
    
        InstantiateCube();
    
	
	private async void InstantiateCube()
	
		// 虽然这里使用了Task,但并没有使用多线程
		GameObject prefabObj = await Addressables.LoadAssetAsync<GameObject>("Assets/Prefabs/Cube.prefab").Task;
		// 实例化
		GameObject cubeObj = Instantiate(prefabObj);
		
		// 也可直接使用InstantiateAsync方法
		// GameObject cubeObj = await Addressables.InstantiateAsync("Assets/Prefabs/Cube.prefab").Task;
	

我们把Main.cs脚本挂到Main Camera相机上,

运行Unity,可以看到,正常加载了Cube并实例化了,

我们顺便测试一下把CubeAddressable Name改为HelloCube

加载的代码也改下,

运行测试,可以看到,依然可以正常加载Cube

这个时候,应该有同学会疑惑了,我改了Addressable Name,但我都没有重新Build资源包,怎么可以正常加载到资源呢?其实Addressables系统为了方便我们在Editor环境下方便测试,默认都是直接从Asset Database加载的,我们可以在Addressables Groups窗口的Play Mode Script中进行切换,建议编辑器环境下使用Use Asset Database (fastest)即可,下面两个选项下文我会讲具体使用,这里先维持原样~

9.2、方式二:通过AssetReference来加载资源

我们知道,脚本中如果声明了一个public变量,默认会进行序列化,可以在Inspector窗口中对它进行设置,我们声明一个publicAssetReference成员,如下,

// Asset弱引用
public AssetReference spherePrefabRef;

我们把Sphere预设拖给这个spherePrefabRef成员,

如果我们声明的不是AssetReference类型,而是GameObject类型,那么场景就直接依赖了Sphere预设,这个Sphere预设会被打到场景中,但我们这里用的是AssetReference,场景并不会真的依赖Sphere预设,它是一个弱引用。
好了我们继续,我们使用AssetReferenceLoadAssetAsync方法进行异步加载,监听Completed回调,如下

using UnityEngine;
using UnityEngine.AddressableAssets;

public class Main : MonoBehaviour

    public AssetReference spherePrefabRef;

    void Start()
    
        spherePrefabRef.LoadAssetAsync<GameObject>().Completed += (obj) =>
        
            // 预设
            GameObject spherePrefab = obj.Result;
            // 实例化
            GameObject sphereObj = Instantiate(spherePrefab);
        ;
    

同样,AssetReference也提供了InstantiateAsync方法,方便一步到位进行实例化,例,

spherePrefabRef.InstantiateAsync().Completed += (obj) =>

    // 已实例化的物体
    GameObject sphereObj = obj.Result;
;

我们运行Unity,测试效果如下,可以看到球体预设正常被加载并实例化了,

10、Addressable资源三个加载模式

Addressables资源加载模式有三个,如下,默认情况下是Use Asset Database (fastest)

Use Asset Database (fastest) 直接加载文件而不打包,快速但Profiler获取的信息较少
Simulate Groups (advanced) 在不打包的情况下模拟AssetBundle的操作
Use Exising Build(requires built groups) 实际上是从AssetBundle打包和加载

10.1、Use Asset Database (fastest)

在这个模式下,Addressables系统会直接从AssetDatabase加载资源,我们 不需要 BuildAddressable资源包,这个加载速度最快,建议在项目开发阶段使用这个模式,加载速度快。

10.2、Simulate Groups (advanced)

这个模式下,也是 不需要 BuildAddressable资源包的,那它与Use Asset Database (fastest)有什么区别呢?
让我先来操作一波,首先,我们选中AddressableAssetSettings,然后勾选Send Profiler Events,勾选之后,我们可以在Addressable的分析面板中查看到一些调试信息,

我们点击菜单Window / Asset Management / Addressables / Event Viewer,打开分析器,

我们运行Unity,在分析器中可以看到我们实例化出来的预设所依赖的资源,还可以看到引用计数等信息,虽然我们没有打出AssetBundle包,但却模拟了类似从AssetBundle包中加载资源的效果,这样可以方便我们快速分析加载策略,

我们对比一下,如果我切换为Use Asset Database (fastest)模式,看,资源加载、依赖、引用等相关信息都没有了,

结论就是Simulate Groups (advanced)会进行AssetBundle加载的模拟,并统计分析数据,方便我们进行快速分析,它并不是真的去加载AssetBundle,所以我们不需要执行Build操作。

10.3、Use Exising Build(requires built groups)

这个模式下,需要先执行Build打出Addressable资源包,它会根据Load Path去加载真正的AssetBundle文件并读取资源。如果不先Build,运行时会报错,

Player content must be built before entering play mode with packed data.  
This can be done from the Addressables window in the Build->Build Player Content menu command.
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

如下

如果执行了Build打出了Addressable资源包,但是把.bundle包手动删掉,运行Unity也会报错,

Exception encountered in operation
Resource<IAssetBundleResource>(xxxxxxxxxxxxx.bundle), status=Failed, result= : Invalid path in AssetBundleProvider:
...

如下:

我们执行一下Build / New Build / Default Build Script,打出Addressable资源包,

运行Unity,可以正常从Addressable.bundle资源包中加载资源,如下

在这个模式下,我们也是可以在Event Viewer窗口中对资源加载进行分析的,

11、加载远程Addressable资源

我们上面的Remote Group是打成包外资源的,我们想要在Editor环境下测试远程加载,这个时候就需要先搭建一个Web服务器了,支持通过http请求来获取资源。Addressable系统已经帮我们做了一个Hosting Services工具,方便我们快速启动一个Web服务器。

11.1、启用Hosting Services

点击菜单Window / Asset Management / Addressables / Hosting

接着点击Create / Local Hosting,创建一个本地Web服务器,

然后勾选Enable

这样我们就开启了一个本地的服务器了,IP地址是我本机的局域网IP,我可以通过localhost进行访问,注意这里的端口号是62762
我们可以看到,它对我们上文中提到的两个文件夹目录进行了Hosting

11.2、加载远程包的柯南图片

因为我们上面已经指向过Build打了资源包,所以这里我们就直接写加载资源的代码吧。
我们改一下Main.cs脚本,让它去加载柯南的图片,我们知道,柯南图片在Remote Group组里,它是在包外的,但我们代码上并不用管它到底是包内还是包外,我们使用Addressable Name来加载,柯南图片的Addressable NameAssets/Textures/kenan.jpg

上代码,

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.UI;

public class Main : MonoBehaviour

    public RawImage img;
    void Start()
    
       	Addressables.LoadAssetAsync<Texture2D>("Assets/Textures/kenan.jpg").Completed += (obj) =>
        
            // 图片
            Texture2D tex2D = obj.Result;
            img.texture = tex2D;
            img.GetComponent<RectTransform>().sizeDelta = new Vector2(tex2D.width, tex2D.height);
        ;
    

使用UGUI创建一张RawImage,并赋值给Main脚本的img成员,如下,

运行Unity,效果如下,可以看到,成功加载了远程资源,

注:如果你是win11系统,可能使用Hosting Services会无法访问,具体原因不明,win11各种恶心的问题,放弃治疗,把资源放到https服务器可以正常加载。

11.3、Addressables是如何知道去哪里加载资源的

假设我现在把资源托管到GitCode上,我把RemoteLoadPath改为GitCode的地址,如下

然后我执行AddressablesBuild打出资源包,如下是RemoteGroup资源包,里面包含了柯南的图片,

我们把它丢到GitCode上,如下

我运行Unity,可以看到,它从GitCode上正常加载了柯南的图片,

如何证明它是从GitCode上下载下来的呢?我们把工程里的柯南图片删了,

ServerData/Android目录中的RemoteGroup.bundle包也删了,

由于我们已经运行过一次,远程的资源会在本地缓存,我们使用Everythine搜索一下.bundle文件的那串哈希值,可以看到一个同名的文件夹,我们进入里面,

可以看到有个__data文件,它就是.bundle的缓存文件,柯南就在里面,我们可以使用AssetStudio__data进行逆向,看到了吗,我们的柯南又出现了,

好,我们把缓存也干掉,

这个时候,我们再运行一下Unity,柯南又重新加载出来了,并且刚刚的缓存目录又出现了,
它是从GitCode上加载并缓存到本地的。
我们通过Assets/Textures/kenan.jpg这个Addressable Name就可以加载到GitCode的柯南图片,这个对应关系是记录在哪里的呢?答案就在catalog.json文件中,这个文件我们在上文中解APK包的时候也有看到,事实上整个aa/Android目录下的文件都会塞入APKassets目录中,

我们打开它,可以看到我们配置的GitCode地址就在里面,

11.4、打个APK包瞧瞧

我们发布成APK,在Android模拟器中去看看效果,

运行,效果如下

我们打开文件管理器,进入Android/data/包名/files目录中,可以看到有个UnityCache文件夹,

继续往里走,那串熟悉的哈希值又出现了,它就是我们放在GitCode上的RemoteGroup.bundle文件的哈希值,它被下载到本地缓存在这个目录中,
我们继续进入,里面的__data文件就是.bundle文件本君,柯南就在里面,

12、如何把Group里的资源打成多个bundle文件

我们如果继续给RemoteGroup添加资源,比如我们再放一张小兰的图片,

把柯南小兰都放在RemoteGroup组里,

这个时候我们执行Addressable资源打包,柯南和小兰是在同一个.bundle文件中的,

AssetStudio逆向验证一下,嗯,他们是在一起的,

假设这个.bundle文件还包含了好多好多其他的资源,

以上是关于Unity资源热更-Addressables总结的主要内容,如果未能解决你的问题,请参考以下文章

游戏开发探究Unity Addressables资源管理方式用起来太爽了,资源打包加载热更变得如此轻松(Addressable Asset System | 简称AA)

游戏开发探究Unity Addressables资源管理方式用起来太爽了,资源打包加载热更变得如此轻松(Addressable Asset System | 简称AA)

游戏开发探究Unity Addressables资源管理方式用起来太爽了,资源打包加载热更变得如此轻松(Addressable Asset System | 简称AA)

HybridCLR+Addressables资源代码全热更框架 二

unity 代码热更+资源管理框架总结

Unity3D资源异步加载——Addressables资源异步加载