Unity5 AssetBundle资源管理架构设计

http://blog.csdn.net/qq_19399235/article/details/51702964

1:Unity5 资源管理架构设计(2017.4.22版本)

2:Android 热更新(不考虑IOS)根据C#反射实现的代码全更新方案(网上一大坨,我重新整理一下)。



一:Unity资源管理架构设计

注意:我配置的Bundle资源文件都放在Assets/ResourceABs文件夹下,并且此文件夹下每个文件夹都对应一个Bundle文件,最终这些文件都打包到StreamingAssets流文件夹下。

1:设计一个资源信息管理类,能够反映Assets/ResourceABs文件夹下的全部的资源信息。
生成工具放在Editor文件下, 代码如下:
[csharp] view plain copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3. using System.IO;  
  4. using UnityEditor;  
  5. using xk_System.AssetPackage;  
  6.   
  7. public class ExportAssetInfoEditor : MonoBehaviour  
  8. {  
  9.     static string extention = AssetBundlePath.ABExtention;  
  10.     static string BuildAssetPath = "Assets/ResourceABs";  
  11.     static string CsOutPath = "Assets/Scripts/auto";  
  12.   
  13.     //~~~~~~~~~~~~~~~~~~~~~~~~~~~~创建AB文件所有的信息~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
  14.     [MenuItem("UnityEditor/GenerationPackage/Generation AssetInfo Cs File")]  
  15.     public static void GenericAssetCSInfo()  
  16.     {  
  17.         Debug.Log("Start Generation AssetInfo Cs Info");  
  18.         CreateABCSFile();  
  19.         Debug.Log("Finish Generation AssetInfo Cs Info");  
  20.     }  
  21.   
  22.     private static void CreateABCSFile()  
  23.     {  
  24.         string m = "";  
  25.         m += "namespace xk_System.AssetPackage { ";  
  26.         DirectoryInfo mDir = new DirectoryInfo(BuildAssetPath);  
  27.         m += " public class " + mDir.Name + "Folder : Singleton<" + mDir.Name + "Folder> { ";  
  28.         string s = "";  
  29.         foreach (var v in mDir.GetDirectories())  
  30.         {  
  31.             FileInfo[] mFileInfos1 = v.GetFiles();  
  32.             int mFilesLength1 = 0;  
  33.             foreach (var v1 in mFileInfos1)  
  34.             {  
  35.                 if (v1.Extension != ".meta")  
  36.                 {  
  37.                     mFilesLength1++;  
  38.                     break;  
  39.                 }  
  40.             }  
  41.             if (mFilesLength1 > 0 || v.GetDirectories().Length > 0)  
  42.             {  
  43.                 string fieldName = v.Name + "Folder";  
  44.                 m += "  public " + fieldName + " " + v.Name + "=new " + fieldName + "(); ";  
  45.                // s += CreateDirClass(v, v.Name.ToLower());  
  46.             }  
  47.         }  
  48.         foreach (var v in mDir.GetDirectories())  
  49.         {  
  50.             m += CreateDirClass(v, v.Name.ToLower());  
  51.         }  
  52.         m += " } ";  
  53.        // m += s;  
  54.         m += "} ";  
  55.         string fileName = CsOutPath + "/" + mDir.Name + ".cs";  
  56.         StreamWriter mSw = new StreamWriter(fileName, false);  
  57.         mSw.Write(m);  
  58.         mSw.Close();  
  59.     }  
  60.   
  61.     private static string CreateDirClass(DirectoryInfo mDir, string bundleName)  
  62.     {  
  63.         string tStr = GetTStr(mDir);  
  64.         string m = "";  
  65.         string s = "";  
  66.         FileInfo[] mFileInfos = mDir.GetFiles();  
  67.         int mFilesLength = 0;  
  68.         foreach (var v in mFileInfos)  
  69.         {  
  70.             if (v.Extension != ".meta")  
  71.             {  
  72.                 mFilesLength++;  
  73.                 break;  
  74.             }  
  75.         }  
  76.         if (mFilesLength > 0)  
  77.         {  
  78.             string bundleName1 = bundleName+ extention;  
  79.             m = tStr+"public class " + mDir.Name + "Folder "+tStr+"{ ";  
  80.             foreach (var v in mFileInfos)  
  81.             {  
  82.                 if (v.Extension != ".meta")  
  83.                 {  
  84.                     string assetPath = GetAssetPath(v.FullName);  
  85.                     string fileName = v.Name.Substring(0, v.Name.LastIndexOf(v.Extension));  
  86.                     m += tStr+"  public AssetInfo m" + fileName + "=new AssetInfo(""+assetPath+"","" + bundleName1 + "","" + v.Name + ""); ";  
  87.                 }  
  88.             }  
  89.             m += tStr+"} ";  
  90.         }  
  91.         else  
  92.         {  
  93.             if (mDir.GetDirectories().Length > 0)  
  94.             {  
  95.   
  96.                 m = tStr+"public class " + mDir.Name + "Folder "+tStr+"{ ";  
  97.                 foreach (var v in mDir.GetDirectories())  
  98.                 {  
  99.                     FileInfo[] mFileInfos1 = v.GetFiles();  
  100.                     int mFilesLength1 = 0;  
  101.                     foreach (var v1 in mFileInfos1)  
  102.                     {  
  103.                         if (v1.Extension != ".meta")  
  104.                         {  
  105.                             mFilesLength1++;  
  106.                             break;  
  107.                         }  
  108.                     }  
  109.                     if (mFilesLength1 > 0 || v.GetDirectories().Length > 0)  
  110.                     {  
  111.                         string fieldName = v.Name + "Folder";  
  112.                         m += tStr+"  public " + fieldName + " " + v.Name + "=new " + fieldName + "(); ";  
  113.                     }  
  114.                 }  
  115.                 foreach (var v in mDir.GetDirectories())  
  116.                 {  
  117.                     m += CreateDirClass(v, bundleName + "_" + v.Name.ToLower());  
  118.                 }  
  119.                 m += tStr+"} ";  
  120.                // m += s;  
  121.             }  
  122.         }  
  123.         return m;  
  124.     }  
  125.     public static string GetTStr(DirectoryInfo mDir)  
  126.     {  
  127.         int coutT = 0;  
  128.         int index = mDir.FullName.IndexOf(@"ResourceABs");  
  129.         if (index >= 0)  
  130.         {  
  131.             for(int j=0;j<mDir.FullName.Length;j++)  
  132.             {  
  133.                 if (j > index)  
  134.                 {  
  135.                     var v = mDir.FullName[j];  
  136.                     if (v.Equals('\'))  
  137.                     {  
  138.                         coutT++;  
  139.                     }  
  140.                 }  
  141.             }  
  142.         }  
  143.         coutT++;  
  144.         string tStr = "";  
  145.         int i = 0;  
  146.         while(i<coutT)  
  147.         {  
  148.             tStr += " ";  
  149.             i++;  
  150.         }  
  151.         return tStr;  
  152.     }  
  153.   
  154.     public static string GetAssetPath(string filePath)  
  155.     {  
  156.         string assetPath = "";  
  157.         int index = filePath.IndexOf(@"Assets");  
  158.         if (index >= 0)  
  159.         {  
  160.             assetPath = filePath.Remove(0, index);  
  161.             assetPath = assetPath.Replace(@"","/");  
  162.         }  
  163.         return assetPath;  
  164.     }  
  165.   
  166. }  
到这里,这个资源基本信息管理类就处理好了。
2:我们就正式开始写资源管理架构类了
我们首先写一个AssetBundleManager类,这个类的目的专门用来更新完毕后,充当资源加载管理器。代码如下
[csharp] view plain copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3. using xk_System.Debug;  
  4. using System.Collections.Generic;  
  5. using System.Xml;  
  6.   
  7. namespace xk_System.AssetPackage  
  8. {  
  9.     /// <summary>  
  10.     /// 此类的目的就是加载本地的Bundle进行资源读取操作的  
  11.     /// </summary>  
  12.     public class AssetBundleManager : SingleTonMonoBehaviour<AssetBundleManager>  
  13.     {  
  14.         private ResourcesABManager mResourcesABManager = new ResourcesABManager();  
  15.         private Dictionary<string, AssetBundle> mBundleDic = new Dictionary<string, AssetBundle>();  
  16.         private Dictionary<string, Dictionary<string, UnityEngine.Object>> mAssetDic = new Dictionary<string, Dictionary<string, UnityEngine.Object>>();  
  17.         private List<string> mBundleLockList = new List<string>();  
  18.   
  19.         /// <summary>  
  20.         /// 加载Assetbundle方案1:初始化时,全部加载  
  21.         /// </summary>  
  22.         /// <returns></returns>  
  23.         public IEnumerator InitLoadAllBundleFromLocal()  
  24.         {  
  25.             yield return mResourcesABManager.InitLoadMainifestFile();  
  26.             List<AssetBundleInfo> bundleList = mResourcesABManager.mNeedLoadBundleList;  
  27.             List<AssetBundleInfo>.Enumerator mIter = bundleList.GetEnumerator();  
  28.             while (mIter.MoveNext())  
  29.             {  
  30.                 yield return AsyncLoadFromLoaclSingleBundle(mIter.Current);  
  31.             }  
  32.         }  
  33.         public IEnumerator InitAssetBundleManager()  
  34.         {  
  35.             yield return mResourcesABManager.InitLoadMainifestFile();  
  36.         }  
  37.   
  38.         private IEnumerator CheckBundleDependentBundle(AssetBundleInfo mBundle)  
  39.         {  
  40.             if (mBundle != null)  
  41.             {  
  42.                 string[] mdependentBundles = mBundle.mDependentBundleList;  
  43.                 foreach (string s in mdependentBundles)  
  44.                 {  
  45.                     AssetBundleInfo mBundleInfo = mResourcesABManager.GetBundleInfo(s);  
  46.                     if (mBundleInfo != null)  
  47.                     {  
  48.                         AssetBundle mAB = null;  
  49.                         if (!mBundleDic.TryGetValue(mBundleInfo.bundleName, out mAB))  
  50.                         {  
  51.                             yield return AsyncLoadFromLoaclSingleBundle(mBundleInfo);  
  52.                         }  
  53.                         else  
  54.                         {  
  55.                             if (mAB == null)  
  56.                             {  
  57.                                 yield return AsyncLoadFromLoaclSingleBundle(mBundleInfo);  
  58.                             }  
  59.                         }  
  60.                     }  
  61.                 }  
  62.             }  
  63.         }  
  64.         /// <summary>  
  65.         /// 从本地外部存储位置加载单个Bundle资源,全部加载  
  66.         /// </summary>  
  67.         /// <param name="BaseBundleInfo"></param>  
  68.         /// <returns></returns>  
  69.         private IEnumerator AsyncLoadFromLoaclSingleBundle1(AssetBundleInfo BaseBundleInfo)  
  70.         {  
  71.             if(mBundleLockList.Contains(BaseBundleInfo.bundleName))  
  72.             {  
  73.                 while(mBundleLockList.Contains(BaseBundleInfo.bundleName))  
  74.                 {  
  75.                     yield return null;  
  76.                 }  
  77.                 yield break;  
  78.             }       
  79.             mBundleLockList.Add(BaseBundleInfo.bundleName);  
  80.             yield return CheckBundleDependentBundle(BaseBundleInfo);  
  81.             string path = AssetBundlePath.Instance.ExternalStorePathUrl;  
  82.             string url = path + "/" + BaseBundleInfo.bundleName;  
  83.             WWW www = new WWW(url);  
  84.             yield return www;  
  85.             if (www.isDone)  
  86.             {  
  87.                 if (!string.IsNullOrEmpty(www.error))  
  88.                 {  
  89.                     DebugSystem.LogError("www Load Error:" + www.error);  
  90.                     www.Dispose();  
  91.                     mBundleLockList.Remove(BaseBundleInfo.bundleName);  
  92.                     yield break;  
  93.                 }  
  94.             }  
  95.             AssetBundle asset = www.assetBundle;  
  96.             SaveBundleToDic(BaseBundleInfo.bundleName, asset);  
  97.             mBundleLockList.Remove(BaseBundleInfo.bundleName);  
  98.             www.Dispose();  
  99.         }  
  100.   
  101.         /// <summary>  
  102.         /// 从本地外部存储位置加载单个Bundle资源,全部加载  
  103.         /// </summary>  
  104.         /// <param name="BaseBundleInfo"></param>  
  105.         /// <returns></returns>  
  106.         private IEnumerator AsyncLoadFromLoaclSingleBundle(AssetBundleInfo BaseBundleInfo)  
  107.         {  
  108.             if (mBundleLockList.Contains(BaseBundleInfo.bundleName))  
  109.             {  
  110.                 while (mBundleLockList.Contains(BaseBundleInfo.bundleName))  
  111.                 {  
  112.                     yield return null;  
  113.                 }  
  114.                 yield break;  
  115.             }  
  116.             mBundleLockList.Add(BaseBundleInfo.bundleName);  
  117.             yield return CheckBundleDependentBundle(BaseBundleInfo);  
  118.             string path = AssetBundlePath.Instance.ExternalStorePath+"/"+BaseBundleInfo.bundleName;  
  119.             AssetBundleCreateRequest www= AssetBundle.LoadFromFileAsync(path);  
  120.             www.allowSceneActivation = true;  
  121.             yield return www;  
  122.             AssetBundle asset = www.assetBundle;  
  123.             SaveBundleToDic(BaseBundleInfo.bundleName, asset);  
  124.             mBundleLockList.Remove(BaseBundleInfo.bundleName);  
  125.         }  
  126.         /// <summary>  
  127.         /// 异步从本地外部存储加载单个Asset文件,只加载Bundle中的单个资源  
  128.         /// </summary>  
  129.         /// <param name="bundle"></param>  
  130.         /// <returns></returns>  
  131.         private IEnumerator AsyncLoadFromLocalSingleAsset(AssetBundleInfo bundle, string assetName)  
  132.         {  
  133.             if (bundle != null)  
  134.             {  
  135.                 yield return AsyncLoadFromLoaclSingleBundle(bundle);  
  136.                 UnityEngine.Object Obj = mBundleDic[bundle.bundleName].LoadAsset(assetName);  
  137.                 if (Obj != null)  
  138.                 {  
  139.                     DebugSystem.Log("Async Load Asset Success:" + Obj.name);  
  140.                     SaveAssetToDic(bundle.bundleName, assetName, Obj);  
  141.                 }  
  142.             }  
  143.         }  
  144.         /// <summary>  
  145.         /// 同步从本地外部存储加载单个Bundle文件  
  146.         /// </summary>  
  147.         /// <param name="BaseBundleInfo"></param>  
  148.         /// <param name="assetName"></param>  
  149.         /// <returns></returns>  
  150.         private void SyncLoadFromLocalSingleBundle(string bundleName)  
  151.         {  
  152.             if (!JudegeOrExistBundle(bundleName))  
  153.             {  
  154.                 string path = AssetBundlePath.Instance.ExternalStorePath + "/" + bundleName;  
  155.                 AssetBundle asset = AssetBundle.LoadFromFile(path);  
  156.                 SaveBundleToDic(bundleName, asset);  
  157.             }else  
  158.             {  
  159.                 DebugSystem.LogError("Bundle 已存在:"+bundleName);  
  160.             }  
  161.         }  
  162.   
  163.         /// <summary>  
  164.         /// 同步从本地外部存储加载单个资源文件  
  165.         /// </summary>  
  166.         /// <param name="BaseBundleInfo"></param>  
  167.         /// <param name="assetName"></param>  
  168.         /// <returns></returns>  
  169.         public UnityEngine.Object SyncLoadFromLocalSingleAsset(AssetInfo mAssetInfo)  
  170.         {  
  171.             if (!JudgeOrExistAsset(mAssetInfo.bundleName, mAssetInfo.assetName))  
  172.             {  
  173.                 string path = AssetBundlePath.Instance.ExternalStorePath+"/"+mAssetInfo.bundleName;  
  174.                 AssetBundle asset = AssetBundle.LoadFromFile(path);  
  175.                 SaveBundleToDic(mAssetInfo.bundleName,asset);  
  176.             }  
  177.             return GetAssetFromDic(mAssetInfo.bundleName,mAssetInfo.assetName);  
  178.         }  
  179.   
  180.   
  181.         private void SaveBundleToDic(string bundleName, AssetBundle bundle)  
  182.         {  
  183.             if (bundle == null)  
  184.             {  
  185.                 DebugSystem.LogError("未保存的Bundle为空:"+bundleName);  
  186.                 return;  
  187.             }  
  188.             if (!mBundleDic.ContainsKey(bundleName))  
  189.             {  
  190.                 mBundleDic[bundleName] = bundle;  
  191.             }else  
  192.             {  
  193.                 DebugSystem.LogError("Bundle资源 重复:"+bundleName);  
  194.             }  
  195.         }  
  196.   
  197.         private void SaveAssetToDic(string bundleName, string assetName, UnityEngine.Object asset)  
  198.         {  
  199.             if (asset == null)  
  200.             {  
  201.                 DebugSystem.LogError("未保存的资源为空:"+assetName);  
  202.                 return;  
  203.             }  
  204.             if(asset is GameObject)  
  205.             {  
  206.                 GameObject obj = asset as GameObject;  
  207.                 obj.SetActive(false);  
  208.             }  
  209.             if (!mAssetDic.ContainsKey(bundleName))  
  210.             {  
  211.                 Dictionary<string, UnityEngine.Object> mDic = new Dictionary<string, UnityEngine.Object>();  
  212.                 mAssetDic.Add(bundleName, mDic);  
  213.             }  
  214.             mAssetDic[bundleName][assetName] = asset;  
  215.         }  
  216.   
  217.         private bool JudgeOrBundelIsLoading(string bundleName)  
  218.         {  
  219.             if (mBundleLockList.Contains(bundleName))  
  220.             {  
  221.                 return true;  
  222.             }else  
  223.             {  
  224.                 return false;  
  225.             }  
  226.         }  
  227.   
  228.         private bool JudegeOrExistBundle(string bundleName)  
  229.         {  
  230.             if (mBundleDic.ContainsKey(bundleName) && mBundleDic[bundleName] != null)  
  231.             {  
  232.                 return true;  
  233.             }  
  234.             else  
  235.             {  
  236.                 return false;  
  237.             }  
  238.         }  
  239.   
  240.         private bool JudgeOrExistAsset(string bundleName, string asstName)  
  241.         {  
  242.             if (JudegeOrExistBundle(bundleName))  
  243.             {  
  244.                 if (!mAssetDic.ContainsKey(bundleName) || mAssetDic[bundleName] == null || !mAssetDic[bundleName].ContainsKey(asstName) || mAssetDic[bundleName][asstName] == null)  
  245.                 {  
  246.                     UnityEngine.Object mm = mBundleDic[bundleName].LoadAsset(asstName);  
  247.                     if (mm != null)  
  248.                     {  
  249.                         SaveAssetToDic(bundleName, asstName, mm);  
  250.                         return true;  
  251.                     }  
  252.                     else  
  253.                     {  
  254.                         return false;  
  255.                     }  
  256.                 }  
  257.                 else  
  258.                 {  
  259.                     return true;  
  260.                 }  
  261.             }  
  262.             else  
  263.             {  
  264.                 return false;  
  265.             }  
  266.         }  
  267.   
  268.         private UnityEngine.Object GetAssetFromDic(string bundleName, string asstName)  
  269.         {  
  270.             if (JudgeOrExistAsset(bundleName, asstName))  
  271.             {  
  272.                 UnityEngine.Object mAsset1 = mAssetDic[bundleName][asstName];  
  273.                 if (mAsset1 is GameObject)  
  274.                 {  
  275.                     GameObject obj = Instantiate(mAsset1) as GameObject;  
  276.                     return obj;  
  277.                 }  
  278.                 else  
  279.                 {  
  280.                     return mAsset1;  
  281.                 }  
  282.             }  
  283.             else  
  284.             {  
  285.                 DebugSystem.LogError("Asset is NUll:" + asstName);  
  286.             }  
  287.             return null;  
  288.         }  
  289. #if UNITY_EDITOR  
  290.         private Dictionary<string, UnityEngine.Object> mEditorAssetDic = new Dictionary<string, UnityEngine.Object>();  
  291.   
  292.         private UnityEngine.Object GetAssetFromEditorDic(string assetPath)  
  293.         {  
  294.             if (string.IsNullOrEmpty(assetPath))  
  295.             {  
  296.                 DebugSystem.LogError("Editor AssetPath is Empty");  
  297.                 return null;  
  298.             }  
  299.             UnityEngine.Object asset = null;  
  300.             if (!mEditorAssetDic.TryGetValue(assetPath, out asset))  
  301.             {  
  302.                 asset = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(assetPath);  
  303.                 if (asset != null)  
  304.                 {  
  305.                     if (asset is GameObject)  
  306.                     {  
  307.                         GameObject obj = asset as GameObject;  
  308.                         obj.SetActive(false);  
  309.                     }  
  310.                     mEditorAssetDic.Add(assetPath, asset);  
  311.                 }  
  312.                 else  
  313.                 {  
  314.                     DebugSystem.LogError("找不到资源:" + assetPath);  
  315.                 }  
  316.             }  
  317.             if (asset is GameObject)  
  318.             {  
  319.                 GameObject obj = Instantiate(asset) as GameObject;  
  320.                 return obj;  
  321.             }  
  322.             else  
  323.             {  
  324.                 return asset;  
  325.             }  
  326.         }  
  327. #endif  
  328.         public IEnumerator AsyncLoadBundle(string bundleName)  
  329.         {  
  330.             if (!JudegeOrExistBundle(bundleName))  
  331.             {  
  332.                 string path = AssetBundlePath.Instance.ExternalStorePath + "/" + bundleName;  
  333.                 AssetBundle asset = AssetBundle.LoadFromFile(path);  
  334.                 SaveBundleToDic(bundleName, asset);  
  335.                 yield return null;  
  336.             }            
  337.         }  
  338.         /// <summary>  
  339.         /// 这个东西用来在顶层使用  
  340.         /// </summary>  
  341.         /// <param name="type"></param>  
  342.         /// <param name="assetName"></param>  
  343.         /// <returns></returns>  
  344.         public UnityEngine.Object LoadAsset(AssetInfo mAssetInfo)  
  345.         {  
  346.             if (GameConfig.Instance.orUseAssetBundle)  
  347.             {  
  348.                 return GetAssetFromDic(mAssetInfo.bundleName, mAssetInfo.assetName);  
  349.             }  
  350.             else  
  351.             {  
  352.                return GetAssetFromEditorDic(mAssetInfo.assetPath);  
  353.             }  
  354.         }  
  355.   
  356.         /// <summary>  
  357.         /// 这个东西用来在专门的管理器中使用(底层封装一下),禁止在顶层使用  
  358.         /// </summary>  
  359.         /// <param name="type"></param>  
  360.         /// <param name="assetName"></param>  
  361.         /// <returns></returns>  
  362.         public IEnumerator AsyncLoadAsset(AssetInfo mAssetInfo)  
  363.         {  
  364.             if (GameConfig.Instance.orUseAssetBundle)  
  365.             {  
  366.                 string bundleName = mAssetInfo.bundleName;  
  367.                 string asstName = mAssetInfo.assetPath;  
  368.                 if (!JudgeOrExistAsset(bundleName, asstName))  
  369.                 {  
  370.                     yield return AsyncLoadFromLocalSingleAsset(mResourcesABManager.GetBundleInfo(bundleName), asstName);  
  371.                 }  
  372.             }  
  373.         }  
  374.     }  
  375.   
  376.     public class ResourcesABManager  
  377.     {  
  378.         public int VersionId = -1;  
  379.         public List<AssetBundleInfo> mNeedLoadBundleList = new List<AssetBundleInfo>();  
  380.         public AssetBundleInfo GetBundleInfo(string bundleName)  
  381.         {  
  382.             AssetBundleInfo mBundleInfo = mNeedLoadBundleList.Find((x) =>  
  383.             {  
  384.                 return x.bundleName == bundleName;  
  385.             });  
  386.             return mBundleInfo;  
  387.         }  
  388.   
  389.         public IEnumerator InitLoadMainifestFile()  
  390.         {  
  391.             if (mNeedLoadBundleList.Count == 0)  
  392.             {  
  393.                 string path = AssetBundlePath.Instance.ExternalStorePathUrl;  
  394.                 string url = path + "/" + AssetBundlePath.AssetDependentFileBundleName;  
  395.                 WWW www = new WWW(url);  
  396.                 yield return www;  
  397.                 if (www.isDone)  
  398.                 {  
  399.                     if (!string.IsNullOrEmpty(www.error))  
  400.                     {  
  401.                         DebugSystem.LogError("初始化 MainifestFile 失败:" + www.error);  
  402.                         www.Dispose();  
  403.                         yield break;  
  404.                     }  
  405.                 }  
  406.                 AssetBundle asset = www.assetBundle;  
  407.                 www.Dispose();  
  408.                 if (asset == null)  
  409.                 {  
  410.                     DebugSystem.LogError("MainifestFile Bundle is Null");  
  411.                     www.Dispose();  
  412.                     yield break;  
  413.                 }  
  414.   
  415.                 AssetBundleManifest mAllBundleMainifest = asset.LoadAsset<AssetBundleManifest>(AssetBundlePath.AssetDependentFileAssetName);  
  416.                 if (mAllBundleMainifest == null)  
  417.                 {  
  418.                     DebugSystem.LogError("Mainifest is Null");  
  419.                     www.Dispose();  
  420.                     yield break;  
  421.                 }  
  422.                 string[] mAssetNames = mAllBundleMainifest.GetAllAssetBundles();  
  423.                 if (mAssetNames != null)  
  424.                 {  
  425.                     foreach (var v in mAssetNames)  
  426.                     {  
  427.   
  428.                         string bundleName = v;  
  429.                         string[] bundleDependentList = mAllBundleMainifest.GetAllDependencies(v);  
  430.                         Hash128 mHash = mAllBundleMainifest.GetAssetBundleHash(v);  
  431.                         AssetBundleInfo mABInfo = new AssetBundleInfo(bundleName, mHash, bundleDependentList);  
  432.                         mNeedLoadBundleList.Add(mABInfo);  
  433.                     }  
  434.                 }  
  435.                 else  
  436.                 {  
  437.                     DebugSystem.Log("初始化资源依赖文件: Null");  
  438.                 }  
  439.                 asset.Unload(false);  
  440.                 DebugSystem.Log("初始化资源管理器全局Bundle信息成功");  
  441.                 www.Dispose();  
  442.   
  443.                 yield return InitLoadExternalStoreVersionConfig();  
  444.             }  
  445.         }  
  446.   
  447.         private IEnumerator InitLoadExternalStoreVersionConfig()  
  448.         {  
  449.             string url = AssetBundlePath.Instance.ExternalStorePathUrl + "/" + AssetBundlePath.versionConfigBundleName;  
  450.             WWW www = new WWW(url);  
  451.             yield return www;  
  452.             if (www.isDone)  
  453.             {  
  454.                 if (!string.IsNullOrEmpty(www.error))  
  455.                 {  
  456.                     DebugSystem.LogError("www Load Error:" + www.error);  
  457.                     www.Dispose();  
  458.                     yield break;  
  459.                 }  
  460.             }  
  461.             AssetBundle mConfigBundle = www.assetBundle;  
  462.             TextAsset mVersionConfig = mConfigBundle.LoadAsset<TextAsset>(AssetBundlePath.versionConfigAssetName);  
  463.             VersionId = GetVersionIdByParseXML(mVersionConfig);  
  464.             DebugSystem.Log("当前版本号:"+VersionId);  
  465.             mConfigBundle.Unload(false);  
  466.             www.Dispose();  
  467.         }  
  468.   
  469.         private int GetVersionIdByParseXML(TextAsset mTextAsset)  
  470.         {  
  471.             XmlDocument mdoc = new XmlDocument();  
  472.             mdoc.LoadXml(mTextAsset.text);  
  473.             foreach (XmlNode v in mdoc.ChildNodes)  
  474.             {  
  475.                 if (v.Name == "root")  
  476.                 {  
  477.                     foreach (XmlNode x in v.ChildNodes)  
  478.                     {  
  479.                         if (x.Name.Contains("versionId"))  
  480.                         {  
  481.                             return int.Parse(x.InnerText);  
  482.                         }  
  483.                     }  
  484.                 }  
  485.             }  
  486.             return 0;  
  487.         }  
  488.     }  
  489.   
  490.     public class AssetBundleInfo  
  491.     {  
  492.         public string bundleName;  
  493.         public Hash128 mHash;  
  494.         public string[] mDependentBundleList;  
  495.   
  496.         public AssetBundleInfo(string bundleName, Hash128 mHash128, string[] mDependentBundleList)  
  497.         {  
  498.             this.bundleName = bundleName;  
  499.             this.mHash = mHash128;  
  500.             this.mDependentBundleList = mDependentBundleList;  
  501.         }  
  502.   
  503.     }  
  504.   
  505.     public class AssetInfo  
  506.     {  
  507.         public string bundleName;  
  508.         public string assetName;  
  509.         public string assetPath;  
  510.   
  511.         public AssetInfo(string assetPath,string bundleName, string assetName)  
  512.         {  
  513.             this.assetPath = assetPath;  
  514.             this.bundleName = bundleName;  
  515.             this.assetName = assetName;  
  516.         }  
  517.   
  518.         public AssetInfo(string bundleName, string assetName)  
  519.         {  
  520.             this.bundleName = bundleName;  
  521.             this.assetName = assetName;  
  522.         }  
  523.     }  
  524.   
  525.     public class AssetBundlePath : Singleton<AssetBundlePath>  
  526.     {  
  527.         public const string versionConfigBundleName = "version.xk_unity3d";  
  528.         public const string versionConfigAssetName = "version.xml";  
  529.         public const string AssetDependentFileBundleName = "StreamingAssets";  
  530.         public const string AssetDependentFileAssetName = "AssetBundleManifest";  
  531.         public const string ABExtention = ".xk_unity3d";  
  532.   
  533.         public readonly string StreamingAssetPathUrl;  
  534.         public readonly string ExternalStorePathUrl;  
  535.         public readonly string WebServerPathUrl;  
  536.   
  537.         public readonly string ExternalStorePath;  
  538.         public AssetBundlePath()  
  539.         {  
  540.             if (Application.platform == RuntimePlatform.WindowsEditor)  
  541.             {  
  542.                 WebServerPathUrl = "file:///F:/WebServer";  
  543.                 StreamingAssetPathUrl = "file:///" + Application.streamingAssetsPath;  
  544.                 ExternalStorePathUrl = "file:///" + Application.persistentDataPath;  
  545.                 ExternalStorePath = Application.persistentDataPath;  
  546.             } else if (Application.platform == RuntimePlatform.WindowsPlayer)  
  547.             {  
  548.                 WebServerPathUrl = "file:///F:/WebServer";  
  549.                 StreamingAssetPathUrl = "file:///" + Application.streamingAssetsPath;  
  550.                 ExternalStorePathUrl = "file:///" + Application.persistentDataPath;  
  551.                 ExternalStorePath = Application.persistentDataPath;  
  552.             }else if(Application.platform == RuntimePlatform.Android)  
  553.             {  
  554.                 WebServerPathUrl = "file:///F:/WebServer";  
  555.                 StreamingAssetPathUrl = "jar:file://" + Application.dataPath + "!/assets";  
  556.                 ExternalStorePathUrl = "file://" + Application.persistentDataPath;  
  557.                 ExternalStorePath = Application.persistentDataPath;  
  558.             }  
  559.             DebugSystem.LogError("www server path: " + WebServerPathUrl);  
  560.             DebugSystem.LogError("www local Stream Path: " + StreamingAssetPathUrl);  
  561.             DebugSystem.LogError("www local external Path: " + ExternalStorePathUrl);  
  562.         }  
  563.     }  
  564.   
  565. }  
3:加载完本地的Bundle文件,那么现在我们开始下载Web服务器上的Bundle文件:
注意:本来我是自己定义一个md5配置文件专门用来比对资源,后来发现,Unity已经帮我们实现了这个功能。这个关键点就在于AssetBundleManifest类,具体请参考这篇文章末尾所讲的资源依赖配置文件:http://liweizhaolili.blog.163.com/blog/static/16230744201541410275298/
下载Web服务器资源代码如下:
[csharp] view plain copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3. using xk_System.Debug;  
  4. using System.Collections.Generic;  
  5. using xk_System.AssetPackage;  
  6. using System.IO;  
  7. using System.Xml;  
  8.   
  9. namespace xk_System.HotUpdate  
  10. {  
  11.     public class AssetBundleHotUpdateManager : Singleton<AssetBundleHotUpdateManager>  
  12.     {  
  13.         private int mStreamFolderVersionId=-1;  
  14.         private int mExternalStoreVersionId=-1;  
  15.         private int mWebServerVersionId=-1;  
  16.   
  17.         private List<AssetBundleInfo> mExternalStoreABInfoList = new List<AssetBundleInfo>();  
  18.         private List<AssetBundleInfo> mWebServerABInfoList = new List<AssetBundleInfo>();  
  19.         private List<AssetBundleInfo> mStreamFolderABInfoList = new List<AssetBundleInfo>();  
  20.   
  21.         private DownLoadAssetInfo mDownLoadAssetInfo = new DownLoadAssetInfo();  
  22.   
  23.         public LoadProgressInfo mTask = new LoadProgressInfo();  
  24.   
  25.         public IEnumerator CheckUpdate()  
  26.         {  
  27.             mTask.progress = 0;  
  28.             mTask.Des = "正在检查资源";  
  29.             yield return CheckVersionConfig();  
  30.             if (mDownLoadAssetInfo.mAssetNameList.Count > 0)  
  31.             {  
  32.                 mTask.progress += 10;  
  33.                 mTask.Des = "正在下载资源";  
  34.                 yield return DownLoadAllNeedUpdateBundle();  
  35.             }  
  36.             else  
  37.             {  
  38.                 mTask.progress = 100;  
  39.             }  
  40.         }  
  41.   
  42.         /// <summary>  
  43.         /// 检查版本配置文件  
  44.         /// </summary>  
  45.         /// <returns></returns>  
  46.         private IEnumerator CheckVersionConfig()  
  47.         {  
  48.             yield return InitLoadExternalStoreVersionConfig();  
  49.             yield return InitLoadStreamFolderVersionConfig();  
  50.             yield return InitLoadWebServerVersionConfig();  
  51.   
  52.             DebugSystem.Log("本地版本号:" + mExternalStoreVersionId);  
  53.             DebugSystem.Log("WebServer版本号:" + mWebServerVersionId);  
  54.             DebugSystem.Log("StreamFolder版本号:" + mStreamFolderVersionId);  
  55.             if (mWebServerVersionId > mExternalStoreVersionId)  
  56.             {  
  57.                 yield return InitLoadExternalStoreABConfig();  
  58.                 if (mWebServerVersionId > mStreamFolderVersionId)  
  59.                 {  
  60.                     yield return InitLoadWebServerABConfig();  
  61.                     CheckAssetInfo(AssetBundlePath.Instance.WebServerPathUrl, mWebServerABInfoList);  
  62.                 }  
  63.                 else  
  64.                 {  
  65.                     yield return InitLoadStreamFolderABConfig();  
  66.                     CheckAssetInfo(AssetBundlePath.Instance.StreamingAssetPathUrl, mStreamFolderABInfoList);  
  67.                 }  
  68.             }  
  69.             else if (mStreamFolderVersionId > mExternalStoreVersionId)  
  70.             {  
  71.                 yield return InitLoadExternalStoreABConfig();  
  72.                 yield return InitLoadStreamFolderABConfig();  
  73.                 CheckAssetInfo(AssetBundlePath.Instance.StreamingAssetPathUrl, mStreamFolderABInfoList);  
  74.             }  
  75.         }  
  76.   
  77.         /// <summary>  
  78.         /// 检查资源配置文件  
  79.         /// </summary>  
  80.         /// <returns></returns>  
  81.         private void CheckAssetInfo(string url, List<AssetBundleInfo> mUpdateABInfoList)  
  82.         {  
  83.             mDownLoadAssetInfo.url = url;  
  84.             foreach (AssetBundleInfo k in mUpdateABInfoList)  
  85.             {  
  86.                 AssetBundleInfo mBundleInfo = mExternalStoreABInfoList.Find((x) =>  
  87.                 {  
  88.                     if (x.mHash.isValid && k.mHash.isValid)  
  89.                     {  
  90.                         return x.mHash.Equals(k.mHash);  
  91.                     }  
  92.                     else  
  93.                     {  
  94.                         DebugSystem.LogError("Hash is no Valid");  
  95.                         return false;  
  96.                     }  
  97.                 });  
  98.                 if (mBundleInfo == null)  
  99.                 {  
  100.                     mDownLoadAssetInfo.mAssetNameList.Add(k.bundleName);  
  101.                 }  
  102.             }  
  103.             if (mDownLoadAssetInfo.mAssetNameList.Count > 0)  
  104.             {  
  105.                 mDownLoadAssetInfo.mAssetNameList.Add(AssetBundlePath.AssetDependentFileBundleName);  
  106.             }  
  107.             DebugSystem.Log("需要下载更新的个数:" + mDownLoadAssetInfo.mAssetNameList.Count);  
  108.         }  
  109.   
  110.         private IEnumerator InitLoadWebServerVersionConfig()  
  111.         {  
  112.             string url = AssetBundlePath.Instance.WebServerPathUrl + "/" + AssetBundlePath.versionConfigBundleName;  
  113.             WWW www = new WWW(url);  
  114.             yield return www;  
  115.             if (www.isDone)  
  116.             {  
  117.                 if (!string.IsNullOrEmpty(www.error))  
  118.                 {  
  119.                     DebugSystem.LogError("www Load Error:" + www.error);  
  120.                     www.Dispose();  
  121.                     yield break;  
  122.                 }  
  123.             }  
  124.   
  125.             AssetBundle mConfigBundle = www.assetBundle;  
  126.             TextAsset mVersionConfig = mConfigBundle.LoadAsset<TextAsset>(AssetBundlePath.versionConfigAssetName);  
  127.             mWebServerVersionId = ParseXML(mVersionConfig);  
  128.             mConfigBundle.Unload(false);  
  129.             www.Dispose();  
  130.         }  
  131.   
  132.         private IEnumerator InitLoadExternalStoreVersionConfig()  
  133.         {  
  134.             string url = AssetBundlePath.Instance.ExternalStorePathUrl + "/" + AssetBundlePath.versionConfigBundleName;  
  135.             WWW www = new WWW(url);  
  136.             yield return www;  
  137.             if (www.isDone)  
  138.             {  
  139.                 if (!string.IsNullOrEmpty(www.error))  
  140.                 {  
  141.                     DebugSystem.LogError("www Load Error:" + www.error);  
  142.                     www.Dispose();  
  143.                     yield break;  
  144.                 }  
  145.             }  
  146.             AssetBundle mConfigBundle = www.assetBundle;  
  147.             TextAsset mVersionConfig = mConfigBundle.LoadAsset<TextAsset>(AssetBundlePath.versionConfigAssetName);  
  148.             mExternalStoreVersionId = ParseXML(mVersionConfig);  
  149.             mConfigBundle.Unload(false);  
  150.             www.Dispose();  
  151.         }  
  152.   
  153.         private IEnumerator InitLoadStreamFolderVersionConfig()  
  154.         {  
  155.             string url = AssetBundlePath.Instance.StreamingAssetPathUrl + "/" + AssetBundlePath.versionConfigBundleName;  
  156.             WWW www = new WWW(url);  
  157.             yield return www;  
  158.             if (www.isDone)  
  159.             {  
  160.                 if (!string.IsNullOrEmpty(www.error))  
  161.                 {  
  162.                     DebugSystem.LogError("www Load Error:" + www.error);  
  163.                     www.Dispose();  
  164.                     yield break;  
  165.                 }  
  166.             }  
  167.             AssetBundle mConfigBundle = www.assetBundle;  
  168.             TextAsset mVersionConfig = mConfigBundle.LoadAsset<TextAsset>(AssetBundlePath.versionConfigAssetName);  
  169.             mStreamFolderVersionId = ParseXML(mVersionConfig);  
  170.             mConfigBundle.Unload(false);  
  171.             www.Dispose();  
  172.         }  
  173.   
  174.         private IEnumerator InitLoadWebServerABConfig()  
  175.         {  
  176.             string url = AssetBundlePath.Instance.WebServerPathUrl + "/" + AssetBundlePath.AssetDependentFileBundleName;  
  177.             WWW www = new WWW(url);  
  178.             yield return www;  
  179.             if (www.isDone)  
  180.             {  
  181.                 if (!string.IsNullOrEmpty(www.error))  
  182.                 {  
  183.                     DebugSystem.LogError("www Load Error:" + www.error);  
  184.                     www.Dispose();  
  185.                     yield break;  
  186.                 }  
  187.             }  
  188.             AssetBundle mConfigBundle = www.assetBundle;  
  189.             AssetBundleManifest mAllBundleMainifest = mConfigBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");  
  190.             if (mAllBundleMainifest == null)  
  191.             {  
  192.                 DebugSystem.LogError("Mainifest is Null");  
  193.                 www.Dispose();  
  194.                 yield break;  
  195.             }  
  196.             string[] mAssetNames = mAllBundleMainifest.GetAllAssetBundles();  
  197.             if (mAssetNames != null)  
  198.             {  
  199.                 foreach (var v in mAssetNames)  
  200.                 {  
  201.                     string bundleName = v;  
  202.                     string[] bundleDependentList = mAllBundleMainifest.GetAllDependencies(v);  
  203.                     Hash128 mHash = mAllBundleMainifest.GetAssetBundleHash(v);  
  204.                     AssetBundleInfo mABInfo = new AssetBundleInfo(bundleName, mHash, bundleDependentList);  
  205.                     mWebServerABInfoList.Add(mABInfo);  
  206.                 }  
  207.             }  
  208.             else  
  209.             {  
  210.                 DebugSystem.Log("初始化资源依赖文件: Null");  
  211.             }  
  212.             mConfigBundle.Unload(false);  
  213.             www.Dispose();  
  214.         }  
  215.   
  216.         private IEnumerator InitLoadExternalStoreABConfig()  
  217.         {  
  218.             string url = AssetBundlePath.Instance.ExternalStorePathUrl + "/" + AssetBundlePath.AssetDependentFileBundleName;  
  219.             WWW www = new WWW(url);  
  220.             yield return www;  
  221.             if (www.isDone)  
  222.             {  
  223.                 if (!string.IsNullOrEmpty(www.error))  
  224.                 {  
  225.                     DebugSystem.LogError("www Load Error:" + www.error);  
  226.                     www.Dispose();  
  227.                     yield break;  
  228.                 }  
  229.             }  
  230.             AssetBundle mConfigBundle = www.assetBundle;  
  231.             AssetBundleManifest mAllBundleMainifest = mConfigBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");  
  232.             if (mAllBundleMainifest == null)  
  233.             {  
  234.                 DebugSystem.LogError("Mainifest is Null");  
  235.                 www.Dispose();  
  236.                 yield break;  
  237.             }  
  238.             string[] mAssetNames = mAllBundleMainifest.GetAllAssetBundles();  
  239.             if (mAssetNames != null)  
  240.             {  
  241.                 foreach (var v in mAssetNames)  
  242.                 {  
  243.                     string bundleName = v;  
  244.                     string[] bundleDependentList = mAllBundleMainifest.GetAllDependencies(v);  
  245.                     Hash128 mHash = mAllBundleMainifest.GetAssetBundleHash(v);  
  246.                     AssetBundleInfo mABInfo = new AssetBundleInfo(bundleName, mHash, bundleDependentList);  
  247.                     mExternalStoreABInfoList.Add(mABInfo);  
  248.                 }  
  249.             }  
  250.             else  
  251.             {  
  252.                 DebugSystem.Log("初始化资源依赖文件: Null");  
  253.             }  
  254.             mConfigBundle.Unload(false);  
  255.             www.Dispose();  
  256.         }  
  257.   
  258.         private IEnumerator InitLoadStreamFolderABConfig()  
  259.         {  
  260.             string url = AssetBundlePath.Instance.StreamingAssetPathUrl + "/" + AssetBundlePath.AssetDependentFileBundleName;  
  261.             WWW www = new WWW(url);  
  262.             yield return www;  
  263.             if (www.isDone)  
  264.             {  
  265.                 if (!string.IsNullOrEmpty(www.error))  
  266.                 {  
  267.                     DebugSystem.LogError("www Load Error:" + www.error);  
  268.                     www.Dispose();  
  269.                     yield break;  
  270.                 }  
  271.             }  
  272.             AssetBundle mConfigBundle = www.assetBundle;  
  273.             AssetBundleManifest mAllBundleMainifest = mConfigBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");  
  274.             if (mAllBundleMainifest == null)  
  275.             {  
  276.                 DebugSystem.LogError("Mainifest is Null");  
  277.                 www.Dispose();  
  278.                 yield break;  
  279.             }  
  280.             string[] mAssetNames = mAllBundleMainifest.GetAllAssetBundles();  
  281.             if (mAssetNames != null)  
  282.             {  
  283.                 foreach (var v in mAssetNames)  
  284.                 {  
  285.                     string bundleName = v;  
  286.                     string[] bundleDependentList = mAllBundleMainifest.GetAllDependencies(v);  
  287.                     Hash128 mHash = mAllBundleMainifest.GetAssetBundleHash(v);  
  288.                     AssetBundleInfo mABInfo = new AssetBundleInfo(bundleName, mHash, bundleDependentList);  
  289.                     mStreamFolderABInfoList.Add(mABInfo);  
  290.                 }  
  291.             }  
  292.             else  
  293.             {  
  294.                 DebugSystem.Log("初始化资源依赖文件: Null");  
  295.             }  
  296.             mConfigBundle.Unload(false);  
  297.             www.Dispose();  
  298.         }  
  299.   
  300.         /// <summary>  
  301.         /// 得到版本号  
  302.         /// </summary>  
  303.         /// <param name="mbytes"></param>  
  304.         /// <returns></returns>  
  305.         public int ParseXML(TextAsset mTextAsset)  
  306.         {  
  307.             XmlDocument mdoc = new XmlDocument();  
  308.             mdoc.LoadXml(mTextAsset.text);  
  309.             foreach (XmlNode v in mdoc.ChildNodes)  
  310.             {  
  311.                 if (v.Name == "root")  
  312.                 {  
  313.                     foreach (XmlNode x in v.ChildNodes)  
  314.                     {  
  315.                         if (x.Name.Contains("versionId"))  
  316.                         {  
  317.                             return int.Parse(x.InnerText);  
  318.                         }  
  319.                     }  
  320.                 }  
  321.             }  
  322.             return 0;  
  323.         }  
  324.   
  325.         private IEnumerator DownLoadAllNeedUpdateBundle()  
  326.         {  
  327.             List<string> bundleList = mDownLoadAssetInfo.mAssetNameList;  
  328.             List<string>.Enumerator mIter = bundleList.GetEnumerator();  
  329.   
  330.             uint addPro = (uint)Mathf.CeilToInt((LoadProgressInfo.MaxProgress - mTask.progress)/(float)bundleList.Count);  
  331.             while (mIter.MoveNext())  
  332.             {  
  333.                 DebugSystem.LogError("下载的文件:" + mDownLoadAssetInfo.url + " | " + mIter.Current);  
  334.                 yield return DownLoadSingleBundle(mDownLoadAssetInfo.url, mIter.Current);  
  335.                 mTask.progress+=addPro;  
  336.             }  
  337.         }  
  338.   
  339.         private IEnumerator DownLoadSingleBundle(string path, string bundleName)  
  340.         {  
  341.             string url = path + "/" + bundleName;  
  342.             WWW www = new WWW(url);  
  343.             yield return www;  
  344.             if (www.isDone)  
  345.             {  
  346.                 if (!string.IsNullOrEmpty(www.error))  
  347.                 {  
  348.                     DebugSystem.LogError("www Load Error:" + www.error);  
  349.                     www.Dispose();  
  350.                     yield break;  
  351.                 }  
  352.             }  
  353.             string savePath = AssetBundlePath.Instance.ExternalStorePath + "/" + bundleName;  
  354.             SaveDownLoadedFile(savePath, www.bytes);  
  355.             www.Dispose();  
  356.         }  
  357.   
  358.         private void SaveDownLoadedFile(string path, byte[] mdata)  
  359.         {  
  360.             if (File.Exists(path))  
  361.             {  
  362.                 File.Delete(path);  
  363.             }  
  364.             FileInfo mFileInfo = new FileInfo(path);  
  365.             FileStream mFileStream = mFileInfo.OpenWrite();  
  366.             mFileStream.Write(mdata, 0, mdata.Length);  
  367.             mFileStream.Flush();  
  368.             mFileStream.Close();  
  369.         }  
  370.   
  371.         private class DownLoadAssetInfo  
  372.         {  
  373.             public string url;  
  374.             public List<string> mAssetNameList = new List<string>();  
  375.         }  
  376.   
  377.   
  378.     }  
  379. }  

现在 资源管理架构设计就完了。

二: C#反射热更新(网上热更新的传说,多数资料都是简单一笔带过)

1:如何编译Unity代码,生成程序集:
Unity工程本身编译的程序集会放在ProjectLibraryScriptAssemblies文件夹下,所以刚开始我是直接拿这个去加载程序集的,后来发现不行。
因为加载的程序集,与本地程序集重名,Unity会认为加载的程序集,还是本地程序集。(测过结果就是这样)
所以后来,通过VS2015编译Unity工程,但遇到一个问题:build的时候报了一大堆错误,错误的原因在于,Proto 生成的cs文件 所用的.net版本过高导致的。
你可以重新新build Protobuf 源码,然后生成.net低版本的程序集,这样做是可以的。

2:加载程序集,代码如下
[csharp] view plain copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3. using System.Reflection;  
  4. using xk_System.Debug;  
  5. using System;  
  6.   
  7. namespace xk_System.AssetPackage  
  8. {  
  9.     public class AssemblyManager : Singleton<AssemblyManager>  
  10.     {  
  11.         private Assembly mHotUpdateAssembly;  
  12.         private Assembly mCurrentAssembly;  
  13.         /// <summary>  
  14.         /// 加载程序集  
  15.         /// </summary>  
  16.         /// <returns></returns>  
  17.         public IEnumerator LoadAssembly()  
  18.         {  
  19.             AssetInfo mAssetInfo = ResourceABsFolder.Instance.scripts.mtest;  
  20.             string path = AssetBundlePath.Instance.ExternalStorePathUrl;  
  21.   
  22.             string bundleName1 = mAssetInfo.bundleName;  
  23.             string url = path + "/" + bundleName1;  
  24.             WWW www = new WWW(url);  
  25.             yield return www;  
  26.             if (www.isDone)  
  27.             {  
  28.                 if (!string.IsNullOrEmpty(www.error))  
  29.                 {  
  30.                     DebugSystem.LogError("www Load Error:" + www.error);  
  31.                     yield break;  
  32.                 }  
  33.             }  
  34.             AssetBundle mConfigBundle = www.assetBundle;  
  35.             TextAsset mAsset = mConfigBundle.LoadAsset<TextAsset>(mAssetInfo.assetName);  
  36.             mHotUpdateAssembly = Assembly.Load(mAsset.bytes);  
  37.             if (mHotUpdateAssembly != null)  
  38.             {  
  39.                 DebugSystem.Log("加载程序集:" + mHotUpdateAssembly.FullName);  
  40.             }  
  41.             else  
  42.             {  
  43.                 DebugSystem.Log("加载程序集: null");  
  44.             }  
  45.             mCurrentAssembly = this.GetType().Assembly;  
  46.             DebugSystem.Log("当前程序集:" + mCurrentAssembly.FullName);  
  47.             if (mCurrentAssembly.FullName.Equals(mHotUpdateAssembly.FullName))  
  48.             {  
  49.                 DebugSystem.LogError("加载程序集名字有误");  
  50.             }  
  51.             mConfigBundle.Unload(false);  
  52.         }  
  53.   
  54.         public object CreateInstance(string typeFullName)  
  55.         {  
  56.             if (mHotUpdateAssembly != null)  
  57.             {  
  58.                 return mHotUpdateAssembly.CreateInstance(typeFullName);  
  59.             }  
  60.             else  
  61.             {  
  62.                return mCurrentAssembly.CreateInstance(typeFullName);  
  63.             }  
  64.         }  
  65.   
  66.         /// <summary>  
  67.         /// 仅仅写入口时,调用。(否则,会使程序变得混乱,反正我是搞乱了)  
  68.         /// </summary>  
  69.         /// <param name="obj"></param>  
  70.         /// <param name="typeFullName"></param>  
  71.         /// <returns></returns>  
  72.         public Component AddComponent(GameObject obj, string typeFullName)  
  73.         {  
  74.             DebugSystem.Log("Type: " + typeFullName);  
  75.             if (mHotUpdateAssembly != null)  
  76.             {  
  77.                 Type mType = mHotUpdateAssembly.GetType(typeFullName);  
  78.                 return obj.AddComponent(mType);  
  79.             }  
  80.             else  
  81.             {  
  82.                 Type mType = typeFullName.GetType();  
  83.                 return obj.AddComponent(mType);  
  84.             }  
  85.         }  
  86.     }  
  87. }  

3:加载完程序集后该如何使用这个程序集就是重点了。
刚开始想这个问题的时候感觉无非反射了这么简单的问题,后来越想感觉越复杂,幸好,崩溃完了之后,发现其实,你只要遵守2点即可实现游戏代码全部更新。(1):我们前面已经做完了,加载资源和加载程序集的工作,那么我们现在要做的工作,就是实现这个新加载的程序集的入口。切记,这个入口要通过动态添加组件的方式出现。如:  
              Type mType = mHotUpdateAssembly.GetType(typeFullName);obj.AddComponent(mType);
(2):要注意所有的预制件上要动态添加脚本,否则,预制件会去寻找【本地程序集】的脚本添加上去,并且还会导致【本地程序集】与【热更新程序集】相互访问的问题。
在这里要注意一点:因为我们已经提供了【热更新程序集】的入口,所以,接下来程序动态添加脚本就会使用【热更新程序集】里脚本。千万不要再去反射程序集里某某个脚本了,加载脚本,还和以前一样写就好了。如:

obj.AddComponent<T>(); 这里与入口动态添加的方式可不一样啊。(没有反射的)。

原文地址:https://www.cnblogs.com/nafio/p/9136996.html