Skip to main content
Version: 2023.1

版本更新

版本更新的流程主要包括以下部分:

  1. 获取更新信息
  2. 更新安装包
  3. 更新资产包版本文件
  4. 热重载和清理
  5. 更新资产包

获取更新信息

使用 Assets.GetUpdateInfoAsync 可以获取客户端的更新信息

xasset>Samples>Scripts>CheckForUpdates.cs:27
// 获取更新信息
var getUpdateInfoAsync = Assets.GetUpdateInfoAsync();
yield return getUpdateInfoAsync;

获取更新时,xasset 会根据 设置配置 文件的 Update Info URL 属性指定的地址下载更新信息到本地。 这里,也可以让控制服下方更新信息。这样可以更轻松地实现让客户端在不同的服务器使用不同的资产。

获取更新信息后,只有当获取更新信息的请求结果返回成功时,才需要进行以下流程的处理:

更新安装包

使用更新信息的版本号和安装包的版本号来判断是否是要去商店下载最新地安装包:

xasset>Samples>Scripts>CheckForUpdates.cs:32
// 强更检查
var updateVersion = System.Version.Parse(getUpdateInfoAsync.info.version);
var playerVersion = System.Version.Parse(Assets.PlayerAssets.version);
if (updateVersion.Major > playerVersion.Major || (updateVersion.Major == playerVersion.Major && updateVersion.Minor > playerVersion.Minor))
{
// 需要强更下载安装包。
var request = MessageBox.Show(Constants.Text.Tips,
string.Format(Constants.Text.TipsNewContent, updateVersion));
yield return request;
if (request.result == Request.Result.Success)
Application.OpenURL(getUpdateInfoAsync.info.playerURL);
Quit();
yield break;
}

这里默认使用版本号的中高位版本判断是否需要更新安装包,可以结合项目的实际需要调整。

更新资产包版本文件

使用 Assets.GetVersionsAsync 可以获取更新后的资产包清单版本文件。

xasset>Samples>Scripts>CheckForUpdates.cs:46
// 需要更新版本文件
var getVersionsAsync = Assets.GetVersionsAsync(getUpdateInfoAsync.info);
while (!getVersionsAsync.isDone)
{
var msg = $"{Constants.Text.UpdateVersions} {getVersionsAsync.progress * 100:f2}%";
LoadingScreen.Instance.SetProgress(msg, getVersionsAsync.progress);
yield return null;
}

热重载和清理

资产包版本文件更新完成后,需要使用 Assets.ReloadAsync 进行热重载处理后,才能使用 xasset 的 API 加载到新版本的资产,同时,已经加载的资产,也会在底层被替换为更新后的资产。

如果想要清理旧版本下载目录的文件,可以在重载前使用 Assets.GetFilesWithoutVersions 获取不在新版本中的文件,等重载完成后,发起删除文件的请求,对这些文件进行清理。

xasset>Samples>Scripts>CheckForUpdates.cs:74
private IEnumerator ClearingAndReloading()
{
// 读取不在新版本的文件
var unusedFiles = Assets.GetFilesWithoutVersions(versions);
// 重载已经加载的旧资产
var reloadAsync = Assets.ReloadAsync(versions);
while (!reloadAsync.isDone)
{
var msg = $"{Constants.Text.Loading}({reloadAsync.pos}/{reloadAsync.max}) {reloadAsync.progress * 100:f2}%";
LoadingScreen.Instance.SetProgress(msg, reloadAsync.progress);
yield return null;
}

// 清理历史文件
var removeAsync = new RemoveRequest();
foreach (var file in unusedFiles)
{
var path = Assets.GetDownloadDataPath(file);
removeAsync.files.Add(path);
}

removeAsync.SendRequest();
while (!removeAsync.isDone)
{
var msg = $"{Constants.Text.Clearing}({removeAsync.current}/{removeAsync.max})";
LoadingScreen.Instance.SetProgress(msg, removeAsync.progress);
yield return null;
}

UpdateVersion();
}

需要注意的是,只有服务器版本和客户端版本不同时才需要进行热重载和清理操作。下面的代码中,versions 是服务器版本,Assets.Versions 是客户端版本。

xasset>Samples>Scripts>CheckForUpdates.cs:63
if (versions.IsNew(Assets.Versions))
{
yield return ClearingAndReloading();
}

在 xasset 的示例中,热重载和清理操作放在了首次更新资产包的操作完成后,这样可以避免更新操作中途退出重启客户端后,出现直接加载服务器的资产的情况。

更新资产内容

更新资产内容的操作主要包括:

  1. 收集需要更新的数据
  2. 获取需要更新的内容大小
  3. 下载需要更新的内容
  4. 显示下载进度
  5. 下载失败,提示重试

以下是相关操作的代码示例。

xasset>Samples>Scripts>CheckForUpdates.cs:106
private IEnumerator DownloadAssets()
{
// 1. 收集需要更新的数据
var assets = new List<string>();
foreach (var ver in versions.data)
{
foreach (var group in ver.manifest.groups)
{
// 对交付模式为 install-time、fast-follow 和更新过的 on-demand 的分组资产进行更新检查
if (group.deliveryMode == DeliveryMode.InstallTime ||
group.deliveryMode == DeliveryMode.FastFollow)
{
assets.Add(group.name);
}
else
{
var bundles = group.manifest.bundles;
if (group.assets.Exists(o=> Assets.IsDownloaded(bundles[o.id])))
{
assets.Add(group.name);
}
}
}
}
// 2. 获取需要更新的内容大小
var getDownloadSizeAsync = versions.GetDownloadSizeAsync(assets.ToArray());
yield return getDownloadSizeAsync;
if (getDownloadSizeAsync.downloadSize > 0)
{
// 3. 下载需要更新的内容
_downloadAsync = Assets.DownloadAsync(getDownloadSizeAsync.GetUpdatedContents());
while (_downloadAsync.result != DownloadRequestBase.Result.Success)
{
// 4. 显示下载进度
var downloadedBytes = Utility.FormatBytes(_downloadAsync.downloadedBytes);
var downloadSize = Utility.FormatBytes(_downloadAsync.downloadSize);
var bandwidth = Utility.FormatBytes(_downloadAsync.bandwidth);
var msg = $"{Constants.Text.Loading}{downloadedBytes}/{downloadSize}, {bandwidth}/s";
LoadingScreen.Instance.SetProgress(msg, _downloadAsync.progress);
yield return null;
if (!_downloadAsync.isDone || string.IsNullOrEmpty(_downloadAsync.error)) continue;
// 5. 下载失败,提示重试
var retry = MessageBox.Show(Constants.Text.Tips, Constants.Text.TipsDownloadFailed);
yield return retry;
if (retry.result == Request.Result.Success) _downloadAsync.Retry();
else break;
}
}
}

在使用 Assets.GetDownloadSizeAsync 获取更新大小时,可以使用 Build Group 的名字、资产路径、资产目录等多个参数来检查对应内容的更新状态。如果什么参数都不传,表示针对所有资产内容进行一次更新状态检查。

同时,当一个资产被投放到多个 Build Group,尽管最终打包时,资产不会重复打包到多个文件中,但是,在更新时,只要 Build Group 的 Assets 中有被投放的资产,那么都可以使用这个 Build Group 的名字获取到被投放的资产的更新状态。