Skip to content

使用 AssetBundle 进行资源按需加载

阐述如何在小游戏环境对AssetBundle进行打包、加载和内存优化。

一、AssetBundle使用

注意:小游戏环境不支持assetbundle本地加载

1.1 AssetBundle打包参数建议

c#
public static void Build()
{
    string dst = Application.streamingAssetsPath + "/AssetBundles";
    if (!Directory.Exists(dst))
    {
        Directory.CreateDirectory(dst);
    }
    BuildPipeline.BuildAssetBundles(dst, BuildAssetBundleOptions.AppendHashToAssetBundleName | BuildAssetBundleOptions.ChunkBasedCompression | UnityEditor.BuildAssetBundleOptions.DisableWriteTypeTree | BuildAssetBundleOptions.None, BuildTarget.WebGL);
}

打包bundle时,请使用如下参数

  • 【重要】BuildAssetBundleOptions.AppendHashToAssetBundleName:bundle带上hash。在小游戏底层对bundle做缓存及缓存淘汰时,hash是重要依据。
  • BuildAssetBundleOptions.ChunkBasedCompression:LZ4压缩方式,加载速度和包体大小更均衡。
  • 如非需要新老Unity引擎版本兼容,请使用DisableWriteTypeTree提升加载速度与降低内存。

1.2 AssetBundle下载

从服务器下载bundle的方式主要以下两种:

  • UnityWebRequestAssetBundle.GetAssetBundle

    c#
    UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uriPath);
    yield return request.SendWebRequest();
    if (request.isHttpError)
    {
        Debug.LogError(GetType() + "/ERROR/" + request.error);
    }
    else
    {
        AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
        // ab.LoadAsset
        ab.Unload(false);
    }
    request.Dispose();
  • UnityWebRequest

    c#
    UnityWebRequest www = new UnityWebRequest(uriPath);
    DownloadHandlerAssetBundle handler = new DownloadHandlerAssetBundle(www.uri.ToString(), 0);
    www.downloadHandler = handler;
    yield return www.Send();
    if (www.isHttpError)
    {
        Debug.LogError(GetType() + "/ERROR/" + www.error);
    } else
    {
        AssetBundle ab = handler.assetBundle
        // ab.LoadAsset
        ab.Unload(false);
    }
    www.Dispose();

    特别地, 切忌使用WWW.LoadFromCacheOrDownload或WWW等带cache接口,WebGL模式下将会使用JS模拟文件系统带来额外内存消耗!

二、小游戏与APP的AssetBundle缓存更新流程差异

小游戏因其平台特殊性,需要保证加载速度,因此我们在底层对bundle文件做了缓存,开发者无须自己实现缓存。

游戏逻辑还是按照未缓存需要从网络下载去编写,插件底层会判断是否已有缓存。若未缓存则缓存此bundle;若已缓存,则返回缓存文件,实际不会发起网络请求。

在业务侧看来:总是使用异步接口从远程下载并使用,底层资源的缓存与更新已由适配层自动完成,游戏不再直接读写文件系统。

三、AssetBundle内存分析

3.1 切勿使用带Cache能力的线管接口

需要注意业务中不要使用已淘汰的WWW类,尤其WWW.LoadFromCacheOrDownload,当bundle数量多时,会浪费不少内存。

3.2 尽可能使用Unload

  • 当bundle从资源服务器下载并使用,会经历多次内存分配: 浏览器HTTP对象-->拷贝到WASM临时内存-->Unity ab内存文件(略大于ab本身体积, 相对于APP常用的LoadFromFile,WebGL这部分开销是额外的)
  • 当HTTP对象dispose之后,Unity ab内存文件
  • 当ab.Unload时,Unity ab内存文件释放

因此,最佳实践是业务应该尽可能早地使用ab.Unload(false),自行维护Asset的引用计数管理资源。

四、部署

4.1 AB编译与部署

  • 使用vivo插件导出后的最终AB资源路径如下,将webgl目录下的文件上传到CDN:
  • 在插件中配置cdn路径

4.2 资源预下载

为了充分利用网络带宽,在网络空闲时可预下载游戏需要用到的AB包。详细配置请参考使用预下载功能