版本管理
Versions 类主要负责运行时的资产版本管理,主要包含以下接口:
- Versions.InitializeAsync 初始化
- Versions.CheckUpdateAsync 检查更新
- Versions.GetDownloadSizeAsync 根据加载路径获取下载大小(支持使用别名和不带hash的包名)
- Versions.GetDownloadSizeAsyncWithManifest 根据清单的名字获取下载大小
- Versions.DownloadAsync 批量下载文件
- Versions.ClearAsync 清理资产
Versions.InitializeAsync
初始化主要用来加载版本文件,并根据版本文件加载版本文件相关的清单文件。
使用 xasset 的加载接口前,需要先执行初始化操作,初始化操作的内部过程是:
- 从安装包读取 versions.json 文件,放到临时目录。
- 根据安装包的 versions.json 文件把包内的清单文件按需读取到下载目录(下载目录没有才读取)。
- 读取下载目录的 versions.json 文件,从服务器下载而来,然后按需采集需要加载的清单文件。
- 使用自动分帧加载清单文件,减少卡顿。
如何进行初始化?以下使用协程初始化的代码示例:
private IEnumerator Start()
{
DontDestroyOnLoad(gameObject);
Versions.VerifyMode = verifyMode;
// 初始化前,需要先初始化自定义加载器。
var customLoader = GetComponent<CustomLoader>();
if (customLoader != null)
{
customLoader.Initialize();
}
var operation = Versions.InitializeAsync();
yield return operation;
}
除了使用协程外,初始化操作也还提供了 completed 事件,可以返回初始化结果,例如:
var operation = Versions.InitializeAsync();
operation.completed += o=> {
// TODO: 执行初始化完成后的流程
};
不想使用协程序和回调,需要使用 c# 的高级语法特性 await/async ?这样也没问题:
var operation = await Versions.InitializeAsync().Task;
Versions.CheckUpdateAsync
检查更新主要用来同步服务器的版本文件,xasset 使用版本文件管理清单的版本,又通过清单文件管理具体资产的版本,所以在获取最新的具体资产的更新大小前,需要先检查更新。检查更新的内部过程是:
- 下载服务器的 versions.json 文件,并通过 versions.json 文件获取需要更新的清单文件的大小。
- 如果有需要更新的清单文件,提示用户下载更新,如果没有则直接完成更新检查。
- 当用户确认下载更新的时候,启动下载更新的操作,下载完成后,自动装载所有已经更新的清单文件。
如何执行检查更新?请参考以下代码示例:
// 启动检查更新
var check = Versions.CheckUpdateAsync();
yield return check;
if (checking.status == OperationStatus.Failed)
{
MessageBox.Show("提示", "更新版本信息失败,请检测网络链接后重试。", ok =>
{
if (ok)
{
CheckUpdate(); // 重新启动更新检查
}
else
{
OnComplete();
}
}, "重试", "跳过");
yield break;
}
// 获取更新大小
var downloadSize = check.downloadSize;
// 有新版本需要更新,这里的内容比较小,可以直接启动下载。
// 但是,如果要支持使用旧版本的资产运行,则可以按需提示用户是否下载更新。
if (downloadSize > 0)
{
var download = check.DownloadAsync();
// 这里可以显示下载进度,可以参考 example 的示例中的 WelcomeScreen 的代码实现。
yield return download;
// 下载完成后,内部会自动状态已经下载好的版本信息。这里可以参考 example 中的代码处理网络异常的情况。
}
// 完成检查更新的操作。
检查更新的操作是异步的可以参考Versions.InitializeAsync接口的代码,使用协程、回调、await/async 等方式获取此操作的结果返回。
Versions.GetDownloadAsync
如果想在加载前获取需要更新的资产的大小,可以使用此接口来实现。以下是调用该接口的代码示例:
private IEnumerator GetDownloadSize()
{
var getDownloadSize = Versions.GetDownloadSizeAsync(assetNames);
yield return getDownloadSize;
if (getDownloadSize.changesSize > 0)
{
var messageBox = MessageBox.Show("提示",
$"发现更新({Utility.FormatBytes(getDownloadSize.changesSize)}),是否下载?",
null, "下载", "跳过");
yield return messageBox;
if (messageBox.ok)
{
StartDownload(getDownloadSize);
yield break;
}
}
OnComplete();
}
上面的接口的参数 assetNames 是可变参数,参数内容可以是一个或多个加载路径,也可以是加载路径的别名,还可以是不带哈希的包名。assetNames 可以在运行时动态组装,这主要是游戏的内容会随着时间轴的变化而变化,预先制作的东西具有一定时效性,传入一个动态列表更准确。例如,MMO游戏中,1级的角色和100级的角色在登入选服的过程中需要的资产是不同的,当老用户下载新安装包时,动态组装需要更新的内容,可以更有针对性的减少用户等待时间。
获取下载大小是本地操作无需消耗流量。
Versions.GetDownloadAsyncWithManifest
根据清单名字获取下载大小,用法和Versions.GetDownloadSizeAsync类似,只是参数内容是清单名字而不是资产名字。以下是调用该接口的代码示例:
var getDownloadSize = Versions.GetDownloadSizeAsyncWithManifest(manifest); // manifest = "Arts"
yield return getDownloadSize;
if (getDownloadSize.downloadSize <= 0)
{
MessageBox.Show("提示", "没有更新,是否重来", b =>
{
if (b)
{
Versions.ClearDownload();
StartUpdate();
}
});
yield break;
}
Versions.DownloadAsync
批量下载文件是一种一次下载多个文件的操作,在获取下载大小后,如果内容有更新,可以按需通过以下代码,启动下载:
private void DownloadAsync(GetDownloadSize getDownloadSize)
{
// 下载需要更新的内容
var downloadAsync = getDownloadSize.DownloadAsync();
// 显示下载进度
PreloadManager.Instance.ShowProgress(downloadAsync);
// 下载失败后提示用户,并在 3s 后会自动重试
StartCoroutine(Downloading(downloadAsync));
}
private IEnumerator Downloading(DownloadFiles downloadAsync)
{
yield return downloadAsync;
if (downloadAsync.status == OperationStatus.Failed)
{
var endTime = Time.realtimeSinceStartup + 3;
var messageBox = MessageBox.Show("提示!", "下载失败!3s 后自动重试");
while (messageBox.Visible)
{
var time = Math.Max(endTime - Time.realtimeSinceStartup, 0);
messageBox.SetContent($"下载失败!{time:0}s 后自动重试");
if (time <= 0)
{
messageBox.HandleEvent(true);
break;
}
yield return null;
}
if (messageBox.ok)
{
// 重试下载,内部实现是只针对下载失败的部分。
downloadAsync.Retry();
StartCoroutine(Downloading(downloadAsync));
}
}
}
Versions.ClearAsync
清理版本数据,不传参数等于清理不在当前版本的所有历史数据,传参数表示清理指定资产和依赖。
以下是调用该接口的代码示例:
public void ClearHistory()
{
MessageBox.Show("提示", "保留历史版本数据可以获得更快的更新体验,请确认是否清理?", ok =>
{
if (ok)
{
PreloadManager.Instance.ShowProgress(Versions.ClearAsync());
}
}, "清理", "退出");
}
Versions.UnpackAsync
解压二进制文件,此二进制文件通过打包配置的 Pack All Bundles To Binary 选项生成。对于一些不常更新的资产,可以把散文件合并后下载解压,减少IO次数,提高IO效率。以下是调用该接口的代码示例:
var unpackAsync = Versions.UnpackAsync(download.info.savePath);
unpackAsync.updated += (message, progress) =>
{
// 显示解压进度
PreloadManager.Instance.SetMessage($"解压中...{message}", progress);
};
unpackAsync.completed += operation =>
{
// 解压完成
PreloadManager.Instance.SetMessage("解压完成", 1);
PreloadManager.Instance.SetVisible(false);
};