206 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C#
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C#
		
	
	
		
			Executable File
		
	
	
| using UnityEngine;
 | |
| using UnityEditor;
 | |
| using System.IO;
 | |
| using System.Collections.Generic;
 | |
| using System.Security.Cryptography;
 | |
| using System.Text;
 | |
| using IOCompression = System.IO.Compression;
 | |
| 
 | |
| namespace EFSDK
 | |
| {
 | |
|     public class AndroidResAarBuilder
 | |
|     {
 | |
|         private static readonly string ResDir = "Assets/EFSDK/Android";
 | |
|         private static readonly string OutputDir = "Assets/Plugins/Android";
 | |
|         private static readonly string TempDir = "Temp/AndroidResAar";
 | |
|         private static readonly string EFSdk_FILE = "Assets/EFSDK/EFSdk.cs";
 | |
| 
 | |
|         [MenuItem("EFSDK/Build Android Res AAR")]
 | |
|         public static void BuildAAR()
 | |
|         {
 | |
|             if (!Directory.Exists(ResDir))
 | |
|             {
 | |
|                 Debug.LogError($"Res folder not found: {ResDir}");
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             // 清理临时目录
 | |
|             if (Directory.Exists(TempDir)) Directory.Delete(TempDir, true);
 | |
|             Directory.CreateDirectory(TempDir);
 | |
| 
 | |
|             // 复制资源并重命名
 | |
|             CopyAndRenameFiles(ResDir, TempDir, out Dictionary<string, string> mapping);
 | |
|             string manifestPath = Path.Combine(TempDir, "AndroidManifest.xml");
 | |
|             File.WriteAllText(manifestPath,
 | |
|                 @$"<manifest xmlns:android=""http://schemas.android.com/apk/res/android""
 | |
|     package=""com.{GetFirstEightWithUnderscore(GetMD5Hash(Application.identifier + "res"))}"">
 | |
|     <application/>
 | |
| </manifest>");
 | |
| 
 | |
|             // 打包 AAR
 | |
|             string aarPath = Path.Combine(OutputDir, "efsdk_res.aar");
 | |
|             if (!Directory.Exists(OutputDir)) Directory.CreateDirectory(OutputDir);
 | |
|             if (File.Exists(aarPath)) File.Delete(aarPath);
 | |
| 
 | |
|             IOCompression.ZipFile.CreateFromDirectory(TempDir, aarPath, IOCompression.CompressionLevel.Optimal, false);
 | |
|             Debug.Log($"✅ AAR built: {aarPath}");
 | |
| 
 | |
|             // 生成压缩 JSON (key 只保留文件名)
 | |
|             Dictionary<string, string> simpleMapping = new Dictionary<string, string>();
 | |
|             foreach (var kv in mapping)
 | |
|             {
 | |
|                 string fileName = Path.GetFileName(kv.Key);
 | |
|                 simpleMapping[fileName] = kv.Value;
 | |
|             }
 | |
| 
 | |
|             string mappingJson = GenerateMappingJson(mapping);
 | |
|             // 更新 mappingInfo
 | |
|             // UpdateMappingInEFSdk_LineByLine(mappingJson);
 | |
|             // 映射文件
 | |
|             string mappingPath = Path.Combine(TempDir, "res_mapping.json");
 | |
|             File.WriteAllText(mappingPath, mappingJson);
 | |
| 
 | |
|             // 清理临时目录
 | |
|             Directory.Delete(TempDir, true);
 | |
|             AssetDatabase.Refresh();
 | |
|         }
 | |
| 
 | |
|         private static void CopyAndRenameFiles(string srcDir, string dstDir, out Dictionary<string, string> mapping)
 | |
|         {
 | |
|             mapping = new Dictionary<string, string>();
 | |
| 
 | |
|             foreach (var filePath in Directory.GetFiles(srcDir, "*", SearchOption.AllDirectories))
 | |
|             {
 | |
|                 if (filePath.EndsWith(".meta")) continue;
 | |
| 
 | |
|                 // 相对于源目录的路径
 | |
|                 string relativePath = filePath.Substring(srcDir.Length + 1).Replace("\\", "/");
 | |
| 
 | |
|                 // 获取文件夹路径
 | |
|                 string relativeDir = Path.GetDirectoryName(relativePath).Replace("\\", "/");
 | |
| 
 | |
|                 // 生成随机文件名
 | |
|                 string newName = GenerateRandomAndroidName(filePath);
 | |
| 
 | |
|                 // 保存映射关系 (相对路径 + 原始文件名 -> 随机名)
 | |
|                 string key = Path.GetFileNameWithoutExtension(relativePath); // 可以保留目录信息
 | |
|                 string value = string.IsNullOrEmpty(relativeDir) ? newName : $"{relativeDir}/{newName}";
 | |
|                 string fileNameWithoutExt = Path.GetFileNameWithoutExtension(value);
 | |
|                 mapping[key] = fileNameWithoutExt;
 | |
| 
 | |
|                 // 目标路径
 | |
|                 string dstPath = Path.Combine(dstDir, value.Replace("/", Path.DirectorySeparatorChar.ToString()));
 | |
| 
 | |
|                 // 确保目录存在
 | |
|                 string dstFolder = Path.GetDirectoryName(dstPath);
 | |
|                 if (!Directory.Exists(dstFolder)) Directory.CreateDirectory(dstFolder);
 | |
| 
 | |
|                 // 复制文件
 | |
|                 File.Copy(filePath, dstPath);
 | |
|             }
 | |
| 
 | |
|             Debug.Log("✅ Files copied and renamed (directory structure preserved)");
 | |
|         }
 | |
| 
 | |
|         private static string GenerateMappingJson(Dictionary<string, string> mapping)
 | |
|         {
 | |
|             var items = new List<MappingItem>();
 | |
|             foreach (var kv in mapping)
 | |
|             {
 | |
|                 items.Add(new MappingItem { key = kv.Key, value = kv.Value });
 | |
|             }
 | |
| 
 | |
|             MappingListWrapper wrapper = new MappingListWrapper { items = items };
 | |
|             return JsonUtility.ToJson(wrapper, false);
 | |
|         }
 | |
| 
 | |
|         [System.Serializable]
 | |
|         private class MappingItem
 | |
|         {
 | |
|             public string key;
 | |
|             public string value;
 | |
|         }
 | |
| 
 | |
|         [System.Serializable]
 | |
|         private class MappingListWrapper
 | |
|         {
 | |
|             public List<MappingItem> items;
 | |
|         }
 | |
| 
 | |
|         private static string GenerateRandomAndroidName(string filePath)
 | |
|         {
 | |
|             string ext = Path.GetExtension(filePath);
 | |
|             string oriFileName = Path.GetFileNameWithoutExtension(filePath);
 | |
|             string md5Str = GetFirstEightWithUnderscore(GetMD5Hash(Application.identifier + oriFileName + oriFileName));
 | |
|             return md5Str + ext;
 | |
|         }
 | |
| 
 | |
|         static string GetFirstEightWithUnderscore(string str)
 | |
|         {
 | |
|             if (string.IsNullOrEmpty(str)) return str;
 | |
|             string sub = str.Length <= 8 ? str : str.Substring(0, 8);
 | |
|             if (char.IsDigit(sub[0]))
 | |
|             {
 | |
|                 sub = "a" + sub;
 | |
|             }
 | |
| 
 | |
|             return sub;
 | |
|         }
 | |
| 
 | |
|         public static string GetMD5Hash(string input)
 | |
|         {
 | |
|             using (var md5 = MD5.Create())
 | |
|             {
 | |
|                 var inputBytes = Encoding.ASCII.GetBytes(input);
 | |
|                 var hashBytes = md5.ComputeHash(inputBytes);
 | |
| 
 | |
|                 var builder = new StringBuilder();
 | |
|                 foreach (var t in hashBytes)
 | |
|                 {
 | |
|                     builder.Append(t.ToString("x2")); // Convert byte to hexadecimal string
 | |
|                 }
 | |
| 
 | |
|                 return builder.ToString();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static void UpdateMappingInEFSdk_LineByLine(string mappingJson)
 | |
|         {
 | |
|             if (!File.Exists(EFSdk_FILE))
 | |
|             {
 | |
|                 Debug.LogError($"EFSdk.cs not found: {EFSdk_FILE}");
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             string[] lines = File.ReadAllLines(EFSdk_FILE);
 | |
|             bool updated = false;
 | |
|             for (int i = 0; i < lines.Length; i++)
 | |
|             {
 | |
|                 if (lines[i].Contains("mappingInfo"))
 | |
|                 {
 | |
|                     lines[i] = $"        private static string mappingInfo = @\"{mappingJson.Replace("\"", "\"\"")}\";";
 | |
|                     updated = true;
 | |
|                     break; // 找到第一行就替换,防止重复
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (!updated)
 | |
|             {
 | |
|                 // 如果没有找到 mappingInfo 行,则在 _mEfSdk 后插入
 | |
|                 for (int i = 0; i < lines.Length; i++)
 | |
|                 {
 | |
|                     if (lines[i].Contains("private static EFSdk _mEfSdk"))
 | |
|                     {
 | |
|                         lines[i] +=
 | |
|                             $"\n        private static string mappingInfo = @\"{mappingJson.Replace("\"", "\"\"")}\";";
 | |
|                         updated = true;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             File.WriteAllLines(EFSdk_FILE, lines);
 | |
|             Debug.Log("✅ mappingInfo updated in EFSdk.cs (line-by-line)");
 | |
|         }
 | |
|     }
 | |
| } |