Unity AssetBundle 热更 资源生成对应 MD5码
每个热更 AssetBundle 文件对应一个MD5码,写入一个 更新文件如update.txt,当有版本更新时,将update.txt 放到服务器,客户端在启动游戏时,首先会从服务端请求一下当前最新版本号,和本地的版本号比较,如果客户端和服务器版本号一致,则视为客户端为最新版本不需要更新,进入游戏。
如果客户端版本号低于最新版本号,则客户端向服务器请求版本更新文件 update.txt ,将 服务器的 update.txt 下载下来,和本地的 update.txt 文件对比。
找出需要更新的文件:
一、服务端 update.txt 中 的文件名, 客户端 update.txt 中没有的,为新版本添加文件,需要更新
二、服务端 update.txt 中有,客户端 update.txt 也有,但是 MD5 码不同,说明新版本对文件有改动,需要更新
全部代码如下:
using UnityEngine;
using System.Text;
using System;
using System.IO;
using UnityEditor;
using System.Linq;
using System.Security.Cryptography;
public static class BuildAssetBundleVersion
{
public static string assetPath = string.Empty;
public static void BuildVersion()
{
assetPath = Path.Combine(Application.streamingAssetsPath, "AssetBundle");
Caching.CleanCache();
CreateUpdateTXT();
AssetDatabase.Refresh();
}
// 创建更新文本
private static void CreateUpdateTXT()
{
string[] files = (string[])Directory.GetFiles(assetPath, "*.*", SearchOption.AllDirectories).Where(s => !s.EndsWith(".meta"));
StringBuilder stringBuilder = new StringBuilder();
foreach (string filePath in files)
{
string md5 = BuildFileMd5(filePath);
string fileName = filePath.Substring(filePath.LastIndexOf("AssetBundle\\") + ("AssetBundle\\").Length);
stringBuilder.AppendLine(string.Format("{0}:{1}", fileName, md5));
}
string updatePath = Path.Combine(Application.streamingAssetsPath, "Version/update.txt");
WriteTXT(updatePath, stringBuilder.ToString());
}
private static string BuildFileMd5(string filePath)
{
string fileMd5 = string.Empty;
try
{
using (FileStream fs = File.OpenRead(filePath))
{
MD5 md5 = MD5.Create();
byte[] fileMd5Bytes = md5.ComputeHash(fs); // 计算FileStream 对象的哈希值
fileMd5 = System.BitConverter.ToString(fileMd5Bytes).Replace("-", "").ToLower();
}
}
catch (System.Exception ex)
{
Debug.LogError(ex);
}
return fileMd5;
}
private static void WriteTXT(string path, string content)
{
string directory = Path.GetDirectoryName(path);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
if (File.Exists(path))
{
File.Delete(path);
}
using (FileStream fs = File.Create(path))
{
StreamWriter sw = new StreamWriter(fs, Encoding.ASCII);
try
{
sw.Write(content);
sw.Close();
fs.Close();
fs.Dispose();
}
catch (IOException e)
{
Debug.Log(e.Message);
}
}
}
}
将生成的 AssetBundle 的所有文件生成 MD5码保存到 update.txt 文件
每一行为一条数据,包含文件名:文件 MD5 码。对比时逐行读取。
伪代码如下
读取服务端 update.txt,逐行解析存入 serverUpdateDic,文件名为 key, MD5 码为 value
读取客户端本地 update.txt, 逐行解析存入 clientUpdateDic,文件名为 key, MD5 码为 value
List<string> updateFileList = new List<string>();
// 遍历服务端数据字典
foreach (var pair in serverUpdateDic)
{
string fileName = pair.key;
string md5 = pair.value;
if (clientUpdateDic 包含 fileName)
{
if (clientUpdateDic[fileName] 等于 md5)
{
// 客户端本地和服务端的相同不需要更新
continue;
}
}
updateFileList.add(fileName);
}
迭代 updateFileList 下载需要更新文件
更新完毕,将客户端本地 update.txt 更新为 最新的 update.txt。
思路,对比文件时将客户端本来就有的不需要更新的文件保存到一个字典中,
对比完成时将这些文件名和MD5码直接写入新的 客户端 update.txt,每下载完成一个文件将文件名和 MD5 码加入到update.txt,所有文件更新完成时,客户端的 update.txt 就同步为何服务器端一致了,好处是下载到一半时断网了,退出游戏了,那么下次进入游戏对比 update.txt 时,就不需要再次下载刚才更新过的文件了。