Unity5 AssetBundle资源管理架构设计

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


本文参考的AssetBundle技术文章:http://liweizhaolili.blog.163.com/blog/static/16230744201541410275298/

本文介绍两大内容:

1:Unity5 资源管理架构设计

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.getSingle().ABExtention;  
  10.     static string BuildAssetPath = "Assets/ResourceABs";  
  11.     static string CsOutPath = "Assets/Scripts/auto";  
  12.   
  13.     //~~~~~~~~~~~~~~~~~~~~~~~~~~~~创建AB文件所有的信息~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
  14.     [MenuItem("UnityEditor/Asset/Auto Generic Cs File")]  
  15.     public static void GenericABInfo()  
  16.     {  
  17.         CreateABCSFile();  
  18.         Debug.Log("创建资源cs文件完成");  
  19.     }  
  20.   
  21.     public static void CreateABCSFile()  
  22.     {  
  23.         string m = "using UnityEngine;\nusing System.Collections;\nusing xk_System.BaseClass;\n";  
  24.         m += "namespace xk_System.AssetPackage\n{\n";  
  25.         DirectoryInfo mDir = new DirectoryInfo(BuildAssetPath);  
  26.         m += "\tpublic class " + mDir.Name + "Folder : Single<" + mDir.Name + "Folder>\n\t{\n";  
  27.         string s = "";  
  28.         foreach (var v in mDir.GetDirectories())  
  29.         {  
  30.             FileInfo[] mFileInfos1 = v.GetFiles();  
  31.             int mFilesLength1 = 0;  
  32.             foreach (var v1 in mFileInfos1)  
  33.             {  
  34.                 if (v1.Extension != ".meta")  
  35.                 {  
  36.                     mFilesLength1++;  
  37.                     break;  
  38.                 }  
  39.             }  
  40.             if (mFilesLength1 > 0 || v.GetDirectories().Length > 0)  
  41.             {  
  42.                 string fieldName = v.Name + "Folder";  
  43.                 m += "\t\t public " + fieldName + " " + v.Name + "=new " + fieldName + "();\n";  
  44.             }  
  45.             s += CreateDirClass(v, v.Name.ToLower());  
  46.         }  
  47.         m += "\t}\n";  
  48.         m += s;  
  49.         m += "}\n";  
  50.         string fileName = CsOutPath + "/" + mDir.Name + ".cs";  
  51.         StreamWriter mSw = new StreamWriter(fileName, false);  
  52.         mSw.Write(m);  
  53.         mSw.Close();  
  54.     }  
  55.   
  56.     public static string CreateDirClass(DirectoryInfo mDir, string bundleName)  
  57.     {  
  58.         string m = "";  
  59.         string s = "";  
  60.         FileInfo[] mFileInfos = mDir.GetFiles();  
  61.         int mFilesLength = 0;  
  62.         foreach (var v in mFileInfos)  
  63.         {  
  64.             if (v.Extension != ".meta")  
  65.             {  
  66.                 mFilesLength++;  
  67.                 break;  
  68.             }  
  69.         }  
  70.         if (mFilesLength > 0)  
  71.         {  
  72.             string bundleName1 = bundleName+ extention;  
  73.             m = "\tpublic class " + mDir.Name + "Folder\n\t{\n";  
  74.             foreach (var v in mFileInfos)  
  75.             {  
  76.                 if (v.Extension != ".meta")  
  77.                 {  
  78.                     string fileName = v.Name.Substring(0, v.Name.LastIndexOf(v.Extension));  
  79.                     m += "\t\t public AssetInfo m" + fileName + "=new AssetInfo(\"" + bundleName1 + "\",\"" + v.Name + "\");\n";  
  80.                 }  
  81.             }  
  82.             m += "\t}\n";  
  83.         }  
  84.         else  
  85.         {  
  86.             if (mDir.GetDirectories().Length > 0)  
  87.             {  
  88.   
  89.                 m = "\tpublic class " + mDir.Name + "Folder\n\t{\n";  
  90.                 foreach (var v in mDir.GetDirectories())  
  91.                 {  
  92.                     FileInfo[] mFileInfos1 = v.GetFiles();  
  93.                     int mFilesLength1 = 0;  
  94.                     foreach (var v1 in mFileInfos1)  
  95.                     {  
  96.                         if (v1.Extension != ".meta")  
  97.                         {  
  98.                             mFilesLength1++;  
  99.                             break;  
  100.                         }  
  101.                     }  
  102.                     if (mFilesLength1 > 0 || v.GetDirectories().Length > 0)  
  103.                     {  
  104.                         string fieldName = v.Name + "Folder";  
  105.                         m += "\t\t public " + fieldName + " " + v.Name + "=new " + fieldName + "();\n";  
  106.                     }  
  107.                     s += CreateDirClass(v, bundleName+"_"+v.Name.ToLower());  
  108.                 }  
  109.                 m += "\t}\n";  
  110.                 m += s;  
  111.             }  
  112.         }  
  113.         return m;  
  114.     }  
  115.   
  116. }  
生成的资源信息管理类的代码样式如下:
 
 
 
[csharp] view plain copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3. using xk_System.BaseClass;  
  4. namespace xk_System.AssetPackage  
  5. {  
  6.     public class ResourceABsFolder : Single<ResourceABsFolder>  
  7.     {  
  8.          public atlasFolder atlas=new atlasFolder();  
  9.          public managerFolder manager=new managerFolder();  
  10.          public scriptsFolder scripts=new scriptsFolder();  
  11.          public sheetFolder sheet=new sheetFolder();  
  12.          public viewFolder view=new viewFolder();  
  13.     }  
  14.   
  15.     public class atlasFolder  
  16.     {  
  17.          public loginFolder login=new loginFolder();  
  18.     }  
  19.   
  20.     public class loginFolder  
  21.     {  
  22.          public AssetInfo m111=new AssetInfo("atlas_login.xk_unity3d","111.jpg");  
  23.          public AssetInfo m222=new AssetInfo("atlas_login.xk_unity3d","222.jpg");  
  24.          public AssetInfo m333=new AssetInfo("atlas_login.xk_unity3d","333.jpg");  
  25.          public AssetInfo m444=new AssetInfo("atlas_login.xk_unity3d","444.jpg");  
  26.          public AssetInfo mbackground_fwqgx_00=new AssetInfo("atlas_login.xk_unity3d","background_fwqgx_00.png");  
  27.          public AssetInfo mbackground_fwqgx_1=new AssetInfo("atlas_login.xk_unity3d","background_fwqgx_1.png");  
  28.          public AssetInfo mbackground_gx_00=new AssetInfo("atlas_login.xk_unity3d","background_gx_00.png");  
  29.          public AssetInfo mbutton_close_00=new AssetInfo("atlas_login.xk_unity3d","button_close_00.png");  
  30.          public AssetInfo mbutton_close_01=new AssetInfo("atlas_login.xk_unity3d","button_close_01.png");  
  31.          public AssetInfo mbutton_close_02=new AssetInfo("atlas_login.xk_unity3d","button_close_02.png");  
  32.          public AssetInfo mbutton_close_03=new AssetInfo("atlas_login.xk_unity3d","button_close_03.png");  
  33.          public AssetInfo mcs_bg_champions=new AssetInfo("atlas_login.xk_unity3d","cs_bg_champions.png");  
  34.          public AssetInfo mLOL_qqlogin=new AssetInfo("atlas_login.xk_unity3d","LOL_qqlogin.png");  
  35.          public AssetInfo mtips=new AssetInfo("atlas_login.xk_unity3d","tips.png");  
  36.          public AssetInfo mUdyr_bear=new AssetInfo("atlas_login.xk_unity3d","Udyr_bear.png");  
  37.          public AssetInfo mUdyr_phoenix=new AssetInfo("atlas_login.xk_unity3d","Udyr_phoenix.png");  
  38.          public AssetInfo mUdyr_tiger=new AssetInfo("atlas_login.xk_unity3d","Udyr_tiger.png");  
  39.          public AssetInfo mUdyr_turtle=new AssetInfo("atlas_login.xk_unity3d","Udyr_turtle.png");  
  40.     }  
  41.   
  42.     public class managerFolder  
  43.     {  
  44.          public AssetInfo mEventSystem=new AssetInfo("manager.xk_unity3d","EventSystem.prefab");  
  45.          public AssetInfo mGlobalWindowManager=new AssetInfo("manager.xk_unity3d","GlobalWindowManager.prefab");  
  46.          public AssetInfo mModulesWindowManager=new AssetInfo("manager.xk_unity3d","ModulesWindowManager.prefab");  
  47.     }  
  48.   
  49.     public class scriptsFolder  
  50.     {  
  51.          public AssetInfo mtest=new AssetInfo("scripts.xk_unity3d","test.bytes");  
  52.     }  
  53.   
  54.     public class sheetFolder  
  55.     {  
  56.          public AssetInfo mDB=new AssetInfo("sheet.xk_unity3d","DB.xml");  
  57.     }  
  58.   
  59.     public class viewFolder  
  60.     {  
  61.          public AssetInfo mChatView=new AssetInfo("view.xk_unity3d","ChatView.prefab");  
  62.          public AssetInfo mHotUpdateView=new AssetInfo("view.xk_unity3d","HotUpdateView.prefab");  
  63.          public AssetInfo mLoginView=new AssetInfo("view.xk_unity3d","LoginView.prefab");  
  64.          public AssetInfo mMainView=new AssetInfo("view.xk_unity3d","MainView.prefab");  
  65.          public AssetInfo mSelectServerView=new AssetInfo("view.xk_unity3d","SelectServerView.prefab");  
  66.          public AssetInfo mShareView=new AssetInfo("view.xk_unity3d","ShareView.prefab");  
  67.     }  
  68. }  
到这里,这个资源基本信息管理类就处理好了。
 
2:我们就正式开始写资源管理架构类了
 
我们首先写一个AssetBundleManager类,这个类的目的专门用来更新完毕后,充当资源加载管理器。代码如下
 
[csharp]  view plain  copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3. using xk_System.Debug;  
  4. using xk_System.BaseClass;  
  5. using System.Collections.Generic;  
  6. using System.IO;  
  7. using System.Xml;  
  8. using System;  
  9.   
  10. namespace xk_System.AssetPackage   
  11. {  
  12.     /// <summary>  
  13.     /// 此类的目的就是加载本地的Bundle进行资源读取操作的  
  14.     /// </summary>  
  15.     public class AssetBundleManager : MonoBehaviour  
  16.     {  
  17.         private static AssetBundleManager single=null;  
  18.         private ResourcesABManager mResourcesABManager = new ResourcesABManager();  
  19.   
  20.         private Dictionary<string, AssetBundle> mBundleDic = new Dictionary<string, AssetBundle>();  
  21.         private Dictionary<string, Dictionary<string, UnityEngine.Object>> mAssetDic = new Dictionary<string, Dictionary<string, UnityEngine.Object>>();  
  22.         private void Awake()  
  23.         {  
  24.             single = this;  
  25.         }  
  26.   
  27.         public static AssetBundleManager getSingle()  
  28.         {  
  29.             return single;  
  30.         }  
  31.   
  32.         /// <summary>  
  33.         /// 加载Assetbundle方案1:初始化时,全部加载  
  34.         /// </summary>  
  35.         /// <returns></returns>  
  36.         public IEnumerator InitLoadAllBundleFromLocal()  
  37.         {  
  38.             DebugSystem.Log("开始初始化本地资源");  
  39.             yield return StartCoroutine(mResourcesABManager.InitLoadMainifestFile());  
  40.             List<AssetBundleInfo> bundleList = mResourcesABManager.mNeedLoadBundleList;  
  41.             List<AssetBundleInfo>.Enumerator mIter = bundleList.GetEnumerator();  
  42.             while (mIter.MoveNext())  
  43.             {  
  44.                 yield return StartCoroutine(AsyncLoadFromLoaclSingleBundle(mIter.Current));  
  45.             }  
  46.             DebugSystem.Log("初始化本地资源完成");  
  47.         }  
  48.   
  49.         private IEnumerator CheckBundleDependentBundle(AssetBundleInfo mBundle)  
  50.         {  
  51.             string[] mdependentBundles = mBundle.mDependentBundleList;             
  52.             foreach(string s in mdependentBundles)  
  53.             {  
  54.                 AssetBundleInfo mBundleInfo = mResourcesABManager.GetBundleInfo(s);  
  55.                 if (mBundleInfo != null)  
  56.                 {  
  57.                     AssetBundle mAB = null;  
  58.                     if (!mBundleDic.TryGetValue(mBundleInfo.bundleName, out mAB))  
  59.                     {  
  60.                         yield return StartCoroutine(AsyncLoadFromLoaclSingleBundle(mBundleInfo));  
  61.                     }else  
  62.                     {  
  63.                         if(mAB==null)  
  64.                         {  
  65.                             yield return StartCoroutine(AsyncLoadFromLoaclSingleBundle(mBundleInfo));  
  66.                         }  
  67.                     }  
  68.                 }  
  69.             }  
  70.         }  
  71.   
  72.         /// <summary>  
  73.         /// 从本地外部存储位置加载单个Bundle资源,全部加载  
  74.         /// </summary>  
  75.         /// <param name="BaseBundleInfo"></param>  
  76.         /// <returns></returns>  
  77.         private IEnumerator AsyncLoadFromLoaclSingleBundle(AssetBundleInfo BaseBundleInfo)  
  78.         {  
  79.             yield return StartCoroutine(CheckBundleDependentBundle(BaseBundleInfo));  
  80.             string path = AssetBundlePath.getSingle().ExternalStorePathUrl;  
  81.             string url = path + "/" + BaseBundleInfo.bundleName;  
  82.             DebugSystem.Log("url path: " + url);  
  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.                     yield break;  
  91.                 }  
  92.             }  
  93.             AssetBundle asset = www.assetBundle;  
  94.             www.Dispose();  
  95.             SaveBundleToDic(BaseBundleInfo.bundleName, asset);  
  96.   
  97.         }  
  98.         /// <summary>  
  99.         /// 异步从本地外部存储加载单个Asset文件,只加载Bundle中的单个资源  
  100.         /// </summary>  
  101.         /// <param name="bundle"></param>  
  102.         /// <returns></returns>  
  103.         private IEnumerator AsyncLoadFromLocalSingleAsset(AssetBundleInfo bundle,string assetName)  
  104.         {  
  105.             yield return StartCoroutine(CheckBundleDependentBundle(bundle));  
  106.   
  107.             string path = AssetBundlePath.getSingle().ExternalStorePathUrl;  
  108.             string url = path + "/" + bundle.bundleName;  
  109.   
  110.             WWW www = new WWW(url);  
  111.             yield return www;  
  112.             if (www.isDone)  
  113.             {  
  114.                 if (!string.IsNullOrEmpty(www.error))  
  115.                 {  
  116.                     DebugSystem.LogError("www Load Error:" + www.error);  
  117.                     yield break;  
  118.                 }  
  119.             }  
  120.   
  121.             AssetBundle asset = www.assetBundle;  
  122.             www.Dispose();  
  123.             UnityEngine.Object Obj = asset.LoadAsset(assetName);  
  124.             if (Obj != null)  
  125.             {  
  126.                 DebugSystem.Log("Async Load Asset Success:" + Obj.name);  
  127.                 SaveAssetToDic(bundle.bundleName, assetName, Obj);  
  128.             }  
  129.             asset.Unload(false);  
  130.         }  
  131.   
  132.         /// <summary>  
  133.         /// 同步从本地外部存储加载单个Bundle文件  
  134.         /// </summary>  
  135.         /// <param name="BaseBundleInfo"></param>  
  136.         /// <param name="assetName"></param>  
  137.         /// <returns></returns>  
  138.         private UnityEngine.Object SyncLoadFromLocalSingleAsset(AssetBundleInfo BaseBundleInfo,string assetName)  
  139.         {  
  140.             string path = AssetBundlePath.getSingle().ExternalStorePathUrl;  
  141.             string url = path + "/" + BaseBundleInfo;  
  142.   
  143.             AssetBundle asset= AssetBundle.CreateFromFile(url);  
  144.             return asset.LoadAsset(assetName);  
  145.         }  
  146.   
  147.         private void SaveBundleToDic(string bundleName,AssetBundle bundle)  
  148.         {  
  149.             if(bundle==null)  
  150.             {  
  151.                 DebugSystem.LogError("保存的Bundle为空");  
  152.                 return;  
  153.             }  
  154.             mBundleDic[bundleName] = bundle;  
  155.         }  
  156.                
  157.         private void SaveAssetToDic(string bundleName, string assetName,UnityEngine.Object asset)  
  158.         {  
  159.             if(asset==null)  
  160.             {  
  161.                 DebugSystem.LogError("保存的资源为空");  
  162.                 return;  
  163.             }  
  164.             if(!mAssetDic.ContainsKey(bundleName))  
  165.             {  
  166.                 Dictionary<string, UnityEngine.Object> mDic = new Dictionary<string, UnityEngine.Object>();  
  167.                 mAssetDic.Add(bundleName,mDic);  
  168.             }  
  169.             mAssetDic[bundleName][assetName] = asset;  
  170.         }  
  171.   
  172.         private bool JudgeOrExistAsset(string bundleName, string asstName)  
  173.         {  
  174.             if (!mAssetDic.ContainsKey(bundleName) || mAssetDic[bundleName] == null || !mAssetDic[bundleName].ContainsKey(asstName) || mAssetDic[bundleName][asstName] == null)  
  175.             {  
  176.                 if (mBundleDic.ContainsKey(bundleName) && mBundleDic[bundleName] != null)  
  177.                 {  
  178.                     UnityEngine.Object mm = mBundleDic[bundleName].LoadAsset(asstName);  
  179.                     if (mm != null)  
  180.                     {  
  181.                         SaveAssetToDic(bundleName, asstName, mm);  
  182.                         return true;  
  183.                     }  
  184.                     else  
  185.                     {  
  186.                         return false;  
  187.                     }  
  188.                 }  
  189.                 else  
  190.                 {  
  191.                     return false;  
  192.                 }  
  193.             }  
  194.             return true;  
  195.         }  
  196.   
  197.         private UnityEngine.Object GetAssetFromDic(string bundleName,string asstName)  
  198.         {  
  199.             if (JudgeOrExistAsset(bundleName, asstName))  
  200.             {  
  201.                 if (mAssetDic.ContainsKey(bundleName) && mAssetDic[bundleName] != null && mAssetDic[bundleName].ContainsKey(asstName) && mAssetDic[bundleName][asstName] != null)  
  202.                 {  
  203.                     UnityEngine.Object mAsset1 = mAssetDic[bundleName][asstName];  
  204.                     mAsset1 = Instantiate(mAsset1);  
  205.                     return mAsset1;  
  206.                 }  
  207.             }else  
  208.             {  
  209.                 DebugSystem.LogError("Asset is NUll");  
  210.             }  
  211.             return null;  
  212.         }  
  213.   
  214.         /// <summary>  
  215.         /// 这个东西用来在顶层使用  
  216.         /// </summary>  
  217.         /// <param name="type"></param>  
  218.         /// <param name="assetName"></param>  
  219.         /// <returns></returns>  
  220.         public UnityEngine.Object LoadAsset(AssetInfo mAssetInfo)  
  221.         {  
  222.            return  GetAssetFromDic(mAssetInfo.bundleName, mAssetInfo.assetName);  
  223.         }  
  224.   
  225.         /// <summary>  
  226.         /// 这个东西用来在专门的管理器中使用(底层封装一下),禁止在顶层使用  
  227.         /// </summary>  
  228.         /// <param name="type"></param>  
  229.         /// <param name="assetName"></param>  
  230.         /// <returns></returns>  
  231.         public IEnumerator  AsyncLoadAsset(AssetInfo mAssetInfo)  
  232.         {  
  233.             string bundleName = mAssetInfo.bundleName;  
  234.             string asstName = mAssetInfo.assetName;  
  235.             if(!JudgeOrExistAsset(bundleName,asstName))  
  236.             {  
  237.                 yield return StartCoroutine(AsyncLoadFromLocalSingleAsset(mResourcesABManager.GetBundleInfo(bundleName), asstName));  
  238.             }  
  239.         }  
  240.     }  
  241.   
  242.     public class ResourcesABManager  
  243.     {  
  244.         public List<AssetBundleInfo> mNeedLoadBundleList = new List<AssetBundleInfo>();  
  245.         public AssetBundleInfo GetBundleInfo(string bundleName)  
  246.         {  
  247.             AssetBundleInfo mBundleInfo = mNeedLoadBundleList.Find((x) =>  
  248.             {  
  249.                 return x.bundleName == bundleName;  
  250.             });  
  251.             return mBundleInfo;  
  252.         }  
  253.   
  254.         private void ParseAssetBundleManifest(AssetBundle mConfigBundle)  
  255.         {  
  256.             AssetBundleManifest mAllBundleMainifest = mConfigBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");  
  257.             if (mAllBundleMainifest == null)  
  258.             {  
  259.                 DebugSystem.LogError("Mainifest is Null");  
  260.                 return;  
  261.             }  
  262.             string[] mAssetNames = mAllBundleMainifest.GetAllAssetBundles();  
  263.             if (mAssetNames != null)  
  264.             {  
  265.                 foreach (var v in mAssetNames)  
  266.                 {  
  267.                     string bundleName = v;  
  268.                     string[] bundleDependentList = mAllBundleMainifest.GetAllDependencies(v);  
  269.                     Hash128 mHash = mAllBundleMainifest.GetAssetBundleHash(v);  
  270.                     AssetBundleInfo mABInfo = new AssetBundleInfo(bundleName,mHash,bundleDependentList);  
  271.                     mNeedLoadBundleList.Add(mABInfo);  
  272.                 }  
  273.             }  
  274.             else  
  275.             {  
  276.                 DebugSystem.Log("初始化资源依赖文件: Null");  
  277.             }  
  278.         }  
  279.   
  280.         public IEnumerator InitLoadMainifestFile()  
  281.         {  
  282.             if(mNeedLoadBundleList.Count>0)  
  283.             {  
  284.                 yield break;  
  285.             }  
  286.             string path = AssetBundlePath.getSingle().ExternalStorePathUrl;  
  287.             string url = path + "/" + AssetBundlePath.getSingle().AssetDependentFile;  
  288.             DebugSystem.Log("url path: " + url);  
  289.             WWW www = new WWW(url);  
  290.             yield return www;  
  291.             if (www.isDone)  
  292.             {  
  293.                 if (!string.IsNullOrEmpty(www.error))  
  294.                 {  
  295.                     DebugSystem.LogError("www Load Error:" + www.error);  
  296.                     yield break;  
  297.                 }  
  298.             }  
  299.             AssetBundle asset = www.assetBundle;  
  300.             www.Dispose();  
  301.             if (asset == null)  
  302.             {  
  303.                 DebugSystem.LogError("MainifestFile Bundle is Null");  
  304.                 yield break;  
  305.             }  
  306.             ParseAssetBundleManifest(asset);  
  307.             asset.Unload(false);  
  308.         }  
  309.     }  
  310.   
  311.     public class AssetBundleInfo  
  312.     {  
  313.         public string bundleName;  
  314.         public Hash128 mHash;  
  315.         public string[] mDependentBundleList;  
  316.   
  317.         public AssetBundleInfo(string bundleName,Hash128 mHash128,string[] mDependentBundleList)  
  318.         {  
  319.             this.bundleName = bundleName;  
  320.             this.mHash = mHash128;  
  321.             this.mDependentBundleList = mDependentBundleList;  
  322.         }  
  323.     }  
  324.   
  325.     public class AssetInfo  
  326.     {  
  327.         public string bundleName;  
  328.         public string assetName;  
  329.   
  330.         public AssetInfo(string bundleName, string assetName)  
  331.         {  
  332.             this.bundleName = bundleName;  
  333.             this.assetName = assetName;  
  334.         }  
  335.     }  
  336.   
  337.     public class AssetBundlePath : Single<AssetBundlePath>  
  338.     {  
  339.         public readonly string WebServerPathUrl;  
  340.   
  341.         public readonly string versionConfig = "version.xml";  
  342.         //public readonly string ABConfig = "abconfig.xml";  
  343.         public readonly string AssetDependentFile = "StreamingAssets";  
  344.         public readonly string ABExtention = ".xk_unity3d";  
  345.   
  346.         public readonly string StreamingAssetPathUrl;  
  347.         public readonly string ExternalStorePathUrl;  
  348.   
  349.         public readonly string StreamingAssetPath;  
  350.         public readonly string ExternalStorePath;  
  351.         public AssetBundlePath()  
  352.         {  
  353. #if UNITY_EDITOR || UNITY_STANDALONE_WIN  
  354.             WebServerPathUrl = "file:///F:/WebServer";  
  355.             StreamingAssetPathUrl = "file:///" + Application.streamingAssetsPath;  
  356.             ExternalStorePathUrl = "file:///" + Application.persistentDataPath;  
  357.             ExternalStorePath = Application.persistentDataPath;  
  358.             StreamingAssetPath = Application.streamingAssetsPath;  
  359. #elif UNITY_ANDROID  
  360.             WebServerPathUrl = "file:///F:/WebServer";  
  361.             StreamingAssetsFolder ="jar:file://"+Application.streamingAssetsPath;  
  362.             ExternalStoreFolder ="file://"+Application.persistentDataPath;  
  363.             ExternalStorePath = Application.persistentDataPath;  
  364.             StreamingAssetPath = Application.streamingAssetsPath;  
  365. #elif UNITY_IPHONE  
  366.             WebServerPathUrl = "file:///F:/WebServer";  
  367.             StreamingAssetsFolder =Application.streamingAssetsPath;  
  368.             ExternalStoreFolder =Application.persistentDataPath;  
  369.             ExternalStorePath = Application.persistentDataPath;  
  370.             StreamingAssetPath = Application.streamingAssetsPath;  
  371. #endif  
  372.             //DebugSystem.LogError("www server path: " + WebServerPathUrl);  
  373.             //DebugSystem.LogError("www local Stream Path: " + StreamingAssetPathUrl);  
  374.             //DebugSystem.LogError("www local external Path: " + ExternalStorePathUrl);  
  375.         }  
  376.     }  
  377. }  
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 System.Collections.Generic;  
  4. using System.IO;  
  5. using xk_System.Debug;  
  6. using System.Xml;  
  7. using xk_System.AssetPackage;  
  8.   
  9. namespace xk_System.HotUpdate  
  10. {  
  11.     public class AssetBundleHotUpdateManager : MonoBehaviour  
  12.     {  
  13.         private List<AssetBundleInfo> mNowABInfoList = new List<AssetBundleInfo>();  
  14.         private List<AssetBundleInfo> mUpdateABInfoList = new List<AssetBundleInfo>();  
  15.   
  16.         private List<AssetBundleInfo> mNeedUpdateList = new List<AssetBundleInfo>();  
  17.         private static AssetBundleHotUpdateManager single=null;  
  18.   
  19.         private void Awake()  
  20.         {  
  21.             single = this;  
  22.         }  
  23.   
  24.         public static AssetBundleHotUpdateManager getSingle()  
  25.         {  
  26.             return single;  
  27.         }  
  28.   
  29.         public IEnumerator CheckUpdate()  
  30.         {  
  31.             DebugSystem.Log("开始校对资源");  
  32.             yield return StartCoroutine(CheckOrCopyFileToExternalStore());  
  33.             yield return StartCoroutine(CheckVersionConfig());  
  34.             yield return StartCoroutine(CheckABConfig());  
  35.             yield return StartCoroutine(DownLoadAllBundleFromWebServer());  
  36.             DebugSystem.Log("热更新资源下载完毕");  
  37.         }  
  38.   
  39.         /// <summary>  
  40.         /// 检查版本配置文件  
  41.         /// </summary>  
  42.         /// <returns></returns>  
  43.         private IEnumerator CheckVersionConfig()  
  44.         {  
  45.             yield return 0;  
  46.         }  
  47.   
  48.         /// <summary>  
  49.         /// 检查资源配置文件  
  50.         /// </summary>  
  51.         /// <returns></returns>  
  52.         private IEnumerator CheckABConfig()  
  53.         {  
  54.             yield return StartCoroutine(InitLoadLocalABConfig());  
  55.             yield return StartCoroutine(InitLoadWebServerABConfig());  
  56.             foreach (AssetBundleInfo k in mUpdateABInfoList)  
  57.             {  
  58.                 AssetBundleInfo mBundleInfo = mNowABInfoList.Find((x) =>  
  59.                 {  
  60.                     if (x.mHash.isValid && k.mHash.isValid)  
  61.                     {  
  62.                         return x.mHash.Equals(k.mHash);  
  63.                     }  
  64.                     else  
  65.                     {  
  66.                         DebugSystem.LogError("Hash is no Valid");  
  67.                         return false;  
  68.                     }  
  69.                 });  
  70.                 if (mBundleInfo == null)  
  71.                 {  
  72.                     mNeedUpdateList.Add(k);  
  73.                 }  
  74.             }           
  75.             DebugSystem.Log("需要下载更新的个数:" + mNeedUpdateList.Count);  
  76.         }  
  77.   
  78.         private IEnumerator CheckOrCopyFileToExternalStore()  
  79.         {  
  80.            /* string path =  AssetBundlePath.getSingle().ExternalStorePath; 
  81.             string StreamPath = AssetBundlePath.getSingle().StreamingAssetPath; 
  82.  
  83.             List<AssetBundleInfo> bundleList = ResourcesABManager.getSingle().mNeedLoadBundleList; 
  84.             List<AssetBundleInfo>.Enumerator mIter = bundleList.GetEnumerator(); 
  85.             while (mIter.MoveNext()) 
  86.             { 
  87.                 string bundleExternalPath = path + "/" + mIter.Current.bundleName; 
  88.                 if (!File.Exists(bundleExternalPath)) 
  89.                 { 
  90.                     string bundleStreamPath = StreamPath + "/" + mIter.Current.bundleName; 
  91.                     if (File.Exists(bundleStreamPath)) 
  92.                     { 
  93.                         File.Copy(bundleStreamPath, bundleExternalPath); 
  94.                     } 
  95.                 } 
  96.                 else 
  97.                 { 
  98.                     // yield return StartCoroutine(DownLoadAllBundleFromWebServer()); 
  99.                 } 
  100.             }*/  
  101.             yield return 0;  
  102.         }  
  103.   
  104.         private IEnumerator InitLoadWebServerABConfig()  
  105.         {  
  106.             string path = AssetBundlePath.getSingle().WebServerPathUrl;  
  107.             string bundleName1 = AssetBundlePath.getSingle().AssetDependentFile;  
  108.             string url = path + "/" + bundleName1;  
  109.             WWW www = new WWW(url);  
  110.             yield return www;  
  111.             if (www.isDone)  
  112.             {  
  113.                 if (!string.IsNullOrEmpty(www.error))  
  114.                 {  
  115.                     DebugSystem.LogError("www Load Error:" + www.error);  
  116.                     yield break;  
  117.                 }  
  118.             }  
  119.             AssetBundle mConfigBundle = www.assetBundle;  
  120.             AssetBundleManifest mAllBundleMainifest = mConfigBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");  
  121.             if (mAllBundleMainifest == null)  
  122.             {  
  123.                 DebugSystem.LogError("Mainifest is Null");  
  124.                 yield break;  
  125.             }  
  126.             string[] mAssetNames = mAllBundleMainifest.GetAllAssetBundles();  
  127.             if (mAssetNames != null)  
  128.             {  
  129.                 foreach (var v in mAssetNames)  
  130.                 {  
  131.                     string bundleName = v;  
  132.                     string[] bundleDependentList = mAllBundleMainifest.GetAllDependencies(v);  
  133.                     Hash128 mHash = mAllBundleMainifest.GetAssetBundleHash(v);  
  134.                     AssetBundleInfo mABInfo = new AssetBundleInfo(bundleName, mHash, bundleDependentList);  
  135.                     mUpdateABInfoList.Add(mABInfo);  
  136.                 }  
  137.             }  
  138.             else  
  139.             {  
  140.                 DebugSystem.Log("初始化资源依赖文件: Null");  
  141.             }  
  142.             mConfigBundle.Unload(false);  
  143.             www.Dispose();  
  144.             yield return 0;  
  145.         }  
  146.   
  147.         private IEnumerator InitLoadLocalABConfig()  
  148.         {   
  149.             string path = AssetBundlePath.getSingle().ExternalStorePathUrl;  
  150.             string bundleName1 = AssetBundlePath.getSingle().AssetDependentFile;  
  151.             string url = path + "/" + bundleName1;  
  152.             WWW www = new WWW(url);  
  153.             yield return www;  
  154.             if (www.isDone)  
  155.             {  
  156.                 if (!string.IsNullOrEmpty(www.error))  
  157.                 {  
  158.                     DebugSystem.LogError("www Load Error:" + www.error);  
  159.                     yield break;  
  160.                 }  
  161.             }  
  162.             AssetBundle mConfigBundle = www.assetBundle;  
  163.             AssetBundleManifest mAllBundleMainifest = mConfigBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");  
  164.             if (mAllBundleMainifest == null)  
  165.             {  
  166.                 DebugSystem.LogError("Mainifest is Null");  
  167.                 yield break;  
  168.             }  
  169.             string[] mAssetNames = mAllBundleMainifest.GetAllAssetBundles();  
  170.             if (mAssetNames != null)  
  171.             {  
  172.                 foreach (var v in mAssetNames)  
  173.                 {  
  174.                     string bundleName = v;  
  175.                     string[] bundleDependentList = mAllBundleMainifest.GetAllDependencies(v);  
  176.                     Hash128 mHash = mAllBundleMainifest.GetAssetBundleHash(v);  
  177.                     AssetBundleInfo mABInfo = new AssetBundleInfo(bundleName, mHash, bundleDependentList);  
  178.                     mNowABInfoList.Add(mABInfo);  
  179.                 }  
  180.             }  
  181.             else  
  182.             {  
  183.                 DebugSystem.Log("初始化资源依赖文件: Null");  
  184.             }  
  185.             mConfigBundle.Unload(false);  
  186.             www.Dispose();  
  187.             yield return 0;  
  188.         }  
  189.   
  190.         /// <summary>  
  191.         /// 用于自己定义的配置文件解析,不要删除  
  192.         /// </summary>  
  193.         /// <param name="mbytes"></param>  
  194.         /// <returns></returns>  
  195.         public Dictionary<AssetBundleInfo, string> ParseXML(byte[] mbytes)  
  196.         {  
  197.             Dictionary<AssetBundleInfo, string> mDic = new Dictionary<AssetBundleInfo, string>();  
  198.   
  199.            /* XmlDocument mdoc = new XmlDocument(); 
  200.             MemoryStream mStream = new MemoryStream(mbytes); 
  201.             mdoc.Load(mStream); 
  202.             foreach (XmlNode v in mdoc.ChildNodes) 
  203.             { 
  204.                 if (v.Name == "root") 
  205.                 { 
  206.                     foreach (XmlNode x in v.ChildNodes) 
  207.                     { 
  208.                         AssetBundleInfo info = ResourcesABManager.GetBundleInfo(x.Name); 
  209.                         if (info != null) 
  210.                         { 
  211.                             mDic.Add(info, x.InnerText); 
  212.                         } 
  213.                     } 
  214.                 } 
  215.             } */  
  216.             return mDic;  
  217.         }  
  218.   
  219.         private IEnumerator DownLoadAllBundleFromWebServer()  
  220.         {  
  221.             yield return StartCoroutine(DownLoadMainifestFromWebServer());  
  222.             List<AssetBundleInfo> bundleList = mNeedUpdateList;  
  223.             List<AssetBundleInfo>.Enumerator mIter = bundleList.GetEnumerator();  
  224.             while (mIter.MoveNext())  
  225.             {  
  226.                 DebugSystem.LogError("下载的文件:" + mIter.Current.bundleName);  
  227.                 yield return StartCoroutine(DownLoadSingleBundleFromWebServer(mIter.Current));  
  228.             }  
  229.         }  
  230.   
  231.         private IEnumerator DownLoadMainifestFromWebServer()  
  232.         {  
  233.             string path = AssetBundlePath.getSingle().WebServerPathUrl;  
  234.             string url = path + "/" + AssetBundlePath.getSingle().AssetDependentFile;  
  235.             DebugSystem.Log("url path: " + url);  
  236.             WWW www = new WWW(url);  
  237.             yield return www;  
  238.             if (www.isDone)  
  239.             {  
  240.                 if (!string.IsNullOrEmpty(www.error))  
  241.                 {  
  242.                     DebugSystem.LogError("www Load Error:" + www.error);  
  243.                     yield break;  
  244.                 }  
  245.             }  
  246.             yield return 0;  
  247.             string savePath = AssetBundlePath.getSingle().ExternalStorePath + "/" + AssetBundlePath.getSingle().AssetDependentFile;  
  248.             SaveDownLoadedFile(savePath, www.bytes);  
  249.             www.Dispose();  
  250.             yield return 0;  
  251.         }  
  252.   
  253.         //下载单个Bundle文件  
  254.         private IEnumerator DownLoadSingleBundleFromWebServer(AssetBundleInfo bundleBaseInfo)  
  255.         {  
  256.             string path = AssetBundlePath.getSingle().WebServerPathUrl;  
  257.             string url = path + "/" + bundleBaseInfo.bundleName;  
  258.             WWW www = new WWW(url);  
  259.             yield return www;  
  260.             if (www.isDone)  
  261.             {  
  262.                 if (!string.IsNullOrEmpty(www.error))  
  263.                 {  
  264.                     DebugSystem.LogError("www Load Error:" + www.error);  
  265.                     yield break;  
  266.                 }  
  267.             }  
  268.             yield return 0;  
  269.             string savePath = AssetBundlePath.getSingle().ExternalStorePath + "/" + bundleBaseInfo.bundleName;  
  270.             SaveDownLoadedFile(savePath, www.bytes);  
  271.             www.Dispose();  
  272.             yield return 0;  
  273.         }  
  274.   
  275.         private void SaveDownLoadedFile(string path, byte[] mdata)  
  276.         {  
  277.             if(File.Exists(path))  
  278.             {  
  279.                 File.Delete(path);  
  280.             }  
  281.             FileInfo mFileInfo = new FileInfo(path);  
  282.             FileStream mFileStream = mFileInfo.OpenWrite();  
  283.             mFileStream.Write(mdata, 0, mdata.Length);  
  284.             mFileStream.Flush();  
  285.             mFileStream.Close();           
  286.         }  
  287.     }  
  288. }  
现在 资源管理架构设计就完了。
 
 
 
 
 
 

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

1:如何编译Unity代码,生成程序集:

Unity工程本身编译的程序集会放在Project\Library\ScriptAssemblies文件夹下,所以刚开始我是直接拿这个去加载程序集的,后来发现不行。
因为加载的程序集,与本地程序集重名,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. using xk_System.BaseClass;  
  7. using xk_System.View;  
  8.   
  9. namespace xk_System.AssetPackage  
  10. {  
  11.     public class AssemblyManager : Single<AssemblyManager>  
  12.     {  
  13.         private Assembly mHotUpdateAssembly;  
  14.         private Assembly mCurrentAssembly;  
  15.   
  16.         public IEnumerator LoadAssembly()  
  17.         {  
  18.             AssetInfo mAssetInfo = ResourceABsFolder.getSingle().scripts.mtest;  
  19.             string path = AssetBundlePath.getSingle().ExternalStorePathUrl;  
  20.             string bundleName1 = mAssetInfo.bundleName;  
  21.             string url = path + "/" + bundleName1;  
  22.             WWW www = new WWW(url);  
  23.             yield return www;  
  24.             if (www.isDone)  
  25.             {  
  26.                 if (!string.IsNullOrEmpty(www.error))  
  27.                 {  
  28.                     DebugSystem.LogError("www Load Error:" + www.error);  
  29.                     yield break;  
  30.                 }  
  31.             }  
  32.             AssetBundle mConfigBundle = www.assetBundle;  
  33.             TextAsset mAsset = mConfigBundle.LoadAsset<TextAsset>(mAssetInfo.assetName);  
  34.             mHotUpdateAssembly = Assembly.Load(mAsset.bytes);  
  35.             if (mHotUpdateAssembly != null)  
  36.             {  
  37.                 DebugSystem.Log("加载程序集:" + mHotUpdateAssembly.FullName);  
  38.             }  
  39.             else  
  40.             {  
  41.                 DebugSystem.Log("加载程序集: null");  
  42.             }  
  43.             mCurrentAssembly = this.GetType().Assembly;  
  44.             DebugSystem.Log("当前程序集:" + mCurrentAssembly.FullName);  
  45.             if (mCurrentAssembly.FullName.Equals(mHotUpdateAssembly.FullName))  
  46.             {  
  47.                 DebugSystem.LogError("加载程序集名字有误");  
  48.             }  
  49.             mConfigBundle.Unload(false);  
  50.         }  
  51.   
  52.         public Component AddComponent(GameObject obj, string typeFullName)  
  53.         {  
  54.             DebugSystem.Log("Type: "+typeFullName);  
  55.             if (mHotUpdateAssembly != null)  
  56.             {  
  57.                 Type mType = mHotUpdateAssembly.GetType(typeFullName);  
  58.                 return obj.AddComponent(mType);  
  59.             }else  
  60.             {  
  61.                 Type mType = typeFullName.GetType();  
  62.                 return obj.AddComponent(mType);  
  63.             }  
  64.         }  
  65.     }  
  66. }  
 
 
 


3:加载完程序集后该如何使用这个程序集就是重点了。

刚开始想这个问题的时候感觉无非反射了这么简单的问题,后来越想感觉越复杂,幸好,崩溃完了之后,发现其实,你只要遵守2点即可实现游戏代码全部更新。
(1):我们前面已经做完了,加载资源和加载程序集的工作,那么我们现在要做的工作,就是实现这个新加载的程序集的入口。
切记,这个入口要通过动态添加组件的方式出现。如:                
Type mType = mHotUpdateAssembly.GetType(typeFullName);
obj.AddComponent(mType);


(2):要注意所有的预制件上要动态添加脚本,否则,预制件会去寻找【本地程序集】的脚本添加上去,并且还会导致【本地程序集】与【热更新程序集】相互访问的问题。


在这里要注意一点:因为我们已经提供了【热更新程序集】的入口,所以,接下来程序动态添加脚本就会使用【热更新程序集】里脚本。千万不要再去反射程序集里某某个脚本了,加载脚本,还和以前一样写就好了。如:

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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值