前言

这阵子终于有空来整框架相关的内容了,目前处理到资源管理相关,自然还是选择我们的老朋友xAsset,简洁强大的资源管理框架!老版本的xAsset(4.0)我也写过一篇入门笔记,前阵子它发布了7.0版本

对比上一个开源版本(4.x),7.0 最大的变化是:

  • 编辑器和运行时高度剥离,代码结构更精炼和模块化。
  • 使用只读的物理文件数据进行版本管理,版本检测稳定性和效率得到前所未有的提高。
  • 打包后的文件的文件名自带文件内容的版本信息,天生可以避免CDN缓存问题以及一些其他的冲突。
  • 全新的多线程文件下载组件,真机环境比之前 UnityWebRequest 版本更稳定。
  • 自动分帧机制为程序运行的流畅度提供保障。
  • 加载资源默认支持自动更新。
  • 相对详细的官方文档

今天就来学习下

正文

下载

xAsset地址,也是本文写作时的Commit版本:https://github.com/xasset/xasset/commit/69f04a06e4a900ce1f77f46e7a494fd19037c579

下载好之后直接将其中的Versions和Versions.Example放到项目根目录即可。

起点

为了学习一个框架我习惯于从入口处扩散性学习。所以来到Startup场景,可以看到两个老朋友

  • Startup是整个热更的入口
  • Updater负责具体的资源热更新/资源加载逻辑的驱动

Startup

Startup是整个热更的入口,自然肩负起配置和环境的初始化操作,Start方法中第一个就是我们的核心API之一——Versions.InitializeAsync

Versions.InitializeAsync

官方文档解释为:

初始化主要用来完成平台路径的设置以及母包的清单文件的加载。注:在使用其他运行时API前,请先确保系统以及正常初始化了。

从代码我们可以看到将下载地址传到进InitializeAsync方法,其调用堆栈如下

1
2
3
4
5
6
7
8
//外部调用接口,用于开启初始化流程
------> InitializeAsync
//初始化绑定一些方法,最主要的作用是根据平台来初始化将要在接下来的热更和正式游戏流程要用到的路径
------> InitializeOnLoad
//初始化/读取本地的PlayerSettings文件,读取其随包发布资源的名单以及是否开启离线模式
//值得注意的是,可以直接将本地的Settings中的scriptPlayMode设置为非Incremental模式来保证不会发生热更行为
//然后初始化本地的Manifest文件和ManifestVersion文件
------> InitializeVersions.Start ------> InitializeVersions.Update

有些同学看到这里可能已经有些困惑了,具体怎么初始化的,没看到相关操作啊,这其实也是我们平时看框架会遇到的问题,看到某个点就看不懂了,这时候就需要跳出来细节,针对这一块宏观来看,也就是去总结这部分的架构

我们可以看到,在XAsset7.0中所有的可加载/更新对象都继承自Loadable这个基类,而Loadable自身又有一套生命周期,可以被子类们重写,具体来说就是

1
OnLoad----->OnUpdate----->OnComplete----->OnUnload----->OnUnused

此时将目光转回InitializeVersions.Start方法,定位到

1
2
3
4
5
6
7
8
9
10
11
12
13
asset = ManifestAsset.LoadAsync(file, true); -----> ManifestAsset.Load(); ------> ManifestAsset.OnLoad();

/// ManifestAsset.OnLoad ///
protected override void OnLoad()
{
asset = ScriptableObject.CreateInstance<Manifest>();
asset.name = name;
pathOrURL = builtin ? Versions.GetPlayerDataURL(name) : Versions.GetDownloadURL(name);
var file = Manifest.GetVersionFile(name);
var url = builtin ? Versions.GetPlayerDataURL(file) : Versions.GetDownloadURL(file);
DownloadAsync(url, GetTemporaryPath(file));
status = LoadableStatus.CheckVersion;
}

是不是一切都明朗起来了呢?

我们这个Manifest文件是从本地读的,所以builtin为true,会直接读本地的Manifest,而不会去服务器进行下载

我们把目光转回InitializeVersions,可以看到它有一个Update函数,这个Update函数里调用了ManifestAsset.Override, 而这个ManifestAsset.Override就会根据ManifestAsset的builtIn是否为true来决定是否要从云端服务器下载更新Manifest的版本信息文件(即ManifestVersion),如果builtIn为true,则直接从本地的Application.streamingAssetsPath目录读取ManifestVersion

值得注意的是,InitializeVersions继承了一个Operation基类,这也是一块重要的内容,类似Loadable,他也包含一套自己的生命周期

Versions.UpdateAsync

接着往下走会来到Versions.UpdateAsync(operation.file),也是去Load ManifestAsset的,与上面唯一不同的是,这里builtIn参数传递的是false,也就是说会从云端服务器拉取更新,并且全量替换本地的Manifest和ManifestVersion文件

WelcomeScreen

到这里其实就是正式的资源热更流程了,通过在Startup获取的Manifest文件来与本地已有的文件进行对比,得到下载列表进行下载,这部分没什么好说的,主要来说一下资源加载流程

Asset.LoadAsync

1
LoadInternal -----> Asset.OnLoad -----> Dependencies.OnLoad -----> Dependencies.OnCompleted -----> Asset.OnCompleted

资源打包

开源版本的资源打包模块相当简洁,通过Unity自带的AB Label进行打包,冗余查找和优化甚至不如4.0到位,不过也可以理解,毕竟是体验版,订阅版的看官方文档介绍似乎很完善

总结

个人感觉7.0版本的开源版除了多线程下载和版本管理比较出彩以外,其余感觉中规中矩,目前个人选择仍然是4.0版本。

既然xAsset选择了商业化路线,那么他所做的一切都可以被市场所理解,究竟能走多远,又会不会步乐变的后尘,我们拭目以待。

最后多说一句,可以多关注下Unity官方的Addressable方案,毕竟官方背书。