微信资源缓存
微信小游戏切断了JS文件系统和IndexDB的同步,以避免大量文件同步带来的卡顿问题。因此所有通过C# 文件IO保存的文件只会在内存中存在,而不会同步到持久化存储中。在游戏退出后,内存中的文件都会被释放。 微信提供了两种方式来持久化存储文件:
- 通过微信SDK提供的文件接口来存储文件
- 通过微信的下载缓存来避免重复下载
使用微信下载缓存时,微信小游戏在下载文件过程中,底层会自动匹配下载url中是否包含小游戏配置文件"Bundle Path Identifier"属性中的字段来决定是否缓存下载结果。由于缓存在小游戏框架底层实现,对Unity不可见,因此在Unity游戏内每次都会触发下载请求。已缓存的url再次被请求时,将直接从缓存中读取,表现为下载时间更短。 具体缓存规则请参考微信官方文档 小游戏资源缓存。
为了在使用微信下载缓存,避免AB文件的重复下载的同时,依旧支持游戏版本变动,即同一AB文件内资源随版本的变动。 打包AB时,需要在AB名称中附带hash,以便于微信管理下载缓存:
- 如果用代码打包AB,请添加BuildAssetBundleOptions.AppendHashToAssetBundleName选项
- 如果使用AssetBundleBrowser package打包AB,请按下图勾选
以使用Auto Streaming和UOS CDN为例。 AB打包完成后,需要手动将所有AB移动到引擎默认的目录CustomCloudAssets/CustomAB, 或其他自定义的目录(需要在微信打包页面自行填写Bundle Path Identififier使缓存生效,CustomAB已自动填写)。
C#代码中下载AB的URl根路径为: AutoStreaming.CustomCloudAssetsRoot+ {自定义子目录} + {带Hash的AB文件名}。
由于AssetBundleManifest对应的AB(下图WebGL文件)文件名不带hash,不能放入微信缓存目录(CustomCloudAssets/CustomAB)中。否则后续游戏版本更新后, AssetBundleManifest却始终从缓存中获取,导致AB无法更新。
使用BuildAssetBundleOptions.AppendHashToAssetBundleName后,AB文件名称会随打包资源变化而变化,因此加载AB代码需要做相应的修改,从AssetBundleManifest中动态获取AB的名称。
加载远程AssetBundle示例:
//示例AB名称: bundle_cda40198af392ffe0419808051b8ac08
//生成字典 abName -> abNameWithHash
private Dictionary<string,string> GetABNamesWithHash(AssetBundleManifest abm)
{
var hashNames = abm.GetAllAssetBundles();
Dictionary<string, string> ABNamesDict =
new Dictionary<string, string>();
foreach (var hashName in hashNames)
{
//需要注意AB后缀名,默认 .unity3d
var abName = Regex.Match(hashName,
"_[0-9a-f]{32}.unity3d$").Success
? hashName.Substring(0,hashName.Length - 33)
: hashName;
ABNamesDict.Add(abName, hashName);
}
return ABNamesDict;
}
IEnumerator LoadABAsync(string abName)
{
//加载manifest
var uwr = UnityWebRequestAssetBundle.GetAssetBundle(AutoStreaming.CustomCloudAssetsRoot + "WebGL");
yield return uwr.SendWebRequest();
if (uwr.result != UnityWebRequest.Result.Success)
{
Debug.Log(uwr.error);
yield break;
}
//获取映射字典
AssetBundle manifestbundle = DownloadHandlerAssetBundle.GetContent(uwr);
AssetBundleManifest abm = manifestbundle?.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
var hashNames = GetABNamesWithHash(abm);
//获取ab带hash的完整文件名
var abNameWithHash = hashNames[abName];
//ab在服务器上的地址
string abUrl = AutoStreaming.CustomCloudAssetsRoot + "CustomAB/" + abNmaeWithHash;
//下载并加载AB
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(abUrl);
yield return request.SendWebRequest();
if(!request.isHttpError)
{
//成功下载并加载,加载资源
...
}
}