AssetBundle的加载

AssetBundle.LoadFromMemoryAsync

AssetBundleCreateRequest LoadFromMemoryAsync(byte[] binary, uint crc = 0);
  • 使用二进制数据异步加载ab对象,通常我们对ab进行加密后,下载到本地解密,然后将解密后的二进制数据传进来,最后获取到ab对象。

  • 如果是LZMA压缩的AB,会在加载的过程中进行解压;如果是LZ4压缩的AB,会直接加载压缩状态的数据。

  • 与同步版接口LoadFromMemory立即返回ab对象不同,LoadFromMemoryAsync会在后台线程中执行解压操作。

  • IEnumerator LoadFromMemoryAsync(string path)
        AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
        yield return createRequest;
        AssetBundle bundle = createRequest.assetBundle;
        var prefab = bundle.LoadAsset.<GameObject>("MyObject");
        Instantiate(prefab);
    

    AssetBundle.LoadFromFile

    AssetBundle LoadFromFile(string path, uint crc = 0, ulong offset = 0); 
    
  • 从本地加载未压缩(uncompressed)或使用LZ4压缩的AB,效率很高。

  • 加载LZMA压缩的AB时,会先将其解压,然后再载入内存。

  • 在Unity5.3及之前的版本中,在Android平台下调用这个接口去加载StreamingAssets目录下的ab会失败,因为安卓下这个目录是一个.jar的压缩文件。不过Unity5.4以及之后的版本已经修复这个问题,可以正常使用。

  • var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));
    if (myLoadedAssetBundle == null) {
        Debug.Log("Failed to load AssetBundle!");
        return;
    var prefab = myLoadedAssetBundle.LoadAsset.<GameObject>("MyObject");
    Instantiate(prefab);
    

    WWW.LoadFromCacheOrDownload

    WWW LoadFromCacheOrDownload(string url, int version);
    
  • 不推荐使用此接口,因为使用www对象来存储ab对象会造成内存开销过多,WebStreaming问题。

  • 先从本地缓存中获取ab,如果不存在或者不是最新版本,则会从远程下载。如果ab是压缩过的,则会在线程中解压ab,然后写入本地缓存中。一但ab解压完成并缓存之后的加载流程就跟AssetBundle.LoadFromFile完全一样。

  • version用法??

  • IEnumerator Start()
        while (!Caching.ready)
            yield return null;
        var www = WWW.LoadFromCacheOrDownload("http://myserver.com/myassetBundle.unity3d", 5);
        yield return www;
        if (!string.IsNullOrEmpty(www.error))
            Debug.Log(www.error);
            yield return null;
        var myLoadedAssetBundle = www.assetBundle;
        var asset = myLoadedAssetBundle.mainAsset;
    

    ab缓存由Caching类管理,Caching还可以用来做ab备份以及回滚。

    https://docs.unity3d.com/ScriptReference/Caching.html

    由于www的性能问题,使用这个接口时需要注意:

  • 单个ab不能太大,一般建议不超过1M

  • 在移动平台,同一时间最多下载一个ab,避免造成内存高峰

  • 如果本地缓存没有足够空间,则会先删除最久没访问的资源;如果找不到可以删除的资源,则会跳过缓存过程,直接将文件加载到内容中,流程就跟"new WWW()"一样。

  • 只能用此方法来访问AB,对其它类型资源不适用。

  • url中的'%'必须被省去。

  • UnityWebRequest

    UnityWebRequest UnityWebRequest.GetAssetBundle(string uri, uint crc);
    AssetBundle DownloadHandlerAssetBundle.GetContent(Networking.UnityWebRequest www);
    
  • 最推荐的方式来替代www的方式加载AB,以减少webstream内存占用问题

  • 先用UnityWebRequest.GetAssetBundle进行下载

  • 再用DownloadHandlerAssetBundle.GetContent(UnityWebRequest)获取AB对象

  • IEnumerator InstantiateObject()
        string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;        
        UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
        yield return request.Send();
        AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
        GameObject cube = bundle.LoadAsset<GameObject>("Cube");
        GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");
        Instantiate(cube);
        Instantiate(sprite);
    

    LoadAsset

    T objectFromBundle = bundleObject.LoadAsset<T>(assetName);
    GameObject gameObject = loadedAssetBundle.LoadAsset<GameObject>(assetName);
    Unity.Object[] objectArray = loadedAssetBundle.LoadAllAssets();
    
    AssetBundleRequest request = loadedAssetBundleObject.LoadAssetAsync<GameObject>(assetName);
    yield return request;
    var loadedAsset = request.asset;
    
    AssetBundleRequest request = loadedAssetBundle.LoadAllAssetsAsync();
    yield return request;
    var loadedAssets = request.allAssets;
    

    Load Manifests

  • 在AB根目录,会有一个Manifest的AB文件,跟加载普通AB一样
  • 存储了依赖关系,哈希值,AB变体等
  • AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
    AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
    
  • 在加载AB前,需要先加载其依赖
  • AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
    AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
    string[] dependencies = manifest.GetAllDependencies("assetBundle"); //Pass the name of the bundle you want the dependencies for.
    foreach(string dependency in dependencies)
        AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, dependency));
    
  • 同一个AB只能加载一次,否则会报错,提示已经加载过