轉自https://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文件下, 代碼以下:
-
using UnityEngine;
-
using System.Collections;
-
using System.IO;
-
using UnityEditor;
-
using xk_System.AssetPackage;
-
-
public class ExportAssetInfoEditor : MonoBehaviour
-
{
-
static string extention = AssetBundlePath.ABExtention;
-
static string BuildAssetPath = "Assets/ResourceABs";
-
static string CsOutPath = "Assets/Scripts/auto";
-
-
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~建立AB文件全部的信息~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
[ MenuItem("UnityEditor/GenerationPackage/Generation AssetInfo Cs File")]
-
public static void GenericAssetCSInfo()
-
{
-
Debug.Log( "Start Generation AssetInfo Cs Info");
-
CreateABCSFile();
-
Debug.Log( "Finish Generation AssetInfo Cs Info");
-
}
-
-
private static void CreateABCSFile()
-
{
-
string m = "";
-
m += "namespace xk_System.AssetPackage\n{\n";
-
DirectoryInfo mDir = new DirectoryInfo(BuildAssetPath);
-
m += "\tpublic class " + mDir.Name + "Folder : Singleton<" + mDir.Name + "Folder>\n\t{\n";
-
string s = "";
-
foreach (var v in mDir.GetDirectories())
-
{
-
FileInfo[] mFileInfos1 = v.GetFiles();
-
int mFilesLength1 = 0;
-
foreach (var v1 in mFileInfos1)
-
{
-
if (v1.Extension != ".meta")
-
{
-
mFilesLength1++;
-
break;
-
}
-
}
-
if (mFilesLength1 > 0 || v.GetDirectories().Length > 0)
-
{
-
string fieldName = v.Name + "Folder";
-
m += "\t\t public " + fieldName + " " + v.Name + "=new " + fieldName + "();\n";
-
// s += CreateDirClass(v, v.Name.ToLower());
-
}
-
}
-
foreach (var v in mDir.GetDirectories())
-
{
-
m += CreateDirClass(v, v.Name.ToLower());
-
}
-
m += "\t}\n";
-
// m += s;
-
m += "}\n";
-
string fileName = CsOutPath + "/" + mDir.Name + ".cs";
-
StreamWriter mSw = new StreamWriter(fileName, false);
-
mSw.Write(m);
-
mSw.Close();
-
}
-
-
private static string CreateDirClass(DirectoryInfo mDir, string bundleName)
-
{
-
string tStr = GetTStr(mDir);
-
string m = "";
-
string s = "";
-
FileInfo[] mFileInfos = mDir.GetFiles();
-
int mFilesLength = 0;
-
foreach (var v in mFileInfos)
-
{
-
if (v.Extension != ".meta")
-
{
-
mFilesLength++;
-
break;
-
}
-
}
-
if (mFilesLength > 0)
-
{
-
string bundleName1 = bundleName+ extention;
-
m = tStr+ "public class " + mDir.Name + "Folder\n"+tStr+"{\n";
-
foreach (var v in mFileInfos)
-
{
-
if (v.Extension != ".meta")
-
{
-
string assetPath = GetAssetPath(v.FullName);
-
string fileName = v.Name.Substring(0, v.Name.LastIndexOf(v.Extension));
-
m += tStr+ "\t public AssetInfo m" + fileName + "=new AssetInfo(\""+assetPath+"\",\"" + bundleName1 + "\",\"" + v.Name + "\");\n";
-
}
-
}
-
m += tStr+ "}\n";
-
}
-
else
-
{
-
if (mDir.GetDirectories().Length > 0)
-
{
-
-
m = tStr+ "public class " + mDir.Name + "Folder\n"+tStr+"{\n";
-
foreach (var v in mDir.GetDirectories())
-
{
-
FileInfo[] mFileInfos1 = v.GetFiles();
-
int mFilesLength1 = 0;
-
foreach (var v1 in mFileInfos1)
-
{
-
if (v1.Extension != ".meta")
-
{
-
mFilesLength1++;
-
break;
-
}
-
}
-
if (mFilesLength1 > 0 || v.GetDirectories().Length > 0)
-
{
-
string fieldName = v.Name + "Folder";
-
m += tStr+ "\t public " + fieldName + " " + v.Name + "=new " + fieldName + "();\n";
-
}
-
}
-
foreach (var v in mDir.GetDirectories())
-
{
-
m += CreateDirClass(v, bundleName + "_" + v.Name.ToLower());
-
}
-
m += tStr+ "}\n";
-
// m += s;
-
}
-
}
-
return m;
-
}
-
public static string GetTStr(DirectoryInfo mDir)
-
{
-
int coutT = 0;
-
int index = mDir.FullName.IndexOf(@"ResourceABs\");
-
if (index >= 0)
-
{
-
for(int j=0;j<mDir.FullName.Length;j++)
-
{
-
if (j > index)
-
{
-
var v = mDir.FullName[j];
-
if (v.Equals('\\'))
-
{
-
coutT++;
-
}
-
}
-
}
-
}
-
coutT++;
-
string tStr = "";
-
int i = 0;
-
while(i<coutT)
-
{
-
tStr += "\t";
-
i++;
-
}
-
return tStr;
-
}
-
-
public static string GetAssetPath(string filePath)
-
{
-
string assetPath = "";
-
int index = filePath.IndexOf(@"Assets\");
-
if (index >= 0)
-
{
-
assetPath = filePath.Remove( 0, index);
-
assetPath = assetPath.Replace( @"\","/");
-
}
-
return assetPath;
-
}
-
-
}
到這裏,這個資源基本信息管理類就處理好了。
2:咱們就正式開始寫資源管理架構類了
咱們首先寫一個AssetBundleManager類,這個類的目的專門用來更新完畢後,充當資源加載管理器。代碼以下
2:咱們就正式開始寫資源管理架構類了
咱們首先寫一個AssetBundleManager類,這個類的目的專門用來更新完畢後,充當資源加載管理器。代碼以下
-
using UnityEngine;
-
using System.Collections;
-
using xk_System.Debug;
-
using System.Collections.Generic;
-
using System.Xml;
-
-
namespace xk_System.AssetPackage
-
{
-
/// <summary>
-
/// 此類的目的就是加載本地的Bundle進行資源讀取操做的
-
/// </summary>
-
public class AssetBundleManager : SingleTonMonoBehaviour<AssetBundleManager>
-
{
-
private ResourcesABManager mResourcesABManager = new ResourcesABManager();
-
private Dictionary<string, AssetBundle> mBundleDic = new Dictionary<string, AssetBundle>();
-
private Dictionary<string, Dictionary<string, UnityEngine.Object>> mAssetDic = new Dictionary<string, Dictionary<string, UnityEngine.Object>>();
-
private List<string> mBundleLockList = new List<string>();
-
-
/// <summary>
-
/// 加載Assetbundle方案1:初始化時,所有加載
-
/// </summary>
-
/// <returns></returns>
-
public IEnumerator InitLoadAllBundleFromLocal()
-
{
-
yield return mResourcesABManager.InitLoadMainifestFile();
-
List<AssetBundleInfo> bundleList = mResourcesABManager.mNeedLoadBundleList;
-
List<AssetBundleInfo>.Enumerator mIter = bundleList.GetEnumerator();
-
while (mIter.MoveNext())
-
{
-
yield return AsyncLoadFromLoaclSingleBundle(mIter.Current);
-
}
-
}
-
public IEnumerator InitAssetBundleManager()
-
{
-
yield return mResourcesABManager.InitLoadMainifestFile();
-
}
-
-
private IEnumerator CheckBundleDependentBundle(AssetBundleInfo mBundle)
-
{
-
if (mBundle != null)
-
{
-
string[] mdependentBundles = mBundle.mDependentBundleList;
-
foreach (string s in mdependentBundles)
-
{
-
AssetBundleInfo mBundleInfo = mResourcesABManager.GetBundleInfo(s);
-
if (mBundleInfo != null)
-
{
-
AssetBundle mAB = null;
-
if (!mBundleDic.TryGetValue(mBundleInfo.bundleName, out mAB))
-
{
-
yield return AsyncLoadFromLoaclSingleBundle(mBundleInfo);
-
}
-
else
-
{
-
if (mAB == null)
-
{
-
yield return AsyncLoadFromLoaclSingleBundle(mBundleInfo);
-
}
-
}
-
}
-
}
-
}
-
}
-
/// <summary>
-
/// 從本地外部存儲位置加載單個Bundle資源,所有加載
-
/// </summary>
-
/// <param name="BaseBundleInfo"></param>
-
/// <returns></returns>
-
private IEnumerator AsyncLoadFromLoaclSingleBundle1(AssetBundleInfo BaseBundleInfo)
-
{
-
if(mBundleLockList.Contains(BaseBundleInfo.bundleName))
-
{
-
while(mBundleLockList.Contains(BaseBundleInfo.bundleName))
-
{
-
yield return null;
-
}
-
yield break;
-
}
-
mBundleLockList.Add(BaseBundleInfo.bundleName);
-
yield return CheckBundleDependentBundle(BaseBundleInfo);
-
string path = AssetBundlePath.Instance.ExternalStorePathUrl;
-
string url = path + "/" + BaseBundleInfo.bundleName;
-
WWW www = new WWW(url);
-
yield return www;
-
if (www.isDone)
-
{
-
if (!string.IsNullOrEmpty(www.error))
-
{
-
DebugSystem.LogError( "www Load Error:" + www.error);
-
www.Dispose();
-
mBundleLockList.Remove(BaseBundleInfo.bundleName);
-
yield break;
-
}
-
}
-
AssetBundle asset = www.assetBundle;
-
SaveBundleToDic(BaseBundleInfo.bundleName, asset);
-
mBundleLockList.Remove(BaseBundleInfo.bundleName);
-
www.Dispose();
-
}
-
-
/// <summary>
-
/// 從本地外部存儲位置加載單個Bundle資源,所有加載
-
/// </summary>
-
/// <param name="BaseBundleInfo"></param>
-
/// <returns></returns>
-
private IEnumerator AsyncLoadFromLoaclSingleBundle(AssetBundleInfo BaseBundleInfo)
-
{
-
if (mBundleLockList.Contains(BaseBundleInfo.bundleName))
-
{
-
while (mBundleLockList.Contains(BaseBundleInfo.bundleName))
-
{
-
yield return null;
-
}
-
yield break;
-
}
-
mBundleLockList.Add(BaseBundleInfo.bundleName);
-
yield return CheckBundleDependentBundle(BaseBundleInfo);
-
string path = AssetBundlePath.Instance.ExternalStorePath+"/"+BaseBundleInfo.bundleName;
-
AssetBundleCreateRequest www= AssetBundle.LoadFromFileAsync(path);
-
www.allowSceneActivation = true;
-
yield return www;
-
AssetBundle asset = www.assetBundle;
-
SaveBundleToDic(BaseBundleInfo.bundleName, asset);
-
mBundleLockList.Remove(BaseBundleInfo.bundleName);
-
}
-
/// <summary>
-
/// 異步從本地外部存儲加載單個Asset文件,只加載Bundle中的單個資源
-
/// </summary>
-
/// <param name="bundle"></param>
-
/// <returns></returns>
-
private IEnumerator AsyncLoadFromLocalSingleAsset(AssetBundleInfo bundle, string assetName)
-
{
-
if (bundle != null)
-
{
-
yield return AsyncLoadFromLoaclSingleBundle(bundle);
-
UnityEngine.Object Obj = mBundleDic[bundle.bundleName].LoadAsset(assetName);
-
if (Obj != null)
-
{
-
DebugSystem.Log( "Async Load Asset Success:" + Obj.name);
-
SaveAssetToDic(bundle.bundleName, assetName, Obj);
-
}
-
}
-
}
-
/// <summary>
-
/// 同步從本地外部存儲加載單個Bundle文件
-
/// </summary>
-
/// <param name="BaseBundleInfo"></param>
-
/// <param name="assetName"></param>
-
/// <returns></returns>
-
private void SyncLoadFromLocalSingleBundle(string bundleName)
-
{
-
if (!JudegeOrExistBundle(bundleName))
-
{
-
string path = AssetBundlePath.Instance.ExternalStorePath + "/" + bundleName;
-
AssetBundle asset = AssetBundle.LoadFromFile(path);
-
SaveBundleToDic(bundleName, asset);
-
} else
-
{
-
DebugSystem.LogError( "Bundle 已存在:"+bundleName);
-
}
-
}
-
-
/// <summary>
-
/// 同步從本地外部存儲加載單個資源文件
-
/// </summary>
-
/// <param name="BaseBundleInfo"></param>
-
/// <param name="assetName"></param>
-
/// <returns></returns>
-
public UnityEngine.Object SyncLoadFromLocalSingleAsset(AssetInfo mAssetInfo)
-
{
-
if (!JudgeOrExistAsset(mAssetInfo.bundleName, mAssetInfo.assetName))
-
{
-
string path = AssetBundlePath.Instance.ExternalStorePath+"/"+mAssetInfo.bundleName;
-
AssetBundle asset = AssetBundle.LoadFromFile(path);
-
SaveBundleToDic(mAssetInfo.bundleName,asset);
-
}
-
return GetAssetFromDic(mAssetInfo.bundleName,mAssetInfo.assetName);
-
}
-
-
-
private void SaveBundleToDic(string bundleName, AssetBundle bundle)
-
{
-
if (bundle == null)
-
{
-
DebugSystem.LogError( "未保存的Bundle爲空:"+bundleName);
-
return;
-
}
-
if (!mBundleDic.ContainsKey(bundleName))
-
{
-
mBundleDic[bundleName] = bundle;
-
} else
-
{
-
DebugSystem.LogError( "Bundle資源 重複:"+bundleName);
-
}
-
}
-
-
private void SaveAssetToDic(string bundleName, string assetName, UnityEngine.Object asset)
-
{
-
if (asset == null)
-
{
-
DebugSystem.LogError( "未保存的資源爲空:"+assetName);
-
return;
-
}
-
if(asset is GameObject)
-
{
-
GameObject obj = asset as GameObject;
-
obj.SetActive( false);
-
}
-
if (!mAssetDic.ContainsKey(bundleName))
-
{
-
Dictionary< string, UnityEngine.Object> mDic = new Dictionary<string, UnityEngine.Object>();
-
mAssetDic.Add(bundleName, mDic);
-
}
-
mAssetDic[bundleName][assetName] = asset;
-
}
-
-
private bool JudgeOrBundelIsLoading(string bundleName)
-
{
-
if (mBundleLockList.Contains(bundleName))
-
{
-
return true;
-
} else
-
{
-
return false;
-
}
-
}
-
-
private bool JudegeOrExistBundle(string bundleName)
-
{
-
if (mBundleDic.ContainsKey(bundleName) && mBundleDic[bundleName] != null)
-
{
-
return true;
-
}
-
else
-
{
-
return false;
-
}
-
}
-
-
private bool JudgeOrExistAsset(string bundleName, string asstName)
-
{
-
if (JudegeOrExistBundle(bundleName))
-
{
-
if (!mAssetDic.ContainsKey(bundleName) || mAssetDic[bundleName] == null || !mAssetDic[bundleName].ContainsKey(asstName) || mAssetDic[bundleName][asstName] == null)
-
{
-
UnityEngine.Object mm = mBundleDic[bundleName].LoadAsset(asstName);
-
if (mm != null)
-
{
-
SaveAssetToDic(bundleName, asstName, mm);
-
return true;
-
}
-
else
-
{
-
return false;
-
}
-
}
-
else
-
{
-
return true;
-
}
-
}
-
else
-
{
-
return false;
-
}
-
}
-
-
private UnityEngine.Object GetAssetFromDic(string bundleName, string asstName)
-
{
-
if (JudgeOrExistAsset(bundleName, asstName))
-
{
-
UnityEngine.Object mAsset1 = mAssetDic[bundleName][asstName];
-
if (mAsset1 is GameObject)
-
{
-
GameObject obj = Instantiate(mAsset1) as GameObject;
-
return obj;
-
}
-
else
-
{
-
return mAsset1;
-
}
-
}
-
else
-
{
-
DebugSystem.LogError( "Asset is NUll:" + asstName);
-
}
-
return null;
-
}
-
#if UNITY_EDITOR
-
private Dictionary<string, UnityEngine.Object> mEditorAssetDic = new Dictionary<string, UnityEngine.Object>();
-
-
private UnityEngine.Object GetAssetFromEditorDic(string assetPath)
-
{
-
if (string.IsNullOrEmpty(assetPath))
-
{
-
DebugSystem.LogError( "Editor AssetPath is Empty");
-
return null;
-
}
-
UnityEngine.Object asset = null;
-
if (!mEditorAssetDic.TryGetValue(assetPath, out asset))
-
{
-
asset = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(assetPath);
-
if (asset != null)
-
{
-
if (asset is GameObject)
-
{
-
GameObject obj = asset as GameObject;
-
obj.SetActive( false);
-
}
-
mEditorAssetDic.Add(assetPath, asset);
-
}
-
else
-
{
-
DebugSystem.LogError( "找不到資源:" + assetPath);
-
}
-
}
-
if (asset is GameObject)
-
{
-
GameObject obj = Instantiate(asset) as GameObject;
-
return obj;
-
}
-
else
-
{
-
return asset;
-
}
-
}
-
#endif
-
public IEnumerator AsyncLoadBundle(string bundleName)
-
{
-
if (!JudegeOrExistBundle(bundleName))
-
{
-
string path = AssetBundlePath.Instance.ExternalStorePath + "/" + bundleName;
-
AssetBundle asset = AssetBundle.LoadFromFile(path);
-
SaveBundleToDic(bundleName, asset);
-
yield return null;
-
}
-
}
-
/// <summary>
-
/// 這個東西用來在頂層使用
-
/// </summary>
-
/// <param name="type"></param>
-
/// <param name="assetName"></param>
-
/// <returns></returns>
-
public UnityEngine.Object LoadAsset(AssetInfo mAssetInfo)
-
{
-
if (GameConfig.Instance.orUseAssetBundle)
-
{
-
return GetAssetFromDic(mAssetInfo.bundleName, mAssetInfo.assetName);
-
}
-
else
-
{
-
return GetAssetFromEditorDic(mAssetInfo.assetPath);
-
}
-
}
-
-
/// <summary>
-
/// 這個東西用來在專門的管理器中使用(底層封裝一下),禁止在頂層使用
-
/// </summary>
-
/// <param name="type"></param>
-
/// <param name="assetName"></param>
-
/// <returns></returns>
-
public IEnumerator AsyncLoadAsset(AssetInfo mAssetInfo)
-
{
-
if (GameConfig.Instance.orUseAssetBundle)
-
{
-
string bundleName = mAssetInfo.bundleName;
-
string asstName = mAssetInfo.assetPath;
-
if (!JudgeOrExistAsset(bundleName, asstName))
-
{
-
yield return AsyncLoadFromLocalSingleAsset(mResourcesABManager.GetBundleInfo(bundleName), asstName);
-
}
-
}
-
}
-
}
-
-
public class ResourcesABManager
-
{
-
public int VersionId = -1;
-
public List<AssetBundleInfo> mNeedLoadBundleList = new List<AssetBundleInfo>();
-
public AssetBundleInfo GetBundleInfo(string bundleName)
-
{
-
AssetBundleInfo mBundleInfo = mNeedLoadBundleList.Find((x) =>
-
{
-
return x.bundleName == bundleName;
-
});
-
return mBundleInfo;
-
}
-
-
public IEnumerator InitLoadMainifestFile()
-
{
-
if (mNeedLoadBundleList.Count == 0)
-
{
-
string path = AssetBundlePath.Instance.ExternalStorePathUrl;
-
string url = path + "/" + AssetBundlePath.AssetDependentFileBundleName;
-
WWW www = new WWW(url);
-
yield return www;
-
if (www.isDone)
-
{
-
if (!string.IsNullOrEmpty(www.error))
-
{
-
DebugSystem.LogError( "初始化 MainifestFile 失敗:" + www.error);
-
www.Dispose();
-
yield break;
-
}
-
}
-
AssetBundle asset = www.assetBundle;
-
www.Dispose();
-
if (asset == null)
-
{
-
DebugSystem.LogError( "MainifestFile Bundle is Null");
-
www.Dispose();
-
yield break;
-
}
-
-
AssetBundleManifest mAllBundleMainifest = asset.LoadAsset<AssetBundleManifest>(AssetBundlePath.AssetDependentFileAssetName);
-
if (mAllBundleMainifest == null)
-
{
-
DebugSystem.LogError( "Mainifest is Null");
-
www.Dispose();
-
yield break;
-
}
-
string[] mAssetNames = mAllBundleMainifest.GetAllAssetBundles();
-
if (mAssetNames != null)
-
{
-
foreach (var v in mAssetNames)
-
{
-
-
string bundleName = v;
-
string[] bundleDependentList = mAllBundleMainifest.GetAllDependencies(v);
-
Hash128 mHash = mAllBundleMainifest.GetAssetBundleHash(v);
-
AssetBundleInfo mABInfo = new AssetBundleInfo(bundleName, mHash, bundleDependentList);
-
mNeedLoadBundleList.Add(mABInfo);
-
}
-
}
-
else
-
{
-
DebugSystem.Log( "初始化資源依賴文件: Null");
-
}
-
asset.Unload( false);
-
DebugSystem.Log( "初始化資源管理器全局Bundle信息成功");
-
www.Dispose();
-
-
yield return InitLoadExternalStoreVersionConfig();
-
}
-
}
-
-
private IEnumerator InitLoadExternalStoreVersionConfig()
-
{
-
string url = AssetBundlePath.Instance.ExternalStorePathUrl + "/" + AssetBundlePath.versionConfigBundleName;
-
WWW www = new WWW(url);
-
yield return www;
-
if (www.isDone)
-
{
-
if (!string.IsNullOrEmpty(www.error))
-
{
-
DebugSystem.LogError( "www Load Error:" + www.error);
-
www.Dispose();
-
yield break;
-
}
-
}
-
AssetBundle mConfigBundle = www.assetBundle;
-
TextAsset mVersionConfig = mConfigBundle.LoadAsset<TextAsset>(AssetBundlePath.versionConfigAssetName);
-
VersionId = GetVersionIdByParseXML(mVersionConfig);
-
DebugSystem.Log( "當前版本號:"+VersionId);
-
mConfigBundle.Unload( false);
-
www.Dispose();
-
}
-
-
private int GetVersionIdByParseXML(TextAsset mTextAsset)
-
{
-
XmlDocument mdoc = new XmlDocument();
-
mdoc.LoadXml(mTextAsset.text);
-
foreach (XmlNode v in mdoc.ChildNodes)
-
{
-
if (v.Name == "root")
-
{
-
foreach (XmlNode x in v.ChildNodes)
-
{
-
if (x.Name.Contains("versionId"))
-
{
-
return int.Parse(x.InnerText);
-
}
-
}
-
}
-
}
-
return 0;
-
}
-
}
-
-
public class AssetBundleInfo
-
{
-
public string bundleName;
-
public Hash128 mHash;
-
public string[] mDependentBundleList;
-
-
public AssetBundleInfo(string bundleName, Hash128 mHash128, string[] mDependentBundleList)
-
{
-
this.bundleName = bundleName;
-
this.mHash = mHash128;
-
this.mDependentBundleList = mDependentBundleList;
-
}
-
-
}
-
-
public class AssetInfo
-
{
-
public string bundleName;
-
public string assetName;
-
public string assetPath;
-
-
public AssetInfo(string assetPath,string bundleName, string assetName)
-
{
-
this.assetPath = assetPath;
-
this.bundleName = bundleName;
-
this.assetName = assetName;
-
}
-
-
public AssetInfo(string bundleName, string assetName)
-
{
-
this.bundleName = bundleName;
-
this.assetName = assetName;
-
}
-
}
-
-
public class AssetBundlePath : Singleton<AssetBundlePath>
-
{
-
public const string versionConfigBundleName = "version.xk_unity3d";
-
public const string versionConfigAssetName = "version.xml";
-
public const string AssetDependentFileBundleName = "StreamingAssets";
-
public const string AssetDependentFileAssetName = "AssetBundleManifest";
-
public const string ABExtention = ".xk_unity3d";
-
-
public readonly string StreamingAssetPathUrl;
-
public readonly string ExternalStorePathUrl;
-
public readonly string WebServerPathUrl;
-
-
public readonly string ExternalStorePath;
-
public AssetBundlePath()
-
{
-
if (Application.platform == RuntimePlatform.WindowsEditor)
-
{
-
WebServerPathUrl = "file:///F:/WebServer";
-
StreamingAssetPathUrl = "file:///" + Application.streamingAssetsPath;
-
ExternalStorePathUrl = "file:///" + Application.persistentDataPath;
-
ExternalStorePath = Application.persistentDataPath;
-
} else if (Application.platform == RuntimePlatform.WindowsPlayer)
-
{
-
WebServerPathUrl = "file:///F:/WebServer";
-
StreamingAssetPathUrl = "file:///" + Application.streamingAssetsPath;
-
ExternalStorePathUrl = "file:///" + Application.persistentDataPath;
-
ExternalStorePath = Application.persistentDataPath;
-
} else if(Application.platform == RuntimePlatform.Android)
-
{
-
WebServerPathUrl = "file:///F:/WebServer";
-
StreamingAssetPathUrl = "jar:file://" + Application.dataPath + "!/assets";
-
ExternalStorePathUrl = "file://" + Application.persistentDataPath;
-
ExternalStorePath = Application.persistentDataPath;
-
}
-
DebugSystem.LogError( "www server path: " + WebServerPathUrl);
-
DebugSystem.LogError( "www local Stream Path: " + StreamingAssetPathUrl);
-
DebugSystem.LogError( "www local external Path: " + ExternalStorePathUrl);
-
}
-
}
-
-
}
注意:原本我是本身定義一個md5配置文件專門用來比對資源,後來發現,Unity已經幫咱們實現了這個功能。這個關鍵點就在於AssetBundleManifest類,具體請參考這篇文章末尾所講的資源依賴配置文件:http://liweizhaolili.blog.163.com/blog/static/16230744201541410275298/
下載Web服務器資源代碼以下:
-
using UnityEngine;
-
using System.Collections;
-
using xk_System.Debug;
-
using System.Collections.Generic;
-
using xk_System.AssetPackage;
-
using System.IO;
-
using System.Xml;
-
-
namespace xk_System.HotUpdate
-
{
-
public class AssetBundleHotUpdateManager : Singleton<AssetBundleHotUpdateManager>
-
{
-
private int mStreamFolderVersionId=-1;
-
private int mExternalStoreVersionId=-1;
-
private int mWebServerVersionId=-1;
-
-
private List<AssetBundleInfo> mExternalStoreABInfoList = new List<AssetBundleInfo>();
-
private List<AssetBundleInfo> mWebServerABInfoList = new List<AssetBundleInfo>();
-
private List<AssetBundleInfo> mStreamFolderABInfoList = new List<AssetBundleInfo>();
-
-
private DownLoadAssetInfo mDownLoadAssetInfo = new DownLoadAssetInfo();
-
-
public LoadProgressInfo mTask = new LoadProgressInfo();
-
-
public IEnumerator CheckUpdate()
-
{
-
mTask.progress = 0;
-
mTask.Des = "正在檢查資源";
-
yield return CheckVersionConfig();
-
if (mDownLoadAssetInfo.mAssetNameList.Count > 0)
-
{
-
mTask.progress += 10;
-
mTask.Des = "正在下載資源";
-
yield return DownLoadAllNeedUpdateBundle();
-
}
-
else
-
{
-
mTask.progress = 100;
-
}
-
}
-
-
/// <summary>
-
/// 檢查版本配置文件
-
/// </summary>
-
/// <returns></returns>
-
private IEnumerator CheckVersionConfig()
-
{
-
yield return InitLoadExternalStoreVersionConfig();
-
yield return InitLoadStreamFolderVersionConfig();
-
yield return InitLoadWebServerVersionConfig();
-
-
DebugSystem.Log( "本地版本號:" + mExternalStoreVersionId);
-
DebugSystem.Log( "WebServer版本號:" + mWebServerVersionId);
-
DebugSystem.Log( "StreamFolder版本號:" + mStreamFolderVersionId);
-
if (mWebServerVersionId > mExternalStoreVersionId)
-
{
-
yield return InitLoadExternalStoreABConfig();
-
if (mWebServerVersionId > mStreamFolderVersionId)
-
{
-
yield return InitLoadWebServerABConfig();
-
CheckAssetInfo(AssetBundlePath.Instance.WebServerPathUrl, mWebServerABInfoList);
-
}
-
else
-
{
-
yield return InitLoadStreamFolderABConfig();
-
CheckAssetInfo(AssetBundlePath.Instance.StreamingAssetPathUrl, mStreamFolderABInfoList);
-
}
-
}
-
else if (mStreamFolderVersionId > mExternalStoreVersionId)
-
{
-
yield return InitLoadExternalStoreABConfig();
-
yield return InitLoadStreamFolderABConfig();
-
CheckAssetInfo(AssetBundlePath.Instance.StreamingAssetPathUrl, mStreamFolderABInfoList);
-
}
-
}
-
-
/// <summary>
-
/// 檢查資源配置文件
-
/// </summary>
-
/// <returns></returns>
-
private void CheckAssetInfo(string url, List<AssetBundleInfo> mUpdateABInfoList)
-
{
-
mDownLoadAssetInfo.url = url;
-
foreach (AssetBundleInfo k in mUpdateABInfoList)
-
{
-
AssetBundleInfo mBundleInfo = mExternalStoreABInfoList.Find((x) =>
-
{
-
if (x.mHash.isValid && k.mHash.isValid)
-
{
-
return x.mHash.Equals(k.mHash);
-
}
-
else
-
{
-
DebugSystem.LogError( "Hash is no Valid");
-
return false;
-
}
-
});
-
if (mBundleInfo == null)
-
{
-
mDownLoadAssetInfo.mAssetNameList.Add(k.bundleName);
-
}
-
}
-
if (mDownLoadAssetInfo.mAssetNameList.Count > 0)
-
{
-
mDownLoadAssetInfo.mAssetNameList.Add(AssetBundlePath.AssetDependentFileBundleName);
-
}
-
DebugSystem.Log( "須要下載更新的個數:" + mDownLoadAssetInfo.mAssetNameList.Count);
-
}
-
-
private IEnumerator InitLoadWebServerVersionConfig()
-
{
-
string url = AssetBundlePath.Instance.WebServerPathUrl + "/" + AssetBundlePath.versionConfigBundleName;
-
WWW www = new WWW(url);
-
yield return www;
-
if (www.isDone)
-
{
-
if (!string.IsNullOrEmpty(www.error))
-
{
-
DebugSystem.LogError( "www Load Error:" + www.error);
-
www.Dispose();
-
yield break;
-
}
-
}
-
-
AssetBundle mConfigBundle = www.assetBundle;
-
TextAsset mVersionConfig = mConfigBundle.LoadAsset<TextAsset>(AssetBundlePath.versionConfigAssetName);
-
mWebServerVersionId = ParseXML(mVersionConfig);
-
mConfigBundle.Unload( false);
-
www.Dispose();
-
}
-
-
private IEnumerator InitLoadExternalStoreVersionConfig()
-
{
-
string url = AssetBundlePath.Instance.ExternalStorePathUrl + "/" + AssetBundlePath.versionConfigBundleName;
-
WWW www = new WWW(url);
-
yield return www;
-
if (www.isDone)
-
{
-
if (!string.IsNullOrEmpty(www.error))
-
{
-
DebugSystem.LogError( "www Load Error:" + www.error);
-
www.Dispose();
-
yield break;
-
}
-
}
-
AssetBundle mConfigBundle = www.assetBundle;
-
TextAsset mVersionConfig = mConfigBundle.LoadAsset<TextAsset>(AssetBundlePath.versionConfigAssetName);
-
mExternalStoreVersionId = ParseXML(mVersionConfig);
-
mConfigBundle.Unload( false);
-
www.Dispose();
-
}
-
-
private IEnumerator InitLoadStreamFolderVersionConfig()
-
{
-
string url = AssetBundlePath.Instance.StreamingAssetPathUrl + "/" + AssetBundlePath.versionConfigBundleName;
-
WWW www = new WWW(url);
-
yield return www;
-
if (www.isDone)
-
{
-
if (!string.IsNullOrEmpty(www.error))
-
{
-
DebugSystem.LogError( "www Load Error:" + www.error);
-
www.Dispose();
-
yield break;
-
}
-
}
-
AssetBundle mConfigBundle = www.assetBundle;
-
TextAsset mVersionConfig = mConfigBundle.LoadAsset<TextAsset>(AssetBundlePath.versionConfigAssetName);
-
mStreamFolderVersionId = ParseXML(mVersionConfig);
-
mConfigBundle.Unload( false);
-
www.Dispose();
-
}
-
-
private IEnumerator InitLoadWebServerABConfig()
-
{
-
string url = AssetBundlePath.Instance.WebServerPathUrl + "/" + AssetBundlePath.AssetDependentFileBundleName;
-
WWW www = new WWW(url);
-
yield return www;
-
if (www.isDone)
-
{
-
if (!string.IsNullOrEmpty(www.error))
-
{
-
DebugSystem.LogError( "www Load Error:" + www.error);
-
www.Dispose();
-
yield break;
-
}
-
}
-
AssetBundle mConfigBundle = www.assetBundle;
-
AssetBundleManifest mAllBundleMainifest = mConfigBundle.LoadAsset<AssetBundleManifest>( "AssetBundleManifest");
-
if (mAllBundleMainifest == null)
-
{
-
DebugSystem.LogError( "Mainifest is Null");
-
www.Dispose();
-
yield break;
-
}
-
string[] mAssetNames = mAllBundleMainifest.GetAllAssetBundles();
-
if (mAssetNames != null)
-
{
-
foreach (var v in mAssetNames)
-
{
-
string bundleName = v;
-
string[] bundleDependentList = mAllBundleMainifest.GetAllDependencies(v);
-
Hash128 mHash = mAllBundleMainifest.GetAssetBundleHash(v);
-
AssetBundleInfo mABInfo = new AssetBundleInfo(bundleName, mHash, bundleDependentList);
-
mWebServerABInfoList.Add(mABInfo);
-
}
-
}
-
else
-
{
-
DebugSystem.Log( "初始化資源依賴文件: Null");
-
}
-
mConfigBundle.Unload( false);
-
www.Dispose();
-
}
-
-
private IEnumerator InitLoadExternalStoreABConfig()
-
{
-
string url = AssetBundlePath.Instance.ExternalStorePathUrl + "/" + AssetBundlePath.AssetDependentFileBundleName;
-
WWW www = new WWW(url);
-
yield return www;
-
if (www.isDone)
-
{
-
if (!string.IsNullOrEmpty(www.error))
-
{
-
DebugSystem.LogError( "www Load Error:" + www.error);
-
www.Dispose();
-
yield break;
-
}
-
}
-
AssetBundle mConfigBundle = www.assetBundle;
-
AssetBundleManifest mAllBundleMainifest = mConfigBundle.LoadAsset<AssetBundleManifest>( "AssetBundleManifest");
-
if (mAllBundleMainifest == null)
-
{
-
DebugSystem.LogError( "Mainifest is Null");
-
www.Dispose();
-
yield break;
-
}
-
string[] mAssetNames = mAllBundleMainifest.GetAllAssetBundles();
-
if (mAssetNames != null)
-
{
-
foreach (var v in mAssetNames)
-
{
-
string bundleName = v;
-
string[] bundleDependentList = mAllBundleMainifest.GetAllDependencies(v);
-
Hash128 mHash = mAllBundleMainifest.GetAssetBundleHash(v);
-
AssetBundleInfo mABInfo = new AssetBundleInfo(bundleName, mHash, bundleDependentList);
-
mExternalStoreABInfoList.Add(mABInfo);
-
}
-
}
-
else
-
{
-
DebugSystem.Log( "初始化資源依賴文件: Null");
-
}
-
mConfigBundle.Unload( false);
-
www.Dispose();
-
}
-
-
private IEnumerator InitLoadStreamFolderABConfig()
-
{
-
string url = AssetBundlePath.Instance.StreamingAssetPathUrl + "/" + AssetBundlePath.AssetDependentFileBundleName;
-
WWW www = new WWW(url);
-
yield return www;
-
if (www.isDone)
-
{
-
if (!string.IsNullOrEmpty(www.error))
-
{
-
DebugSystem.LogError( "www Load Error:" + www.error);
-
www.Dispose();
-
yield break;
-
}
-
}
-
AssetBundle mConfigBundle = www.assetBundle;
-
AssetBundleManifest mAllBundleMainifest = mConfigBundle.LoadAsset<AssetBundleManifest>( "AssetBundleManifest");
-
if (mAllBundleMainifest == null)
-
{
-
DebugSystem.LogError( "Mainifest is Null");
-
www.Dispose();
-
yield break;
-
}
-
string[] mAssetNames = mAllBundleMainifest.GetAllAssetBundles();
-
if (mAssetNames != null)
-
{
-
foreach (var v in mAssetNames)
-
{
-
string bundleName = v;
-
string[] bundleDependentList = mAllBundleMainifest.GetAllDependencies(v);
-
Hash128 mHash = mAllBundleMainifest.GetAssetBundleHash(v);
-
AssetBundleInfo mABInfo = new AssetBundleInfo(bundleName, mHash, bundleDependentList);
-
mStreamFolderABInfoList.Add(mABInfo);
-
}
-
}
-
else
-
{
-
DebugSystem.Log( "初始化資源依賴文件: Null");
-
}
-
mConfigBundle.Unload( false);
-
www.Dispose();
-
}
-
-
/// <summary>
-
/// 獲得版本號
-
/// </summary>
-
/// <param name="mbytes"></param>
-
/// <returns></returns>
-
public int ParseXML(TextAsset mTextAsset)
-
{
-
XmlDocument mdoc = new XmlDocument();
-
mdoc.LoadXml(mTextAsset.text);
-
foreach (XmlNode v in mdoc.ChildNodes)
-
{
-
if (v.Name == "root")
-
{
-
foreach (XmlNode x in v.ChildNodes)
-
{
-
if (x.Name.Contains("versionId"))
-
{
-
return int.Parse(x.InnerText);
-
}
-
}
-
}
-
}
-
return 0;
-
}
-
-
private IEnumerator DownLoadAllNeedUpdateBundle()
-
{
-
List< string> bundleList = mDownLoadAssetInfo.mAssetNameList;
-
List< string>.Enumerator mIter = bundleList.GetEnumerator();
-
-
uint addPro = (uint)Mathf.CeilToInt((LoadProgressInfo.MaxProgress - mTask.progress)/(float)bundleList.Count);
-
while (mIter.MoveNext())
-
{
-
DebugSystem.LogError( "下載的文件:" + mDownLoadAssetInfo.url + " | " + mIter.Current);
-
yield return DownLoadSingleBundle(mDownLoadAssetInfo.url, mIter.Current);
-
mTask.progress+=addPro;
-
}
-
}
-
-
private IEnumerator DownLoadSingleBundle(string path, string bundleName)
-
{
-
string url = path + "/" + bundleName;
-
WWW www = new WWW(url);
-
yield return www;
-
if (www.isDone)
-
{
-
if (!string.IsNullOrEmpty(www.error))
-
{
-
DebugSystem.LogError( "www Load Error:" + www.error);
-
www.Dispose();
-
yield break;
-
}
-
}
-
string savePath = AssetBundlePath.Instance.ExternalStorePath + "/" + bundleName;
-
SaveDownLoadedFile(savePath, www.bytes);
-
www.Dispose();
-
}
-
-
private void SaveDownLoadedFile(string path, byte[] mdata)
-
{
-
if (File.Exists(path))
-
{
-
File.Delete(path);
-
}
-
FileInfo mFileInfo = new FileInfo(path);
-
FileStream mFileStream = mFileInfo.OpenWrite();
-
mFileStream.Write(mdata, 0, mdata.Length);
-
mFileStream.Flush();
-
mFileStream.Close();
-
}
-
-
private class DownLoadAssetInfo
-
{
-
public string url;
-
public List<string> mAssetNameList = new List<string>();
-
}
-
-
-
}
-
}
如今 資源管理架構設計就完了。
二: C#反射熱更新(網上熱更新的傳說,多數資料都是簡單一筆帶過)
1:如何編譯Unity代碼,生成程序集:
Unity工程自己編譯的程序集會放在Project\Library\ScriptAssemblies文件夾下,因此剛開始我是直接拿這個去加載程序集的,後來發現不行。
由於加載的程序集,與本地程序集重名,Unity會認爲加載的程序集,仍是本地程序集。(測過結果就是這樣)
因此後來,經過VS2015編譯Unity工程,但遇到一個問題:build的時候報了一大堆錯誤,錯誤的緣由在於,Proto 生成的cs文件 所用的.net版本太高致使的。
你能夠從新新build Protobuf 源碼,而後生成.net低版本的程序集,這樣作是能夠的。
2:加載程序集,代碼以下
-
using UnityEngine;
-
using System.Collections;
-
using System.Reflection;
-
using xk_System.Debug;
-
using System;
-
-
namespace xk_System.AssetPackage
-
{
-
public class AssemblyManager : Singleton<AssemblyManager>
-
{
-
private Assembly mHotUpdateAssembly;
-
private Assembly mCurrentAssembly;
-
/// <summary>
-
/// 加載程序集
-
/// </summary>
-
/// <returns></returns>
-
public IEnumerator LoadAssembly()
-
{
-
AssetInfo mAssetInfo = ResourceABsFolder.Instance.scripts.mtest;
-
string path = AssetBundlePath.Instance.ExternalStorePathUrl;
-
-
string bundleName1 = mAssetInfo.bundleName;
-
string url = path + "/" + bundleName1;
-
WWW www = new WWW(url);
-
yield return www;
-
if (www.isDone)
-
{
-
if (!string.IsNullOrEmpty(www.error))
-
{
-
DebugSystem.LogError( "www Load Error:" + www.error);
-
yield break;
-
}
-
}
-
AssetBundle mConfigBundle = www.assetBundle;
-
TextAsset mAsset = mConfigBundle.LoadAsset<TextAsset>(mAssetInfo.assetName);
-
mHotUpdateAssembly = Assembly.Load(mAsset.bytes);
-
if (mHotUpdateAssembly != null)
-
{
-
DebugSystem.Log( "加載程序集:" + mHotUpdateAssembly.FullName);
-
}
-
else
-
{
-
DebugSystem.Log( "加載程序集: null");
-
}
-
mCurrentAssembly = this.GetType().Assembly;
-
DebugSystem.Log( "當前程序集:" + mCurrentAssembly.FullName);
-
if (mCurrentAssembly.FullName.Equals(mHotUpdateAssembly.FullName))
-
{
-
DebugSystem.LogError( "加載程序集名字有誤");
-
}
-
mConfigBundle.Unload( false);
-
}
-
-
public object CreateInstance(string typeFullName)
-
{
-
if (mHotUpdateAssembly != null)
-
{
-
return mHotUpdateAssembly.CreateInstance(typeFullName);
-
}
-
else
-
{
-
return mCurrentAssembly.CreateInstance(typeFullName);
-
}
-
}
-
-
/// <summary>
-
/// 僅僅寫入口時,調用。(不然,會使程序變得混亂,反正我是搞亂了)
-
/// </summary>
-
/// <param name="obj"></param>
-
/// <param name="typeFullName"></param>
-
/// <returns></returns>
-
public Component AddComponent(GameObject obj, string typeFullName)
-
{
-
DebugSystem.Log( "Type: " + typeFullName);
-
if (mHotUpdateAssembly != null)
-
{
-
Type mType = mHotUpdateAssembly.GetType(typeFullName);
-
return obj.AddComponent(mType);
-
}
-
else
-
{
-
Type mType = typeFullName.GetType();
-
return obj.AddComponent(mType);
-
-
}
-
}
-
}
-
}
剛開始想這個問題的時候感受無非反射了這麼簡單的問題,後來越想感受越複雜,幸虧,崩潰完了以後,發現其實,你只要遵照2點便可實現遊戲代碼所有更新。(1):咱們前面已經作完了,加載資源和加載程序集的工做,那麼咱們如今要作的工做,就是實現這個新加載的程序集的入口。切記,這個入口要經過動態添加組件的方式出現。如:
Type mType = mHotUpdateAssembly.GetType(typeFullName);obj.AddComponent(mType);
(2):要注意全部的預製件上要動態添加腳本,不然,預製件會去尋找【本地程序集】的腳本添加上去,而且還會致使【本地程序集】與【熱更新程序集】相互訪問的問題。
在這裏要注意一點:由於咱們已經提供了【熱更新程序集】的入口,因此,接下來程序動態添加腳本就會使用【熱更新程序集】裏腳本。千萬不要再去反射程序集裏某某個腳本了,加載腳本,還和之前同樣寫就行了。如:
(2):要注意全部的預製件上要動態添加腳本,不然,預製件會去尋找【本地程序集】的腳本添加上去,而且還會致使【本地程序集】與【熱更新程序集】相互訪問的問題。
在這裏要注意一點:由於咱們已經提供了【熱更新程序集】的入口,因此,接下來程序動態添加腳本就會使用【熱更新程序集】裏腳本。千萬不要再去反射程序集裏某某個腳本了,加載腳本,還和之前同樣寫就行了。如:
obj.AddComponent<T>(); 這裏與入口動態添加的方式可不同啊。(沒有反射的)。