Version: 1.5
语言 : 中文
部署微信小游戏
微信小游戏 Profiler 连接配置

微信资源缓存

微信小游戏切断了 JS 文件系统和 IndexDB 的同步,以避免大量文件同步带来的卡顿问题。因此所有通过 C# 文件 IO 保存的文件只会在内存中存在,而不会同步到持久化存储中。在游戏退出后,内存中的文件都会被释放。 微信提供了两种方式来持久化存储文件:

  1. 通过微信 SDK 提供的文件接口来存储文件

  2. 通过微信的下载缓存来避免重复下载

在微信小游戏中,为了避免大量文件同步导致的性能问题,微信平台限制了 JS 文件系统和 IndexedDB 的同步。这意味着通过 C# 文件 IO 操作保存的文件仅存在于内存中,并不会持久化存储。当游戏退出时,这些文件将被释放。为了持久化存储文件,微信提供了两种解决方案:

  1. 使用微信 SDK 的文件接口存储文件:通过微信提供的 API,可以将文件保存到设备的存储中。

  2. 利用微信的下载缓存机制:微信小游戏在下载文件时,会自动检查下载 URL 中是否包含 Bundle Path Identifier 属性来决定是否缓存文件。由于缓存在小游戏框架底层实现,对引擎不可见,因此在游戏内每次都会触发下载请求。已缓存的 url 再次被请求时,将直接从缓存中读取,表现为下载时间更短。

具体缓存规则请参考微信官方文档 小游戏资源缓存

使用微信下载缓存

为了有效利用微信的下载缓存,并支持游戏版本的更新,即同一 AB 文件内资源随版本的变动,建议在打包 AssetBundle 时包含哈希值,以便于微信管理下载缓存。具体步骤如下:

  1. 代码打包 AssetBundle:在打包时添加 BuildAssetBundleOptions.AppendHashToAssetBundleName 选项,以确保 AssetBundle 名称包含哈希值。
  2. 使用 AssetBundleBrowser 打包:在 AssetBundleBrowser 中勾选相应的选项,以自动添加哈希值到 AssetBundle 名称。请按下图勾选:

部署 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 无法更新。

加载远程 AssetBundle

使用 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)
    {
        //成功下载并加载,加载资源
        ...
    }
}
部署微信小游戏
微信小游戏 Profiler 连接配置