AssetBundle打包写入MD5待更新文件
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Text;
using System.Collections.Generic;
using LitJson;
public class EditorCreateBundle : Editor
{
public static string m_BundleDirectory = Application.dataPath + "/AssetBundle/";
[MenuItem("Tools/Bundle/IOS打Bundle")]
static void BuildReleaseIOSBundle()
{
BuildBundleTest(BuildTarget.iOS);
}
[MenuItem("Tools/Bundle/Android打Bundle")]
static void BuildReleaseAndroidBundle()
{
BuildBundleTest(BuildTarget.Android);
}
[MenuItem("Tools/Bundle/Windows64打Bundle")]
static void BuildReleaseWindowsBundle()
{
BuildBundleTest(BuildTarget.StandaloneWindows64);
}
static void BuildBundleTest(BuildTarget target)
{
Caching.ClearCache();
string[] filePaths = Directory.GetDirectories(m_BundleDirectory, "*.*", SearchOption.TopDirectoryOnly);
string path = GetTempPath(target);
DeleteTempBundles(target);
SetAssetBundleName(filePaths);
BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.ChunkBasedCompression, target);
CreateBundleVersionNumber(path, target);
AssetDatabase.Refresh();
}
private static Dictionary<string, string> m_BundleMD5Map = new Dictionary<string, string>();
/// <summary>
/// 删除目标文件夹下的所有文件
/// </summary>
/// <param name="target"></param>
static void DeleteTempBundles(BuildTarget target)
{
string[] bundleFiles = GetAllFilesFromBundleDirectory(target);
foreach (string s in bundleFiles)
{
File.Delete(s);
}
}
static string[] GetAllFilesFromBundleDirectory(BuildTarget target)
{
string path = GetTempPath(target);
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
string[] bundleFiles = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
return bundleFiles;
}
static void SetAssetBundleName(string[] topDirectories)
{
foreach (string path in topDirectories)
{
string[] childPaths = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
string childPathName, extension, directoryName;
foreach (string childPath in childPaths)
{
extension = Path.GetExtension(childPath);
if (extension != ".meta" && extension != ".DS_Store")
{
childPathName = Path.GetFileNameWithoutExtension(childPath);
directoryName = Path.GetDirectoryName(childPath).Replace("\\", "/");
AssetImporter temp = AssetImporter.GetAtPath(childPath.Replace(Application.dataPath, "Assets"));
temp.assetBundleName = null;
if (directoryName.ToLower().IndexOf("sprite") >= 0)
{
AssetImporter ai = AssetImporter.GetAtPath(directoryName.Replace(Application.dataPath, "Assets"));
ai.assetBundleName = directoryName.Replace(m_BundleDirectory, "");
}
else
temp.assetBundleName = directoryName.Replace(m_BundleDirectory, "") + "/" + childPathName;
}
}
}
}
/// <summary>获取文件的md5校验码</summary>
static string GetMD5HashFromFile(string fileName)
{
if (File.Exists(fileName))
{
FileStream file = new FileStream(fileName, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(file);
file.Close();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
sb.Append(retVal[i].ToString("x2"));
return sb.ToString();
}
return null;
}
static void CreateBundleVersionNumber(string bundlePath, BuildTarget target)
{
JsonData serverJson = new JsonData();
string[] contents = Directory.GetFiles(bundlePath, "*.*", SearchOption.AllDirectories);
string extension;
string fileName = "";
string fileMD5 = "";
long allLength = 0;
int fileLen;
m_BundleMD5Map.Clear();
for (int i = 0; i < contents.Length; i++)
{
fileName = contents[i].Replace(GetTempPath(target), "").Replace("\\", "/");
extension = Path.GetExtension(contents[i]);
if (extension != ".meta")
{
fileMD5 = GetMD5HashFromFile(contents[i]);
fileLen = File.ReadAllBytes(contents[i]).Length;
allLength += fileLen;
m_BundleMD5Map.Add(fileName, fileMD5 + "+" + fileLen);
}
}
JsonData files = new JsonData();
foreach (KeyValuePair<string, string> kv in m_BundleMD5Map)
{
JsonData jd = new JsonData();
jd["file"] = kv.Key;
string[] nAndL = kv.Value.Split('+');
jd["md5"] = nAndL[0];
jd["fileLength"] = nAndL[1];
files.Add(jd);
}
serverJson["length"] = allLength;
serverJson["files"] = files;
File.WriteAllText(GetTempPath(target) + "Bundle.txt", serverJson.ToJson());
m_BundleMD5Map.Clear();
//MiscUtils.CopyDirectory(Application.streamingAssetsPath + "/AssetBundle", Application.dataPath.Replace("Assets", ""), "*.*", true);
//Directory.Delete(Application.streamingAssetsPath + "/AssetBundle", true);
}
static string GetTempPath(BuildTarget target)
{
return Application.streamingAssetsPath + "/";
}
}
服务端比对版本更新
/// <summary>
/// 版本更新
/// </summary>
/// <returns></returns>
IEnumerator VersionUpdate()
{
WWW www = new WWW(ConstantUtils.HttpDownLoadUrl + "Bundle.txt");
yield return www;
if (www.isDone && string.IsNullOrEmpty(www.error))
{
List<BundleInfo> bims = new List<BundleInfo>();
JsonData data = JsonMapper.ToObject(www.text);
string md5, file, path;
int lenth;
for (int i = 0; i < data["files"].Count; i++)
{
JsonData jd = data["files"][i];
file = jd.TryGetstring("file");
path = ConstantUtils.PathUrl(file);
md5 = GetMD5HashFromFile(path);
if (string.IsNullOrEmpty(md5) || md5 != jd.TryGetstring("md5"))
{
bims.Add(new BundleInfo()
{
Url = ConstantUtils.HttpDownLoadUrl +file,
Path = path
});
lenth = int.Parse(jd.TryGetstring("fileLength"));
allfilesLength += lenth;
}
}
if (bims.Count > 0)
{
GameObject.Find("Canvas").transform.Find("LoadPage").gameObject.SetActive(true);
StartCoroutine(DownLoadBundleFiles(bims, (progress) => {
OpenLodingShow("自动更新中...", progress, allfilesLength);
}, (isfinish) => {
if (isfinish)
StartCoroutine(VersionUpdateFinish());
else
{
LoadingPage.Instance.GetMyEvent.Invoke("部分文件更新失败,正在准备重试...");
StartCoroutine(VersionUpdate());
}
}));
}
else
{
//Debug.Log(ConstantUtils.DataPath("common/luascript/XLuaScript.lua.txt", _pathinfo.streamingAssetsPath));
StartCoroutine(VersionUpdateFinish());
}
}
}
/// <summary>获取文件的md5校验码</summary>
public static string GetMD5HashFromFile(string fileName)
{
if (File.Exists(fileName))
{
FileStream file = new FileStream(fileName, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(file);
file.Close();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
sb.Append(retVal[i].ToString("x2"));
return sb.ToString();
}
return null;
}
public LuaEnv LuaEnvt { get; private set; }
Action StartLua;
Action UpdateLua;
Action DestoryLua;
IEnumerator VersionUpdateFinish()
{
// LoadingNode.instance.Close();
GameObject.Find("Canvas").transform.Find("LoadPage").gameObject.SetActive(false);
//登录验证...执行lua文件
LuaEnvt = new LuaEnv();
TextAsset texts = Singleton<UIManager>.singleton.GetBundleFile<TextAsset>("Lua/FirstLua.lua", "FirstLua.lua");
LuaEnvt.DoString(texts.text);
StartLua = LuaEnvt.Global.Get<Action>("start");
UpdateLua = LuaEnvt.Global.Get<Action>("update");
DestoryLua = LuaEnvt.Global.Get<Action>("ondestroy");
yield return new WaitForEndOfFrame();
if (StartLua != null)
StartLua();
}
/// <summary>
/// 路径比对
/// </summary>
/// <param name="infos"></param>
/// <param name="LoopCallBack"></param>
/// <param name="CallBack"></param>
/// <returns></returns>
public IEnumerator DownLoadBundleFiles(List<BundleInfo> infos, Action<float> LoopCallBack = null, Action<bool> CallBack = null)
{
int num = 0;
string dir;
for (int i = 0; i < infos.Count; i++)
{
BundleInfo info = infos[i];
WWW www = new WWW(info.Url);
yield return www;
if (www.isDone && string.IsNullOrEmpty(www.error))
{
try
{
string filepath = info.Path;
dir = Path.GetDirectoryName(filepath);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
File.WriteAllBytes(filepath, www.bytes);
num++;
if (LoopCallBack != null)
LoopCallBack.Invoke((float)num / infos.Count);
}
catch (Exception e)
{
Debug.Log("下载失败pp");
}
}
else
{
Debug.Log("没有进去");
}
}
if (CallBack != null)
CallBack.Invoke(num == infos.Count);
}
/// <summary>
/// 记录信息
/// </summary>
public struct BundleInfo
{
public string Path { get; set; }
public string Url { get; set; }
public override bool Equals(object obj)
{
return obj is BundleInfo && Url == ((BundleInfo)obj).Url;
}
public override int GetHashCode()
{
return Url.GetHashCode();
}
}
/// <summary>
/// loadpage展示
/// </summary>
/// <param name="text"></param>
/// <param name="progress"></param>
/// <param name="filealllength"></param>
public static void OpenLodingShow(string text = null, float progress = 0, long filealllength = 0)
{
string allLength = ConstantUtils.GetMillionFromByte(filealllength).ToString("F2");
string currlength = ConstantUtils.GetMillionFromByte((long)(filealllength * progress)).ToString("F2");
LoadingPage.Instance.PrograssText.text = "<color=#8CF976FF>" + currlength + "MB</color>/<color=#FEE646FF>" + allLength + "MB</color>";
LoadingPage.Instance.imagePrograss.DOFillAmount(progress, 0.5f);
if (!string.IsNullOrEmpty(text))
LoadingPage.Instance.LodingDes.text = text;
else
LoadingPage.Instance.LodingDes.text = text;
}
void Update() {
if (UpdateLua != null)
{
UpdateLua.Invoke();
}
if (LuaEnvt != null)
LuaEnvt.Tick();
}
private void OnDestroy()
{
if (DestoryLua != null)
DestoryLua();
UpdateLua = null;
DestoryLua = null;
StartLua = null;
// LuaEnvt.Dispose();
}