SDK_UnityMoney/Assets/EFSDK/Editor/AndroidResAarBuilder.cs

203 lines
7.5 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.unity.reswrapper"">
<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)");
}
}
}