Unity更新資源代碼


如果發布android端  需要將路徑改為Application.persistentDataPath

還有一定要注意ip地址和打包的平台類型..... 一上午買了個記性.....

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using UnityEngine.Networking;

public class ResUpdate : MonoBehaviour
{
public string VERSION_FILE;// = "version.txt"; //文件名
public string LOCAL_RES_URL;// = "file://" + Application.dataPath + "/Res/"; //本地文件的路徑加file是為了使用WWW拿到絕對路徑,這個例子其實可以只使用下邊一個Application.dataPath
public string SERVER_RES_URL;// = "file:///C:/Res/"; //服務器文件的路徑
public string LOCAL_RES_PATH;// = Application.dataPath + "/Res/"; //游戲文件的本地路徑

private Dictionary<string,string> LocalResVersion; //本地配置文件的內存變量

private Dictionary<string, string> ServerResVersion; //服務器配置文件的內存變量
private List<string> NeedDownFiles; //需要更新的文件列表
private bool NeedUpdateLocalVersionFile = false; //是否需要更新

private void Awake()
{
NeedDownFiles = new List<string>();
VERSION_FILE = "version.txt";
LOCAL_RES_URL = "file://" + Application.dataPath + "/AssetBundles/";
SERVER_RES_URL = @"file://C:/Users/Administrator/Desktop/";
LOCAL_RES_PATH = Application.dataPath + "/AssetBundles/";
}

void Start()
{
//初始化
LocalResVersion = new Dictionary<string, string>(); // 將本地文件中的包名+MD5放到這個內存變量中
ServerResVersion = new Dictionary<string, string>(); //將服務器文件中的包名+MD5放到這個內存變量中

//加載本地version配置
StartCoroutine(DownLoad(LOCAL_RES_PATH + VERSION_FILE, delegate(WWW localVersion)
{
//保存本地的version
ParseVersionFile(localVersion.text, LocalResVersion);
//加載服務端version配置
StartCoroutine(DownLoad(SERVER_RES_URL + VERSION_FILE, delegate(WWW serverVersion)
{
//保存服務端version
ParseVersionFile(serverVersion.text, ServerResVersion);
//計算出需要重新加載的資源
CompareVersion();
//加載需要更新的資源
DownLoadRes();
}));

}));
}

//依次加載需要更新的資源
private void DownLoadRes() //這是一個遞歸
{
if (NeedDownFiles.Count == 0) //如果沒有需要更新的文件 或者說需要更新的文件已經全更新完了
{
UpdateLocalVersionFile(); //更新本地配置文件
return;
}

string file = NeedDownFiles[0]; //獲取當前列表中第一個需要更新的文件
NeedDownFiles.RemoveAt(0); //移除當前列表中第一個需要更新的文件

StartCoroutine(this.DownLoad(SERVER_RES_URL + file, delegate(WWW w) //從服務器通過文件名下載剛剛刪除的內存變量中第一個需要更新的文件
{
//將下載的資源替換本地就的資源
ReplaceLocalRes(file, w.bytes);
DownLoadRes();
}));
}

private void ReplaceLocalRes(string fileName, byte[] data) //通過文件名替換/添加新文件 通過字節的方式傳輸
{
string filePath = LOCAL_RES_PATH + fileName; //存儲一下當前下載的文件名,在前邊加上放到的路徑
FileStream stream = new FileStream(filePath, FileMode.Create); //創建一個文件路徑為上邊的變量
stream.Write(data, 0, data.Length); //將數據(ab包)字節寫入文件流中
stream.Flush(); //將文件流強行寫入硬盤
stream.Close(); //關閉文件流
}

//顯示資源 待改為UnityWebRequest
private IEnumerator Show()
{

UnityWebRequest request = UnityWebRequest.GetAssetBundle("file://" + Application.dataPath + "/AssetBundles/" + "cube.ab");
yield return request.SendWebRequest();
//AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request); //這兩種獲取ab包的方式都可以
AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
print(ab.name);
GameObject go = ab.LoadAsset<GameObject>("Cube");
Instantiate(go);
ab.Unload(false);
request.Dispose();


}

//更新本地的version配置
private void UpdateLocalVersionFile()
{
if (NeedUpdateLocalVersionFile) //如果有需要更新的文件情況下執行(因為沒有更新的文件情況下也會調用這個方法,下邊有個Show方法(- -...)), 不能通過NeedDownFiles = 0來判斷, 因為程序走到這里NeedDownFiles是一定等於0的,上邊逐個更新逐個刪除,所以為0
{
StringBuilder versions = new StringBuilder(); //創建字符流節省運算量,
foreach (var item in ServerResVersion) //遍歷服務器文件的內存變量
{
versions.Append(item.Key).Append(",").Append(item.Value).Append("\n"); //將里邊的key+value遍歷寫入到字符流中
}

FileStream stream = new FileStream(LOCAL_RES_PATH + VERSION_FILE, FileMode.Create); //再創建個文件流
byte[] data = Encoding.UTF8.GetBytes(versions.ToString()); //把字符流轉換為byte[] 因為寫入時需要byte[]類型
stream.Write(data, 0, data.Length); //寫入字符流內存
stream.Flush(); //強制寫入硬盤
stream.Close(); //關閉字符流
}
//加載顯示對象
StartCoroutine(Show());
}

private void CompareVersion()
{
foreach (var version in ServerResVersion) //遍歷服務器變量
{
string fileName = version.Key; //保存其中一項Key
string serverMd5 = version.Value; //保存其中一項Value
//新增的資源
if (!LocalResVersion.ContainsKey(fileName)) //如果本地存儲的內存文件中不包含服務器中這個項的Key(新資源)
{
NeedDownFiles.Add(fileName); //將這項添加到需要更新的List
}
else //否則可能是需要替換的資源也可能是不需要替換的,這需要通過MD5值進行判斷
{
//需要替換的資源
string localMd5;
LocalResVersion.TryGetValue(fileName, out localMd5); //從本地文件判斷一下服務器中這個文件的名字的MD5 並返回,以供下邊判斷同一個文件名的包是否是同一個MD5
if (!serverMd5.Equals(localMd5)) //當前服務器項中這個MD5不等於本地的,也就是不是一個資源, 那么需要更新
{
NeedDownFiles.Add(fileName); //添加到集合
}
}
}
//本次有更新,同時更新本地的version.txt
NeedUpdateLocalVersionFile = NeedDownFiles.Count > 0; //判斷需要更新和添加的資源是否大於0 賦值給bool判斷變量
}

private void ParseVersionFile(string content, Dictionary<string, string> dict) // 從www加載的text 保存到哪個字典中
{
if (content == null || content.Length == 0) //如果參數為null或者長度為null 不處理(正常不會走到這一步,一般是沒有這個文件或者文件內容為空)
{
return;
}
string[] items = content.Split(new char[] { '\n' }); //將文件中數據按回車分割到items數組中,也就是 文件名+MD5為一個數據
foreach (string item in items) //遍歷
{
string[] info = item.Split(new char[] { ',' }); //將文件名和MD5分割
if (info != null && info.Length == 2) //安全校驗
{
dict.Add(info[0], info[1]); //添加到傳遞過來的字典中 參數是本地文件內存變量就保存到本地內存變量,參數是服務器文件內存變量就保存到服務器文件內存變量
}
}
}

private IEnumerator DownLoad(string url, HandleFinishDownload finishFun) //帶有委托的方法,讓注冊進委托的方法去調用(也就是上邊的匿名函數)
{
WWW www = new WWW(url); //創建一個www實例, 待改為UnityWebRequest
yield return www;
if (finishFun != null) //如果參數不為空,也就是有方法被注冊進委托
{
finishFun(www); //激活委托調用上邊注冊進來的的匿名函數
}
www.Dispose(); //釋放www
}

public delegate void HandleFinishDownload(WWW www); //使用一個委托,才能使用匿名函數使代碼更簡潔
}

 

 

 

 

 

 

//********************************改為UnityWebRequest方式實現

 

 

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using UnityEngine.Networking;

public class ResUpdate : MonoBehaviour
{
public string VERSION_FILE;// = "version.txt"; //文件名
public string LOCAL_RES_URL;// = "file://" + Application.dataPath + "/Res/"; //本地文件的路徑加file是為了使用WWW拿到絕對路徑,這個例子其實可以只使用下邊一個Application.dataPath
public string SERVER_RES_URL;// = "file:///C:/Res/"; //服務器文件的路徑
public string LOCAL_RES_PATH;// = Application.dataPath + "/Res/"; //游戲文件的本地路徑

private Dictionary<string,string> LocalResVersion; //本地配置文件的內存變量

private Dictionary<string, string> ServerResVersion; //服務器配置文件的內存變量
private List<string> NeedDownFiles; //需要更新的文件列表
private bool NeedUpdateLocalVersionFile = false; //是否需要更新

private void Awake()
{
NeedDownFiles = new List<string>();
VERSION_FILE = "version.txt";
LOCAL_RES_URL = "file://" + Application.dataPath + "/AssetBundles/";
SERVER_RES_URL = @"file://C:/Users/Administrator/Desktop/";
LOCAL_RES_PATH = Application.dataPath + "/AssetBundles/";
}

void Start()
{
//初始化
LocalResVersion = new Dictionary<string, string>(); // 將本地文件中的包名+MD5放到這個內存變量中
ServerResVersion = new Dictionary<string, string>(); //將服務器文件中的包名+MD5放到這個內存變量中

//加載本地version配置
StartCoroutine(DownLoad(LOCAL_RES_PATH + VERSION_FILE, delegate(UnityWebRequest localVersion)
{
//保存本地的version
ParseVersionFile(localVersion.downloadHandler.text, LocalResVersion);
//加載服務端version配置
StartCoroutine(DownLoad(SERVER_RES_URL + VERSION_FILE, delegate(UnityWebRequest serverVersion)
{
//保存服務端version
ParseVersionFile(serverVersion.downloadHandler.text, ServerResVersion);
//計算出需要重新加載的資源
CompareVersion();
//加載需要更新的資源
DownLoadRes();
}));

}));
}

//依次加載需要更新的資源
private void DownLoadRes() //這是一個遞歸
{
if (NeedDownFiles.Count == 0) //如果沒有需要更新的文件 或者說需要更新的文件已經全更新完了
{
UpdateLocalVersionFile(); //更新本地配置文件
return;
}

string file = NeedDownFiles[0]; //獲取當前列表中第一個需要更新的文件
NeedDownFiles.RemoveAt(0); //移除當前列表中第一個需要更新的文件

StartCoroutine(this.DownLoad(SERVER_RES_URL + file, delegate(UnityWebRequest w) //從服務器通過文件名下載剛剛刪除的內存變量中第一個需要更新的文件
{
//將下載的資源替換本地就的資源
ReplaceLocalRes(file, w.downloadHandler.data);
DownLoadRes();
}));
}

private void ReplaceLocalRes(string fileName, byte[] data) //通過文件名替換/添加新文件 通過字節的方式傳輸
{
string filePath = LOCAL_RES_PATH + fileName; //存儲一下當前下載的文件名,在前邊加上放到的路徑
FileStream stream = new FileStream(filePath, FileMode.Create); //創建一個文件路徑為上邊的變量
stream.Write(data, 0, data.Length); //將數據(ab包)字節寫入文件流中
stream.Flush(); //將文件流強行寫入硬盤
stream.Close(); //關閉文件流
}

//顯示資源 待改為UnityWebRequest
private IEnumerator Show()
{

UnityWebRequest request = UnityWebRequest.GetAssetBundle("file://" + Application.dataPath + "/AssetBundles/" + "cube.ab");
yield return request.SendWebRequest();
//AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request); //這兩種獲取ab包的方式都可以
AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
print(ab.name);
GameObject go = ab.LoadAsset<GameObject>("Cube");
Instantiate(go);
ab.Unload(false);
request.Dispose();


}

//更新本地的version配置
private void UpdateLocalVersionFile()
{
if (NeedUpdateLocalVersionFile) //如果有需要更新的文件情況下執行(因為沒有更新的文件情況下也會調用這個方法,下邊有個Show方法(- -...)), 不能通過NeedDownFiles = 0來判斷, 因為程序走到這里NeedDownFiles是一定等於0的,上邊逐個更新逐個刪除,所以為0
{
StringBuilder versions = new StringBuilder(); //創建字符流節省運算量,
foreach (var item in ServerResVersion) //遍歷服務器文件的內存變量
{
versions.Append(item.Key).Append(",").Append(item.Value).Append("\n"); //將里邊的key+value遍歷寫入到字符流中
}

FileStream stream = new FileStream(LOCAL_RES_PATH + VERSION_FILE, FileMode.Create); //再創建個文件流
byte[] data = Encoding.UTF8.GetBytes(versions.ToString()); //把字符流轉換為byte[] 因為寫入時需要byte[]類型
stream.Write(data, 0, data.Length); //寫入字符流內存
stream.Flush(); //強制寫入硬盤
stream.Close(); //關閉字符流
}
//加載顯示對象
StartCoroutine(Show());
}

private void CompareVersion()
{
foreach (var version in ServerResVersion) //遍歷服務器變量
{
string fileName = version.Key; //保存其中一項Key
string serverMd5 = version.Value; //保存其中一項Value
//新增的資源
if (!LocalResVersion.ContainsKey(fileName)) //如果本地存儲的內存文件中不包含服務器中這個項的Key(新資源)
{
NeedDownFiles.Add(fileName); //將這項添加到需要更新的List
}
else //否則可能是需要替換的資源也可能是不需要替換的,這需要通過MD5值進行判斷
{
//需要替換的資源
string localMd5;
LocalResVersion.TryGetValue(fileName, out localMd5); //從本地文件判斷一下服務器中這個文件的名字的MD5 並返回,以供下邊判斷同一個文件名的包是否是同一個MD5
if (!serverMd5.Equals(localMd5)) //當前服務器項中這個MD5不等於本地的,也就是不是一個資源, 那么需要更新
{
NeedDownFiles.Add(fileName); //添加到集合
}
}
}
//本次有更新,同時更新本地的version.txt
NeedUpdateLocalVersionFile = NeedDownFiles.Count > 0; //判斷需要更新和添加的資源是否大於0 賦值給bool判斷變量
}

private void ParseVersionFile(string content, Dictionary<string, string> dict) // 從www加載的text 保存到哪個字典中
{
if (content == null || content.Length == 0) //如果參數為null或者長度為null 不處理(正常不會走到這一步,一般是沒有這個文件或者文件內容為空)
{
return;
}
string[] items = content.Split(new char[] { '\n' }); //將文件中數據按回車分割到items數組中,也就是 文件名+MD5為一個數據
foreach (string item in items) //遍歷
{
string[] info = item.Split(new char[] { ',' }); //將文件名和MD5分割
if (info != null && info.Length == 2) //安全校驗
{
dict.Add(info[0], info[1]); //添加到傳遞過來的字典中 參數是本地文件內存變量就保存到本地內存變量,參數是服務器文件內存變量就保存到服務器文件內存變量
}
}
}

private IEnumerator DownLoad(string url, HandleFinishDownload finishFun) //帶有委托的方法,讓注冊進委托的方法去調用(也就是上邊的匿名函數)
{
UnityWebRequest request = UnityWebRequest.Get(url);
yield return request.SendWebRequest();
if (finishFun != null) //如果參數不為空,也就是有方法被注冊進委托
{
finishFun(request); //激活委托調用上邊注冊進來的的匿名函數
}
request.Dispose(); //釋放request
}

public delegate void HandleFinishDownload(UnityWebRequest request); //使用一個委托,才能使用匿名函數使代碼更簡潔
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM