unity3D熱更新——(1)Assetbundle資源打包部分


/*
* <資源打包介紹>
* 首先會根據已經建好的文件進行遍歷,找到所有預製物並設置AssetBundleName,因爲是遍歷Resources下面的文件夾,
* 所以可以將每個文件夾裏的所有預製物打成一個包,然後打包到StreamingAssets 下面,並會生成一個配置文件,這個
* 配置文件是以Resources下的文件夾命名的,一個文件夾一個配置文件,方便後面的更新資源,這個配置文件是根據打包
* 好的包文件生成的,每行都記錄了單個包的路徑+;+.manifest文件裏的crc碼,當每次打包預製物有改變時,crc碼會重新
* 生成,更新資源時會通過配置文件裏每個包路徑後面的crc碼來判斷這個包是否需要更新。
*
*
* 所有需要打包的預製物需要放入文件夾 AssetBundleResources/Resources 下進行打包.
* 打包出來的文件會在 Assets/StreamingAssets(沒有該文件夾會自動創建) 文件夾下生成.
*
* 路徑供閱讀下面代碼參考
* 完整的需要打包路徑:Assets\AssetBundleResources\Resources\Prefad\UI\XXX.prefab
* 完整的打包好的路徑(安卓):Assets\StreamingAssets\Android\resources\prefad\ui\XXX.unity3d
* 完整的配置文件路徑:Assets\StreamingAssets\Android\configuration\prefad\ui.txt
*
*
* 因爲unity5.X不需要我們來管理引用, 所以下面的代碼大部分都是對路徑和文件夾的處理,打包的代碼也就兩行
* 1:設置AssetBundleName
*:2:根據平臺設置進行打包
*
* 該段代碼打包流程
* 清除已設置的AssetBundleName -→ 找到要打包的資源並設置 AssetBundleName -→ 進行打包 -→ 創建文本並寫入配置信息
*
* 調用該函數,unity會自動根據資源的標籤進行打包,而且是增量打包,
* a.對於資源沒有變更的bundle包,不會觸發重新打包;
* b.資源沒變,即使生成目錄下的bundle包被刪除了,unity也不會重新打包;
* c.生成目錄下的bundle包對應的manifase被刪了,會重新打包;
* d.可以使用BuildAssetBundleOptions.ForceRebuildAssetBundle參數觸發強制重新打包。
*
*
*/
public class Builder : Editor
{

[MenuItem("打包/熱更新打包")]
public static void BuildAssetBundleAll()
{
#if UNITY_ANDROID && UNITY_EDITOR
BuildResource(BuildTarget.Android);
#endif
#if UNITY_IOS && UNITY_EDITOR
BuildResource(BuildTarget.iOS);
#endif
}
/// <summary>
/// 資源打包
/// </summary>
/// <param name="target">打包平臺</param>
static void BuildResource(BuildTarget target)
{
//清除所有之前設置過的AssetBundleName
ClearAssetBundlesName();
//代碼中給資源設置AssetBundleName
SetAssetBundelsName(AssetPath.OriginalPath);
//因爲要根據平臺打包,爲了方便分類,所以在Assets\StreamingAssets目錄下創建一個
//以平臺名字命名的文件夾來放置各平臺打出來的包和其他相關的文件,以方便管理
//例如安卓平臺: 處理路徑爲Assets\StreamingAssets\Android
string outputPath = Path.Combine(AssetPath.StreamingAssetsPath, target.ToString());
//查找Assets\StreamingAssets路徑下有沒有當前平臺名字的文件夾,沒有的話就創建
if (!Directory.Exists(outputPath))
{
Directory.CreateDirectory(outputPath);
}
//刷新
AssetDatabase.Refresh();
//根據平臺設置進行打包
BuildPipeline.BuildAssetBundles(outputPath, 0, target);
AssetDatabase.Refresh();
//生成配置文檔(配置文檔以遊戲文件夾進行分類,一個遊戲文件夾一個配置文檔,方便管理)
ConfigurationFiles(target);
//刷新
AssetDatabase.Refresh();
Debug.Log("打包成功!");
}
/// <summary>
/// 清除之前設置過的AssetBundleName
/// 因爲只要設置過AssetBundleName就會打包,所以這裏一定要清理乾淨,防止重複打包
/// </summary>
static void ClearAssetBundlesName()
{
string[] strArr = AssetDatabase.GetAllAssetBundleNames();
for (int i = 0; i < strArr.Length; i++)
{
AssetDatabase.RemoveAssetBundleName(strArr[i], true);
}
AssetDatabase.RemoveUnusedAssetBundleNames();
}
/// <summary>
/// 在代碼中給資源設置AssetBundleName
/// </summary>
static void SetAssetBundelsName(string folderName)
{
//首先遍歷需要打包的文件夾,找到所有需要打包的文件
//AssetBundleResources/Resources/Prefad/UI 因爲我的要打包的文件
//都是放在Prefad下的文件夾裏面也就是UI文件裏所以我需要遍歷到UI文件夾裏面
DirectoryInfo folder = new DirectoryInfo(folderName);
FileSystemInfo[] files = folder.GetFileSystemInfos();
for (int i = 0; i < files.Length; i++)
{
if (files[i] is DirectoryInfo)
{
SetAssetBundelsName(files[i].FullName);
}
else
{
//過濾.meta文件,並給遍歷到的資源設置AssetBundleName,以路徑的形式命名
//這裏是一個資源一個包,也可以把多個資源打一個包中
//最好是對資源進行分類,將一些有共有資源的預製物打進一個包中
if (!files[i].Name.EndsWith(AssetPath.metaSuffix))
{
//處理前的路徑C:\Users\Administrator\Desktop\DynamicLoadResource\Assets\AssetBundleResources\Resources\Prefad\UI\XXX.prefab
//處理後的路徑Resources/Prefad/UI/XXX.unity3d
//這個處理後的路徑會拿來設置AssetBundleName
string str1 = files[i].FullName.Replace(@"\", "/");
string path = "Assets" + str1.Substring(Application.dataPath.Length);
AssetImporter ass = AssetImporter.GetAtPath(path);
string str2 = str1.Substring(Application.dataPath.Length + 1);
str2 = str2.Substring(str2.IndexOf("/") + 1);
string assetName = str2.Replace(Path.GetExtension(str2), ".unity3d");
//這裏設置AssetBundleName,AssetBundleName相同的文件會打到一個包中
ass.assetBundleName = assetName;
}
}
}
}
/// <summary>
/// 生成配置文件
/// </summary>
static void ConfigurationFiles(BuildTarget target)
{
//所有配置文件的配置文件
List<string> MapConfig = new List<string>();
//查找Assets\StreamingAssets\Android 下是否有 configuration(該文件用於放置生成的配置文件)文件夾
//有的話就刪掉該文件夾(把文件夾下已存在的配置文件一起刪除),然後重新創建該文件夾
string str = AssetPath.StreamingAssetsPath + "/" + target.ToString() + "/" + AssetPath.ConfigurationFilesName;
if (Directory.Exists(str))
{
Directory.Delete(str, true);
}
Directory.CreateDirectory(str);
//處理包路徑
string resourcesStr = AssetPath.OriginalPath.Substring(AssetPath.OriginalPath.LastIndexOf("/") + 1);
string packetPath = Application.dataPath + "/" + AssetPath.StreamingAssets + "/" + target.ToString() + "/" + resourcesStr.ToLower();
//遍歷 Assets\StreamingAssets\Android\resources 下的文件夾
//因爲打出來的包並沒有直接放在resources下,都是放在該文件夾裏面的各個文件夾下
//所以需要再遍歷resources下的各個文件夾
DirectoryInfo folder = new DirectoryInfo(packetPath);
FileSystemInfo[] files = folder.GetFileSystemInfos();
for (int i = 0; i < files.Length; i++)
{
if (files[i] is DirectoryInfo)
{
string config = str + "/" + files[i].Name;
if (Directory.Exists(config))
{
Directory.Delete(config, true);
}
Directory.CreateDirectory(config);
DirectoryInfo folder1 = new DirectoryInfo(files[i].FullName);
FileSystemInfo[] files1 = folder1.GetFileSystemInfos();
for (int n = 0; n < files1.Length; n++)
{
if (files1[n] is DirectoryInfo)
{
//配表文件路徑
string configurationPath = config + "/" + files1[n].Name.Replace(AssetPath.metaSuffix, "") + ".txt";
//添加配表相對路徑到總配表中
MapConfig.Add(configurationPath.Remove(0, AssetPath.StreamingAssetsPath.Length + 1));
SetCon(files1[n].FullName.Replace(AssetPath.metaSuffix, ""), configurationPath);
}
}
}
}
//最後生成所有配置文件的配置文件
string MapConfigPath = AssetPath.StreamingAssetsPath + "/" + target.ToString() + "/" + IP.ResoucelsTablePath;
string mapConfigStr = "";
for (int i = 0; i < MapConfig.Count; i++)
{
mapConfigStr += MapConfig[i];
mapConfigStr += System.Environment.NewLine;
}
File.WriteAllText(MapConfigPath, mapConfigStr);
}
/// <summary>
/// 向配置文件中寫入ab包路徑與標識
/// </summary>
/// <param name="path"></param>
/// <param name="textPath"></param>
static void SetCon(string path, string textPath)
{
string content = "";
string[] assetPath = Directory.GetFiles(path, "*.manifest", SearchOption.AllDirectories);
for (int i = 0; i < assetPath.Length; i++)
{
content += assetPath[i].Replace(Application.dataPath.Replace("/", "\\") + "\\", "").Replace(".manifest", "").Replace(AssetPath.StreamingAssets + "\\", "");
content += ";";
content += File.ReadAllLines(assetPath[i])[1].Replace("CRC:", "").Trim();
content += System.Environment.NewLine;
}
File.WriteAllText(textPath, content.Replace('\\','/'));
}


}


public class AssetPath
{
/// <summary>
/// 需要打包的文件夾路徑
/// </summary>
public static string OriginalPath = Application.dataPath + "/AssetBundleResources/Resources";
/// <summary>
/// 打包出來的文件夾路徑
/// </summary>
public const string StreamingAssetsPath = @"Assets/StreamingAssets";
/// <summary>
/// 配置文件夾
/// </summary>
public const string ConfigurationFilesName = "configuration";
/// <summary>
/// 資源文件夾
/// </summary>
public const string ResourcesFilesName = "resources";
/// <summary>
/// 資源文件後綴名
/// </summary>
public const string unity3dSuffix = ".unity3d";
/// <summary>
/// .meta後綴名
/// </summary>
public const string metaSuffix = ".meta";
/// <summary>
/// 打包目錄
/// </summary>
public const string StreamingAssets = "StreamingAssets";
/// <summary>
/// Android
/// </summary>
public const string _Android = "Android";
/// <summary>
/// IPhonePlayer
/// </summary>
public const string _IPhonePlayer = "IPhonePlayer";
/// <summary>
/// 移動端本地壓縮包路徑
/// </summary>
public static string streamingPath = Application.streamingAssetsPath + "/" + Application.platform;
/// <summary>
/// 移動端資產放置路徑
/// </summary>
public static string persistentPath = Application.persistentDataPath + "/" + Application.platform;
/// <summary>
/// 預留物配表相對路徑
/// </summary>
public const string scheduledFileName = "/"+ConfigurationFilesName+"/prefad/scheduled.txt";
/// <summary>
/// "jar:file"
/// </summary>
public const string jarHead = "jar:file";
/// <summary>
/// "http"
/// </summary>
public const string httpHead = "http";

/// <summary>
/// 配置物
/// </summary>
public const string source = "source";

}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章