2023年11月29日发(作者:)

Unity热更新笔记(三)Addressable+ILRuntime实现代码热更

系列⽂章⽬录

⽬录

简介

把热更项⽬的 DLL 作为 addressable 的资源来实现热更新

流程

资源部分

(1)addressable 是不⽀持 dll 的,所以需要把 dll ⽂件加⼯成 addressable ⽀持的格式

(2)直接 lBytes 读取成 bytes 然后 llBytes 保存

(3)保存⽂件的后缀为 .bytes (.txt 被会被转换成 UTF-8 编码导致加载出来跟源⽂件不符) (4)然后是正常的资源热更新

DLL 加载

(1)使⽤ TextAsset 类型加载⽂件

(2) 拿到需要的 byte[]

(3)后续就是正常的 ILRuntime 初始化了

DLL 转换代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

[MenuItem("MyMenu/ILRuntime/DLL To byte[]")]

public static void DLLToBytes()

{

DLLToBytes(true);

}

[MenuItem("MyMenu/ILRuntime/DLL To byte[] (Choose Folder)")]

public static void DLLToBytes_Choose()

{

DLLToBytes(false);

}

private static void DLLToBytes(bool autoChoosePath)

{

string folderPath;

if (autoChoosePath)

folderPath = NormalPath;

else

folderPath= EditorUtility.OpenFolderPanel("选择 DLL 所在的⽂件夹", Application.dataPath + "/Addressable/ILRuntime", string.Empty);

if (string.IsNullOrEmpty(folderPath)) return;

DirectoryInfo directoryInfo = new DirectoryInfo(folderPath);

if (directoryInfo == null) return;

FileInfo[] fileInfos = directoryInfo.GetFiles();

List<FileInfo> listDLL = new List<FileInfo>();

List<FileInfo> listPDB = new List<FileInfo>();

for (int i = 0; i < fileInfos.Length; i++)

{

if (fileInfos[i].Extension == ".dll")

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

if (fileInfos[i].Extension == ".dll")

{

listDLL.Add(fileInfos[i]);

}

else if (fileInfos[i].Extension == ".pdb")

{

listPDB.Add(fileInfos[i]);

}

}

if (listDLL.Count + listPDB.Count <= 0)

{

Debug.Log("⽂件夹下没有dll⽂件");

return;

}

else

{

Debug.Log("选择路径为:" + folderPath);

}

string savePath;

if (autoChoosePath)

savePath = NormalPath;

else

savePath = EditorUtility.OpenFolderPanel("选择 DLL 转换后保存的⽂件夹", Application.dataPath + "/Addressable/ILRuntime", string.Empty);

if (string.IsNullOrEmpty(savePath)) return;

Debug.Log("---开始转换 DLL ⽂件------------------");

string path = string.Empty;

for (int i = 0; i < listDLL.Count; i++)

{

path = $"{savePath}/{eNameWithoutExtension(listDLL[i].Name)}_dll_";

BytesToFile(path, FileToBytes(listDLL[i]));

}

Debug.Log("---DLL ⽂件转换结束------------------");

Debug.Log("---开始转换 PDB ⽂件------------------");

for (int i = 0; i < listPDB.Count; i++)

{

path = $"{savePath}/{eNameWithoutExtension(listPDB[i].Name)}_pdb_";

BytesToFile(path, FileToBytes(listPDB[i]));

}

Debug.Log("---PDB ⽂件转换结束------------------");

Debug.Log("导出路径为:" + savePath);

AssetDatabase.Refresh();

}

private static byte[] FileToBytes(FileInfo fileInfo)

{

return File.ReadAllBytes(fileInfo.FullName);

}

private static void BytesToFile(string path, byte[] bytes)

{

Debug.Log($"Path:{path}nlength:{}");

File.WriteAllBytes(path, bytes);

}

DLL 加载代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

private static byte[] LoadFile(string path)

{

Debug.Log(path);

return System.IO.File.ReadAllBytes(path);

}

private static async Task<byte[]> LoadFile_Addressables(string path)

{

Debug.Log(path);

var text= await Addressables.LoadAssetAsync<TextAsset>(path).Task;

return text.bytes;

}

private static async Task<byte[]> LoadFile_WebRequest(string path)

{

var request = UnityWebRequest.Get("file:///" + DLLPath_File );

request.SendWebRequest();

while (!request.isDone)

await Task.Delay(200);

if (!string.IsNullOrEmpty(request.error))

Debug.LogError(request.error);

byte[] bytes = request.downloadHandler.data;

//

销毁请求对象

request.Dispose();

return bytes;

}