微信小游戏切断了 JS 文件系统和 IndexDB 的同步,以避免大量文件同步带来的卡顿问题。因此所有通过 C# 文件 IO 保存的文件只会在内存中存在,而不会同步到持久化存储中。在游戏退出后,内存中的文件都会被释放。 微信提供了两种方式来持久化存储文件:
通过微信 SDK 提供的文件接口来存储文件
通过微信的下载缓存来避免重复下载
在微信小游戏中,为了避免大量文件同步导致的性能问题,微信平台限制了 JS 文件系统和 IndexedDB 的同步。这意味着通过 C# 文件 IO 操作保存的文件仅存在于内存中,并不会持久化存储。当游戏退出时,这些文件将被释放。为了持久化存储文件,微信提供了两种解决方案:
使用微信 SDK 的文件接口存储文件:通过微信提供的 API,可以将文件保存到设备的存储中。
利用微信的下载缓存机制:微信小游戏在下载文件时,会自动检查下载 URL 中是否包含 Bundle Path Identifier
属性来决定是否缓存文件。由于缓存在小游戏框架底层实现,对引擎不可见,因此在游戏内每次都会触发下载请求。已缓存的 url 再次被请求时,将直接从缓存中读取,表现为下载时间更短。
具体缓存规则请参考微信官方文档 小游戏资源缓存。
为了有效利用微信的下载缓存,并支持游戏版本的更新,即同一 AB 文件内资源随版本的变动,建议在打包 AssetBundle 时包含哈希值,以便于微信管理下载缓存。具体步骤如下:
BuildAssetBundleOptions.AppendHashToAssetBundleName
选项,以确保 AssetBundle 名称包含哈希值。以使用 Auto Streaming 和 UOS CDN 为例。
AB 打包完成后,需要手动将所有 AB 移动到引擎默认的目录 CustomCloudAssets/CustomAB,或其他自定义的目录(需要在微信打包页面自行填写 Bundle Path Identififier
使缓存生效,CustomAB 已自动填写)。(可参考UOS 文件上传和下载 “手动上传的文件”小节)
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)
{
//成功下载并加载,加载资源
...
}
}