使用Adressable完成游戏更新-自定义Bundle加载方式

前面自定义了Bundle的打包方式,现在就要自定义加载方式了,不然就会走原来设置的远程加载的原本逻辑,我们多做了一个内置包列表和复制移动Bundle到Library中的准备工作就没有用了。

注意如果是UnityWebRequestAssetBundle,则不会支持访问data去保存,不过自行缓存,此时只需要判断是不是内置Bundle就行,其他走web。需要自己缓存Bundle的,需要修改UnityWebRequestAssetBundle为UnityWebRequest

新建一个cs文件MyAssetBundleProvider,复制原内容的AssetBundlePrivider到新建cs脚本中,修改相关类名为自己自定义类名。主要修改IAssetBundleResource的BeginOperation方法和WebRequestOperationCompleted方法


//MyAssetBundleProvider.cs

private void BeginOperation()
{
    string path = m_ProvideHandle.Location.InternalId;
    var url = m_ProvideHandle.ResourceManager.TransformInternalId(m_ProvideHandle.Location);
    string bundleName = Path.GetFileName(url);
    // if a path starts with jar:file, it is an android embeded resource. The resource is a local file but cannot be accessed by 
    // FileStream(called in LoadWithDataProc) directly
    // Need to use webrequest's async call to get the content.
    if (AssetBundleManager.GetInstance().buildInData != null && AssetBundleManager.GetInstance().buildInData.BuildInBundleNames.Contains(bundleName))//本地资源,内置包
    {
        string streamPath = UnityEngine.AddressableAssets.Addressables.RuntimePath + "/" + PlatformMappingService.GetPlatformPathSubFolder() + "/" + bundleName;
        Debug.Log("LoadOne:" + streamPath);
        var crc = m_Options == null ? 0 : m_Options.Crc;
        CompleteBundleLoad(AssetBundle.LoadFromFile(streamPath));
    }
    else if (AssetBundleManager.GetInstance().IsCache(bundleName)) //已经下载过 缓存到本地的Bundle
    {
        string cachePath = Path.Combine(AssetBundleManager.GetInstance().GetBundleCachePath(), bundleName);
        Debug.Log("LoadTwo:" + cachePath);
        var crc = m_Options == null ? 0 : m_Options.Crc;
        CompleteBundleLoad(AssetBundle.LoadFromFile(cachePath));
    }
    else if (ResourceManagerConfig.ShouldPathUseWebRequest(path)) //真正需要下载的Bundle
    {
        Debug.Log("DownloadThree:" + url);
        var req = CreateWebRequest(m_ProvideHandle.Location);
        req.disposeDownloadHandlerOnDispose = false;
        m_WebRequestQueueOperation = WebRequestQueue.QueueRequest(req);
        if (m_WebRequestQueueOperation.IsDone)
        {
            m_RequestOperation = m_WebRequestQueueOperation.Result;
            m_RequestOperation.completed += WebRequestOperationCompleted;
        }
        else
        {
            m_WebRequestQueueOperation.OnComplete += asyncOp =>
            {
                m_RequestOperation = asyncOp;
                m_RequestOperation.completed += WebRequestOperationCompleted;
            };
        }
    }
    else
    {
        m_RequestOperation = null;
        m_ProvideHandle.Complete<MyAssetBundleResource>(null, false, new Exception(string.Format("Invalid path in AssetBundleProvider: '{0}'.", path)));
    }
}


private void WebRequestOperationCompleted(AsyncOperation op)
{
    UnityWebRequestAsyncOperation remoteReq = op as UnityWebRequestAsyncOperation;
    var webReq = remoteReq.webRequest;
    if (!UnityWebRequestUtilities.RequestHasErrors(webReq, out UnityWebRequestResult uwrResult))
    {
        m_downloadHandler = webReq.downloadHandler;
        string path = m_ProvideHandle.ResourceManager.TransformInternalId(m_ProvideHandle.Location);
        string bundleName = Path.GetFileName(path);

        AssetBundleManager.GetInstance().CacheBundle(bundleName, m_downloadHandler.data);//主要是在这里加了一个保存到本地的方法

        if (!m_Completed)
        {
            m_ProvideHandle.Complete(this, true, null);
            m_Completed = true;
        }
    }
    else
    {
        m_downloadHandler = webReq.downloadHandler;
        m_downloadHandler.Dispose();
        m_downloadHandler = null;
        string message = string.Format("Web request {0} failed with error '{1}', retrying ({2}/{3})...", webReq.url, webReq.error, m_Retries, m_Options.RetryCount);

        if (m_Retries < m_Options.RetryCount)
        {
            Debug.LogFormat(message);
            BeginOperation();
            m_Retries++;
        }
        else
        {
            var exception = new Exception(string.Format(
                "RemoteAssetBundleProvider unable to load from url {0}, result='{1}'.", webReq.url,
                webReq.error));
            m_ProvideHandle.Complete<MyAssetBundleResource>(null, false, exception);
        }
    }
    webReq.Dispose();
}


读取内置包列表,缓存Bundle到本地,检查是否有缓存,都是使用 AssetBundleManager.cs

using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO;

[Serializable]
public class BuildInBundleData
{
    public List<string> BuildInBundleNames = new List<string>();
}

public class AssetBundleManager
{
    private static AssetBundleManager _instance = null;
    private string cachePath = "";
    public BuildInBundleData buildInData;

    public static AssetBundleManager GetInstance()
    {
        if (_instance == null)
            _instance = new AssetBundleManager();

        return _instance;
    }

    AssetBundleManager()
    {
        cachePath = Path.Combine(Application.persistentDataPath, "ab");
        if (!Directory.Exists(cachePath))
        {
            Directory.CreateDirectory(cachePath);
        }
    }

    public void Init()
    {
#if !UNITY_EDITOR
            var json = Resources.Load<TextAsset>("Version/BuildInBundleName");
            buildInData = JsonUtility.FromJson<BuildInBundleData>(json.text);
#endif
    }

    public String GetBundleCachePath()
    {
        return cachePath;
    }

    public bool IsCache(string bundleName)
    {
        string filePath = Path.Combine(AssetBundleManager.GetInstance().GetBundleCachePath(), bundleName);
        return File.Exists(filePath);
    }

    public void CacheBundle(string bundlename, byte[] bytes)
    {
        string filePath = Path.Combine(GetBundleCachePath(), bundlename);
        if (File.Exists(filePath))
            File.Delete(filePath);

        File.WriteAllBytes(filePath, bytes);

        string realName = GetRealBundleName(bundlename);
        string oldPath = PlayerPrefs.GetString(realName, "");
        if (oldPath != "")
            File.Delete(oldPath);

        PlayerPrefs.SetString(realName, filePath);
    }

    public string GetRealBundleName(string bundlename)
    {
        if (string.IsNullOrEmpty(bundlename))
            return "";

        int index = bundlename.LastIndexOf("_");
        return bundlename.Substring(0, index);
    }
}


自定义写完后,需要应用使用上这个自定义加载Provider

public static void SetAllGroupToRemote()
{
    var s = AASUtility.GetSettings();
    var groups = s.groups;
    foreach (var group in groups)
    {
        BundledAssetGroupSchema bundledAssetGroupSchema = group.GetSchema<BundledAssetGroupSchema>();
        if (bundledAssetGroupSchema == null)
        {
            bundledAssetGroupSchema = group.AddSchema<BundledAssetGroupSchema>();
        }

        bundledAssetGroupSchema.BuildPath.SetVariableByName(group.Settings, AddressableAssetSettings.kRemoteBuildPath);
        bundledAssetGroupSchema.LoadPath.SetVariableByName(group.Settings, AddressableAssetSettings.kRemoteLoadPath);
        bundledAssetGroupSchema.SetAssetBundleProviderType(typeof(MyAssetBundleProvider)); //主要是这

        EditorUtility.SetDirty(bundledAssetGroupSchema);
    }

    AssetDatabase.Refresh();
}



首页 我的博客
粤ICP备17103704号