123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using System;
- using System.IO;
- using UnityEngine.Networking;
- /// <summary>
- /// 更新助手
- /// </summary>
- public class UpdateHelper : MonoBehaviour
- {
- /// <summary>
- /// 安卓更新文件名称
- /// </summary>
- public static string AndroidUpdateFileName = "UpdateFileAndroid.json";
- /// <summary>
- /// IOS更新文件名称
- /// </summary>
- public static string IosUpdateFileName = "UpdateFileIOS.json";
- /// <summary>
- /// 资源储存的根目录
- /// </summary>
- private string resSaveRootPath = "";
- /// <summary>
- /// 单键
- /// </summary>
- private static UpdateHelper mInst = null;
- /// <summary>
- /// 客户端的更新文件信息
- /// </summary>
- private UpdateFileInfo mClientUpdateFileInfo = null;
- /// <summary>
- /// 服务器上的更新文件信息
- /// </summary>
- private UpdateFileInfo mServerUpdateFileInfo = null;
- /// <summary>
- /// 服务器更新文件的数据
- /// </summary>
- private byte[] mServerUpdateFileDatas = null;
- /// <summary>
- /// 更新列表
- /// </summary>
- private List<string> mUpdateList = new List<string>();
- /// <summary>
- /// 开始更新的时间
- /// </summary>
- private float mUpdateTime = -1;
- /// <summary>
- /// 更新信息
- /// </summary>
- private UpdateInfo mUpdateInfo = new UpdateInfo();
- /// <summary>
- /// 更新迭代器
- /// </summary>
- private IEnumerator mUpdateIEnumerator = null;
- /// <summary>
- /// 超时时间
- /// </summary>
- private const float mTimeOut = 10.0f;
- /// <summary>
- /// 服务器地址
- /// </summary>
- private string mServerUrl = "";
- /// <summary>
- /// 获取单键实例
- /// </summary>
- /// <returns>单键实例</returns>
- public static UpdateHelper Instance()
- {
- return mInst;
- }
- /// <summary>
- /// 唤醒
- /// </summary>
- private void Awake()
- {
- mInst = this;
- resSaveRootPath = Application.persistentDataPath + "/Res/";
- }
- /// <summary>
- /// 获取更新文件列表
- /// </summary>
- public void GetUpdateFile(string serverUrl, Action ac)
- {
- Debug.Log("开始获取更新文件");
- mServerUrl = serverUrl;
- mUpdateTime = Time.time;
- ResetUpdateInfo();
- // 资源保存的路径
- if (!Directory.Exists(resSaveRootPath))
- {
- Directory.CreateDirectory(resSaveRootPath);
- }
- // 加载客户端更新文件
- LoadClientMD5FileInfo((md5) => { });
- // 加载服务器更新文件
- LoadServerMD5FileInfo(serverUrl, (md5) =>
- {
- if (ac != null)
- {
- ac();
- }
- });
- }
- /// <summary>
- /// 当前版本号
- /// </summary>
- /// <returns></returns>
- public void GetCurVersion(Action<int> ac)
- {
- LoadClientMD5FileInfo((info) =>
- {
- if (info != null)
- {
- // 基带版本>=本地版本清空沙盒
- if (GlobalConfig.ClientBsaeVersion >= mClientUpdateFileInfo.Version)
- {
- mUpdateInfo.mCurFileIndex = 1;
- mUpdateInfo.mCurFileProgress = 1;
- mUpdateInfo.mCurFlieName = "";
- mUpdateInfo.mTotalFileCount = 1;
- mUpdateInfo.mUpdateComplete = true;
- // 删除Res文件夹
- if (Directory.Exists(resSaveRootPath))
- {
- Debug.Log("版本已是最新,发现过期的资源文件,开始清理...");
- Directory.Delete(resSaveRootPath, true); // 直接删除路径
- Debug.Log("清理过期的资源文件成功...");
- return;
- }
- }
- ac(info.Version);
- }
- else
- {
- ac(1);
- }
- });
- }
- /// <summary>
- /// 获取完整版本号
- /// </summary>
- /// <returns></returns>
- public string GetFullVersion()
- {
- if (mServerUpdateFileInfo != null)
- {
- int midVer = mServerUpdateFileInfo.Version / 1000;
- int minVer = mServerUpdateFileInfo.Version % 1000;
- string fullVersion = GlobalConfig.ClientVersion + "." + midVer + "." + minVer;
- PlayerPrefs.SetString("Version", fullVersion);
- PlayerPrefs.Save();
- return fullVersion;
- }
- else if (mClientUpdateFileInfo != null)
- {
- int midVer = mClientUpdateFileInfo.Version / 1000;
- int minVer = mClientUpdateFileInfo.Version % 1000;
- string fullVersion = GlobalConfig.ClientVersion + "." + midVer + "." + minVer;
- PlayerPrefs.SetString("Version", fullVersion);
- PlayerPrefs.Save();
- return fullVersion;
- }
- else
- {
- return GlobalConfig.ClientVersion + ".0.0";
- }
- }
- /// <summary>
- /// 获取本地MD5文件
- /// </summary>
- /// <param name="ac"></param>
- public void LoadClientMD5FileInfo(Action<UpdateFileInfo> ac)
- {
- string fullUrl = "";
- // 加载客户端更新文件
- if (mClientUpdateFileInfo == null)
- {
- if (Application.platform == RuntimePlatform.IPhonePlayer)
- {
- fullUrl = GetPath(IosUpdateFileName);
- }
- else
- {
- fullUrl = GetPath(AndroidUpdateFileName);
- }
- StartCoroutine(IE_GetUpdateFile(fullUrl, false, (clientFile) =>
- {
- if (clientFile != null)
- {
- mClientUpdateFileInfo = clientFile;
- ac(mClientUpdateFileInfo);
- }
- else
- {
- ac(null);
- mUpdateTime = -1;
- mClientUpdateFileInfo = null;
- UI_CueDialog.Instance().Open("加载本地MD5文件失败!请稍后重试!", "更新提示", E_DialogType.OneButton, ExitGame);
- }
- }));
- }
- else
- {
- ac(mClientUpdateFileInfo);
- }
- }
- /// <summary>
- /// 加载服务端MD5文件
- /// </summary>
- /// <param name="serverUrl"></param>
- /// <param name="ac"></param>
- public void LoadServerMD5FileInfo(string serverUrl, Action<UpdateFileInfo> ac)
- {
- string fullUrl = "";
- if (mServerUpdateFileInfo == null)
- {
- if (Application.platform == RuntimePlatform.IPhonePlayer)
- {
- fullUrl = serverUrl + "/" + IosUpdateFileName;
- }
- else
- {
- fullUrl = serverUrl + "/" + AndroidUpdateFileName;
- }
- StartCoroutine(IE_GetUpdateFile(fullUrl, true, (serverFile) =>
- {
- if (serverFile != null)
- {
- mServerUpdateFileInfo = serverFile;
- ac(mServerUpdateFileInfo);
- }
- else
- {
- ac(null);
- mUpdateTime = -1;
- mServerUpdateFileInfo = null;
- UI_CueDialog.Instance().Open("从服务器获取更新列表失败!请稍后重试!", "更新提示", E_DialogType.OneButton, ExitGame);
- }
- }));
- }
- else
- {
- ac(mServerUpdateFileInfo);
- }
- }
- /// <summary>
- /// 开始更新
- /// </summary>
- public void CheckUpdate()
- {
- //当用户使用移动网络时,提醒用户是否继续更新
- if (Application.internetReachability == NetworkReachability.ReachableViaCarrierDataNetwork)
- {
- UI_CueDialog.Instance().Open("检测到您当前使用的是流量,更新将消耗您的流量,是否继续更新!", "更新提示", E_DialogType.TwoBntton, StartUpdate, ExitGame);
- }
- else
- {
- StartUpdate();
- }
- }
- /// <summary>
- /// 开始更新
- /// </summary>
- private void StartUpdate()
- {
- // 提取需要更新的列表
- mUpdateList.Clear();
- for (int i = 0; i < mServerUpdateFileInfo.Infos.Count; i++)
- {
- bool add = true;
- for (int j = 0; j < mClientUpdateFileInfo.Infos.Count; j++)
- {
- if (mClientUpdateFileInfo.Infos[j].Name == mServerUpdateFileInfo.Infos[i].Name)
- {
- if (mClientUpdateFileInfo.Infos[j].MD5 == mServerUpdateFileInfo.Infos[i].MD5)
- {
- // md5相同,无需重新下载
- add = false;
- break;
- }
- }
- }
- // 添加到更新列表
- if (add)
- {
- mUpdateList.Add(mServerUpdateFileInfo.Infos[i].Name);
- }
- }
- // 获取更新的断点续传信息
- string LastUpdateInfo = PlayerPrefs.GetString("YLSJ_LastUpdateInfo", "0_0");
- string[] strs = LastUpdateInfo.Split('_');
- int startIndex = 0;
- if (strs.Length == 2)
- {
- int version = int.Parse(strs[0]);
- int index = int.Parse(strs[1]);
- // 储存版本和服务版本一致,更新从记录的索引开始
- if (version == mServerUpdateFileInfo.Version)
- {
- startIndex = index;
- }
- }
- // 开始更新
- mUpdateIEnumerator = IE_DownLoadUpdateFile(startIndex);
- StartCoroutine(mUpdateIEnumerator);
- }
- /// <summary>
- /// 重设更新信息
- /// </summary>
- private void ResetUpdateInfo()
- {
- mClientUpdateFileInfo = null;
- mServerUpdateFileInfo = null;
- mUpdateInfo.mCurFileIndex = 0;
- mUpdateInfo.mCurFileProgress = 0;
- mUpdateInfo.mCurFlieName = "";
- mUpdateInfo.mTotalFileCount = 0;
- mUpdateInfo.mUpdateComplete = false;
- }
- /// <summary>
- /// 获取更新信息
- /// </summary>
- /// <returns></returns>
- public UpdateInfo GetUpdateInfo()
- {
- return mUpdateInfo;
- }
- /// <summary>
- /// 协同加载 更新文件
- /// </summary>
- /// <param name="call"> 当前的更新信息</param>
- /// <returns>返回资源AssetBundle</returns>
- private IEnumerator IE_DownLoadUpdateFile(int index)
- {
- if (index >= 0 && index < mUpdateList.Count)
- {
- mUpdateInfo.mTotalFileCount = mUpdateList.Count;
- string url = "";
- for (int i = index; i < mUpdateList.Count; i++)
- {
- // 加载服务器更新文件
- if (Application.platform == RuntimePlatform.IPhonePlayer)
- {
- url = mServerUrl + "UpdateIOS/" + mUpdateList[i];
- }
- else
- {
- url = mServerUrl + "UpdateAndroid/" + mUpdateList[i];
- }
- mUpdateInfo.mCurFileIndex = i;
- mUpdateInfo.mCurFlieName = mUpdateList[i];
- // 是否有错误
- bool isError = false;
- // 上次的进度
- float lastProgress = 0;
- // 上次进度的时间
- float lastProgresstime = Time.time;
- WWW www = new WWW(url);
- // 未完成,更新进度
- while (www.isDone == false)
- {
- if (lastProgress == www.progress)
- {
- // 检测是否超时
- if (lastProgresstime + mTimeOut <= Time.time)
- {
- isError = true;
- break;
- }
- }
- else
- {
- mUpdateInfo.mCurFileProgress = www.progress + 0.05f;
- lastProgress = www.progress;
- lastProgresstime = Time.time;
- }
- yield return null;
- }
- // 未超时,但有网络返回的错误
- if (isError == false && string.IsNullOrEmpty(www.error) == false)
- {
- continue;
- }
- // 成功
- if (isError == false)
- {
- mUpdateInfo.mCurFileProgress = 1;
- byte[] datas = www.bytes;
- // 保存
- string savePath = resSaveRootPath + mUpdateInfo.mCurFlieName;
- File.WriteAllBytes(savePath, datas);
- // 储存更新信息
- PlayerPrefs.SetString("YLSJ_LastUpdateInfo", mServerUpdateFileInfo.Version + "_" + (i + 1));
- PlayerPrefs.Save();
- }
- // 失败
- else
- {
- mServerUpdateFileDatas = null;
- UI_CueDialog.Instance().Open("更新失败!是否重试!", "更新提示", E_DialogType.TwoBntton, ReUpdate, ExitGame);
- break;
- }
- www.Dispose();
- yield return new WaitForSeconds(0.1f);
- }
- // 更新完成
- mUpdateInfo.mUpdateComplete = true;
- // 储存更新文件
- string fileSavePath = "";
- if (Application.platform == RuntimePlatform.IPhonePlayer)
- {
- fileSavePath = resSaveRootPath + IosUpdateFileName;
- }
- else
- {
- fileSavePath = resSaveRootPath + AndroidUpdateFileName;
- }
- if (mServerUpdateFileDatas != null)
- {
- File.WriteAllBytes(fileSavePath, mServerUpdateFileDatas);
- }
- }
- }
- /// <summary>
- /// 重新更新
- /// </summary>
- private void ReUpdate()
- {
- // 停止正在更新的
- if (mUpdateIEnumerator != null)
- {
- StopCoroutine(mUpdateIEnumerator);
- mUpdateIEnumerator = null;
- }
- // 开始更新
- mUpdateIEnumerator = IE_DownLoadUpdateFile(mUpdateInfo.mCurFileIndex);
- StartCoroutine(mUpdateIEnumerator);
- }
- /// <summary>
- /// 退出游戏
- /// </summary>
- private void ExitGame()
- {
- Application.Quit();
- }
- /// <summary>
- /// 更新
- /// </summary>
- private void Update()
- {
- // 未启用更新
- if (mUpdateTime < 0)
- {
- return;
- }
- // 开始检测更新
- if (mClientUpdateFileInfo != null && mServerUpdateFileInfo != null)
- {
- CheckUpdate();
- mUpdateTime = -1;
- }
- else
- {
- if (mUpdateTime + 10 <= Time.time)
- {
- mUpdateTime = -1;
- UI_CueDialog.Instance().Open("从服务器获取更新列表失败!请稍后重试!", "更新提示", E_DialogType.OneButton, ExitGame);
- }
- }
- }
- /// <summary>
- /// 协同加载 服务器上的更新文件信息
- /// </summary>
- /// <param name="url">地址</param>
- /// <param name="save">是否保存</param>
- /// <param name="fileInfo"> 更新文件信息</param>
- /// <returns>返回资源AssetBundle</returns>
- private IEnumerator IE_GetUpdateFile(string url, bool save, Action<UpdateFileInfo> fileInfo)
- {
- Debug.Log("获取配置的地址:" + url);
- //UnityWebRequest www = UnityWebRequest.Get(url);
- //yield return www.Send();
- // 是否有错误
- bool isError = false;
- // 上次的进度
- float lastProgress = 0;
- // 上次进度的时间
- float lastProgresstime = Time.time;
- WWW www = new WWW(url);
- // 未完成,更新进度
- while (www.isDone == false)
- {
- if (lastProgress == www.progress)
- {
- // 检测是否超时
- if (lastProgresstime + mTimeOut <= Time.time)
- {
- isError = true;
- break;
- }
- }
- else
- {
- mUpdateInfo.mCurFileProgress = www.progress + 0.05f;
- lastProgress = www.progress;
- lastProgresstime = Time.time;
- }
- yield return null;
- }
- // 未超时,但有网络返回的错误
- if (isError == false && string.IsNullOrEmpty(www.error) == false)
- {
- isError = true;
- }
- // 成功
- if (isError == false)
- {
- if (save)
- {
- mServerUpdateFileDatas = www.bytes;
- }
- byte[] datas = www.bytes;
- string DecrypText = System.Text.Encoding.UTF8.GetString(datas);
- fileInfo.Invoke(JsonUtility.FromJson<UpdateFileInfo>(DecrypText));
- }
- // 失败
- else
- {
- fileInfo(null);
- }
- www.Dispose();
- }
- /// <summary>
- /// 获取异步加载资源路径(用于 www 加载)
- /// </summary>
- /// <param name="strName">资源名称</param>
- /// <returns>返回实际路径</returns>
- public string GetPath(string strName)
- {
- string strPath = string.Empty;
- string persistentDataPath = resSaveRootPath + strName;
- if (Application.isEditor)
- {
- if (File.Exists(persistentDataPath))
- {
- strPath = "file:///" + resSaveRootPath + strName;
- }
- else
- {
- strPath = "file://" + Application.streamingAssetsPath + "/" + strName;
- }
- }
- else
- {
- if (File.Exists(persistentDataPath))
- {
- strPath = "file://" + resSaveRootPath + strName;
- }
- else
- {
- if (RuntimePlatform.Android == Application.platform)
- {
- strPath = Application.streamingAssetsPath + "/" + strName;
- }
- else
- {
- strPath = "file://" + Application.streamingAssetsPath + "/" + strName;
- }
- }
- }
- return strPath;
- }
- }
- /// <summary>
- /// 更新信息
- /// </summary>
- public class UpdateInfo
- {
- /// <summary>
- /// 总共的文件数
- /// </summary>
- public int mTotalFileCount = 0;
- /// <summary>
- /// 当前文件索引
- /// </summary>
- public int mCurFileIndex = 0;
- private float _curFileProgress;
- /// <summary>
- /// 当前文件的索引
- /// </summary>
- public float mCurFileProgress
- {
- set
- {
- this._curFileProgress = value;
- if (_curFileProgress > 1.0f)
- {
- _curFileProgress = 1.0f;
- }
- }
- get { return _curFileProgress; }
- }
- /// <summary>
- /// 当前文件的名称
- /// </summary>
- public string mCurFlieName = "";
- /// <summary>
- /// 更新是否完成
- /// </summary>
- public bool mUpdateComplete = false;
- }
|