using UnityEngine; using UnityEditor; using System.IO; using System; using GameEditor.FrameTool; using GameEditor.Util; using System.Collections; using System.Collections.Generic; public class PackConfig { public string name; public string scene; public string project; public string version; public string bench; public PackConfig(string _name, string _scene, string _project, string _version, string _bench) { name = _name; scene = _scene; project = _project; version= _version; bench = _bench; } } public class AutoPack : EditorWindow { static List PackConfig = new List(); #if UNITY_ANDROID static string Platform = "Android"; static string ConfigFileName = "config.txt"; static string VersionFileName = "version.txt"; #elif UNITY_IOS static string Platform = "IOS"; static string ConfigFileName = "config.txt"; static string VersionFileName = "version.txt"; #else static string Platform = "Android"; static string ConfigFileName = "config.txt"; static string VersionFileName = "version.txt"; #endif static string MomPackPath; static string ExportPackPath; static string ScenePath; static string ABPath; static string APKPath; static string PackTime; static bool CommitToGit; // 判断是否要重新导出工程 static string[] ExportTypeList = { "导出工程,替换出包", "只替换AB出包", "只出包" }; static int ExportType; static bool[] Chooser; static bool isObb = false; static string benchName; // 当前所在分支 private void OnEnable() { MomPackPath = EditorPrefs.GetString("MomPackPath", ""); ExportPackPath = Application.dataPath.Replace("Assets", "ExportProject"); ScenePath = Application.dataPath + "/LuaFramework/Scenes/"; ABPath = Application.dataPath + "/../BuildABs/" + Platform + "/"; ExportType = 2; // 加载配置 LoadConfig(); } static void LoadConfig() { PackConfig.Clear(); Hashtable config = ClientConfigManager.Instance.GetAutoPackConfig(); foreach (string k in config.Keys) { Hashtable ht = config[k] as Hashtable; string name = k; string scene = ht["scene"] as string; string project = ht["project"] as string; string version = ht["version"] as string; string bench = ht["bench"] as string; PackConfig.Add(new PackConfig(name, scene, project, version, bench)); } Chooser = new bool[PackConfig.Count]; } /// /// 版本文件路径 /// static string _MomPackPath { get { return MomPackPath + "/" + Platform + "/"; } } //bool isBuild = false; //static bool isZs = false; //static string[] versionArr = new string[15]; //static int verIndex = 0; //static string curProjectDir; //static string m_ExcelPath; //static string[] excelArr; //static int excelIndex=0; //打包数据 [MenuItem("自动化打包/一键导出")] private static void EzBuildPack() { benchName = GitUtil.GetCurBenchName(); UnityEngine.Debug.Log("当前分支:" + benchName); //创建窗口 Rect wr = new Rect(0, 0, 500, 1000); var buildWin = GetWindowWithRect(wr, true); buildWin.titleContent = new GUIContent("打包工具"); buildWin.Show(); } //[MenuItem("自动化打包/一键导出2")] //private static void EzBuildPack2() //{ // //创建窗口 // string[] ss = ProcessUtil.OpenFileWin(); // foreach(string s in ss) // { // Debug.Log(s); // } //} private void OnGUI() { EditorGUILayout.BeginVertical(); EditorGUILayout.Space(); EditorGUILayout.Space(); //EditorGUILayout.LabelField(""); MomPackPath = EditorGUILayout.TextField("母包工程地址:", MomPackPath); if (GUILayout.Button("Browse", GUILayout.ExpandWidth(false))) { MomPackPath = EditorUtility.OpenFolderPanel("Resource path", MomPackPath, MomPackPath); EditorPrefs.SetString("MomPackPath", MomPackPath); } EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.LabelField("请选择要打的包:"); for(int i = 0; i < PackConfig.Count; i++) { if (PackConfig[i].bench.Equals(benchName)) { EditorGUILayout.BeginVertical(); Chooser[i] = EditorGUILayout.ToggleLeft(PackConfig[i].name, Chooser[i]); if (Chooser[i]) { EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("编辑Config", GUILayout.Height(20f))) { string tpath = ClientConfigManager.Instance.GetClientConfigPath() + "/Version/" + PackConfig[i].version + "/" + ConfigFileName; GameEditor.Util.ProcessUtil.OpenText(tpath); } if (GUILayout.Button("编辑Version", GUILayout.Height(20f))) { string tpath = ClientConfigManager.Instance.GetClientConfigPath() + "/Version/" + PackConfig[i].version + "/" + VersionFileName; GameEditor.Util.ProcessUtil.OpenText(tpath); } if (GameLogic.AppConst.PlatformPath.Equals("Android")) { if (GUILayout.Button("编辑Gradle", GUILayout.Height(20f))) { string tpath = _MomPackPath + PackConfig[i].project + "/build.gradle"; GameEditor.Util.ProcessUtil.OpenText(tpath); } if (GUILayout.Button("更新蓝鲸SDK", GUILayout.Height(20f))) { File.Copy(_MomPackPath + "BlueWhaleJar/app/build/outputs/aar/app-release.aar", _MomPackPath + PackConfig[i].project + "/libs/BlueWhale.aar", true); Debug.Log("更新完成"); } } else { if (GUILayout.Button("同步配置文件", GUILayout.Height(20f))) { ReplaceConfigAndVersion(i); } if (GUILayout.Button("开始混淆", GUILayout.Height(20f))) { EncryptAB(i); } } EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); EditorGUILayout.Space(); EditorGUILayout.Space(); } } ExportType = EditorGUILayout.Popup("请选择出包方式", ExportType, ExportTypeList); EditorGUILayout.Space(); CommitToGit = EditorGUILayout.ToggleLeft("是否要提交到Git", CommitToGit); EditorGUILayout.Space(); if (GUILayout.Button("开始", GUILayout.Height(40f))) { StartExport(); } } public static void StartExport() { if (MomPackPath.Equals("")) { EditorUtility.DisplayDialog("提示", "母包工程地址错误", "确定"); return; } bool check_result = false; for (int i = 0; i < Chooser.Length; i++) { if (!Chooser[i]) continue; string sceneFilePath = ScenePath + PackConfig[i].scene; if (!File.Exists(sceneFilePath + ".unity")) { Debug.LogError(PackConfig[i].name + " 未找到场景:" + sceneFilePath); check_result = true; } string momPath = _MomPackPath + PackConfig[i].project; if (!Directory.Exists(momPath)) { Debug.LogError(PackConfig[i].name + " 未找到母包:" + momPath); check_result = true; } } if (check_result) { EditorUtility.DisplayDialog("提示", "包路径错误", "确定"); return; } // 开始导出 for (int i = 0; i < Chooser.Length; i++) { if (!Chooser[i]) continue; switch (ExportType) { case 0: // 导出工程 ExportAS(i); ReplaceFromProject(i); ReplaceConfigAndVersion(i); //EncryptAB(i); GitUpdate(i); CreateLogFile(i); StartGradleBuild(i); GitCommit(i); break; case 1: // 只替换AB ReplaceFromAB(i); ReplaceConfigAndVersion(i); //EncryptAB(i); GitUpdate(i); CreateLogFile(i); StartGradleBuild(i); GitCommit(i); break; case 2: // 只重新打包 ReplaceConfigAndVersion(i); GitUpdate(i); CreateLogFile(i); StartGradleBuild(i); GitCommit(i); break; } } } public static void CreateLogFile(int index) { APKPath = _MomPackPath + PackConfig[index].project + "/APK/"; if (!Directory.Exists(APKPath)) { Directory.CreateDirectory(APKPath); } PackTime = DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss"); APKPath += PackTime; if (!Directory.Exists(APKPath)) { Directory.CreateDirectory(APKPath); } } // 导出android 工程 public static void ExportAS(int index) { string pName = PackConfig[index].scene + "__" + PackConfig[index].project; PlayerSettings.productName = pName; PlayerSettings.Android.useAPKExpansionFiles = isObb; if (isObb) { pName += "__obb"; } if (!Directory.Exists(ExportPackPath)) { Directory.CreateDirectory(ExportPackPath); } if (Directory.Exists(ExportPackPath + "/" + pName)) { Directory.Delete(ExportPackPath + "/" + pName, true); } EditorUserBuildSettings.exportAsGoogleAndroidProject = true; EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle; // 设置需要打包的场景 string launchScene = "Assets/LuaFramework/Scenes/" + PackConfig[index].scene + ".unity"; Debug.Log(PackConfig[index].name + ":打包场景:" + launchScene); BuildPlayerOptions bpo = new BuildPlayerOptions(); bpo.locationPathName = ExportPackPath; bpo.options = BuildOptions.None; //bpo.options |= BuildOptions.AcceptExternalModificationsToPlayer; bpo.scenes = new[] { launchScene }; bpo.target = BuildTarget.Android; // 调用开始打包 BuildPipeline.BuildPlayer(bpo); Debug.Log(PackConfig[index].name + ":android工程导出路径" + ExportPackPath + "/" + pName); Debug.Log(PackConfig[index].name + ":android工程导出完成"); } static string[] ReplaceDir = new string[] { "/src/main/assets/Android", "/src/main/assets/bin" }; static string[] CopyDir = new string[] { "/src/main/jniLibs" }; // 从工程中替换 private static void ReplaceFromProject(int index) { string fromPath = ExportPackPath + "/" + PackConfig[index].scene + "__" + PackConfig[index].project; string toPath = _MomPackPath + PackConfig[index].project; for (int i = 0; i < ReplaceDir.Length; i++) { string dir = ReplaceDir[i]; string to = toPath + dir; GameCore.FileUtils.ReplaceDir(fromPath + dir, to, (string dirName, string fileName, float progress)=> { EditorUtility.DisplayProgressBar("正在复制:"+ dirName, fileName, progress); }); EditorUtility.ClearProgressBar(); } for (int i = 0; i < CopyDir.Length; i++) { string dir = CopyDir[i]; string to = toPath + dir; GameCore.FileUtils.CopyDir(fromPath + dir, to, (string dirName, string fileName, float progress) => { EditorUtility.DisplayProgressBar("正在复制:" + dirName, fileName, progress); }); EditorUtility.ClearProgressBar(); } Debug.Log(PackConfig[index].name + ":母包工程资源替换完成"); // 替换build-id EditorUtility.DisplayProgressBar("重写AndroidManifest", "", 0.5f); RewriteManifest(fromPath + "/src/main/AndroidManifest.xml", toPath + "/src/main/AndroidManifest.xml"); Debug.Log(PackConfig[index].name + ":母包Manifest修改完成"); EditorUtility.ClearProgressBar(); } private static void RewriteManifest(string f, string t) { // 找到要替换的内容 string[] flines = File.ReadAllLines(f, System.Text.Encoding.UTF8); string rpl = ""; for (int fi = 0; fi < flines.Length; fi++) { if (flines[fi].Contains("unity.build-id")) { rpl = flines[fi]; break; } } // 判断是否正确 if (rpl.Equals("")) { return; } // 替换到母包中 string[] tlines = File.ReadAllLines(t, System.Text.Encoding.UTF8); string[] wlines = new string[tlines.Length - 1]; string lastLine = ""; for (int ti = 0; ti < tlines.Length; ti++) { if (tlines[ti].Contains("unity.build-id")) { tlines[ti] = rpl; } if (ti == tlines.Length - 1) { lastLine = tlines[ti]; } else { wlines[ti] = tlines[ti]; } } File.WriteAllLines(t, wlines, System.Text.Encoding.UTF8); File.AppendAllText(t, lastLine, System.Text.Encoding.UTF8); } // 从AB包替换 private static void ReplaceFromAB(int index) { string toPath = _MomPackPath + PackConfig[index].project + "/src/main/assets/Android"; if (Directory.Exists(toPath)) Directory.Delete(toPath, true); Directory.CreateDirectory(toPath); GameCore.FileUtils.ReplaceDir(ABPath, toPath, (string dirName, string fileName, float progress) => { EditorUtility.DisplayProgressBar("正在复制:" + dirName, fileName, progress); }); EditorUtility.ClearProgressBar(); Debug.Log(PackConfig[index].name + ":替换AB包完成"); } // 加密AB包 private static void EncryptAB(int index) { string toPath = _MomPackPath + PackConfig[index].project + "/src/main/assets/Android"; if (GameLogic.AppConst.PlatformPath.Equals("IOS")) { toPath = _MomPackPath + PackConfig[index].project + "/Data/Raw/IOS"; } string json = File.ReadAllText(toPath + "/"+ VersionFileName); VersionTxt version = JsonUtility.FromJson(json); if (version.EncyptKey != null && version.EncyptKey != "") { string[] pathList = Directory.GetFiles(toPath, "*.unity3d", SearchOption.AllDirectories); float i = 0f; Debug.Log("文件数量;" + pathList.Length); foreach (string path in pathList) { GameLogic.MEncyptUtil.EncyptAB(path, version.EncyptKey); EditorUtility.DisplayProgressBar("正在加密:", path, i++ / pathList.Length); } EditorUtility.ClearProgressBar(); Debug.Log(PackConfig[index].name + ":加密AB包完成"); } else { Debug.Log(PackConfig[index].name + ":无需加密"); } } // 替换配置文件 private static void ReplaceConfigAndVersion(int index) { if (GameLogic.AppConst.PlatformPath.Equals("Android")) { //EditorUtility.DisplayProgressBar("替换配置文件1", "", 0.5f); string fromPath = ClientConfigManager.Instance.GetClientConfigPath() + "/Version/" + PackConfig[index].version + "/"; string toPath = _MomPackPath + PackConfig[index].project + "/Config/"; File.Copy(fromPath + ConfigFileName, toPath + ConfigFileName, true); File.Copy(fromPath + VersionFileName, toPath + VersionFileName, true); //EditorUtility.DisplayProgressBar("替换配置文件2", "", 0.5f); fromPath = toPath; toPath = _MomPackPath + PackConfig[index].project + "/src/main/assets/Android/"; File.Copy(fromPath + ConfigFileName, toPath + ConfigFileName, true); File.Copy(fromPath + VersionFileName, toPath + VersionFileName, true); } else { //EditorUtility.DisplayProgressBar("替换配置文件", "", 0.5f); string fromPath = ClientConfigManager.Instance.GetClientConfigPath() + "/Version/" + PackConfig[index].version + "/"; string toPath = _MomPackPath + PackConfig[index].project + "/Data/Raw/IOS/"; File.Copy(fromPath + ConfigFileName, toPath + ConfigFileName, true); File.Copy(fromPath + VersionFileName, toPath + VersionFileName, true); } Debug.Log(PackConfig[index].name+":配置文件替换完成"); EditorUtility.ClearProgressBar(); } // 开始生成apk private static void StartGradleBuild(int index) { EditorUtility.DisplayProgressBar("正在生成APK", "", 0f); GameEditor.Util.ProcessUtil.ProcessCommand(_MomPackPath + PackConfig[index].project, "gradlew assembleRelease>>" + APKPath + "/_log.txt"); EditorUtility.DisplayProgressBar("正在导出APK", "", 1f); string versionStr = GetAPKVersionStr(PackConfig[index].project); string apkFilePath = _MomPackPath + PackConfig[index].project + "/build/outputs/apk/release/" + PackConfig[index].project + "-release.apk"; if (File.Exists(apkFilePath)) { File.Copy(apkFilePath, APKPath + "/" + PackConfig[index].name +"_" + versionStr + "_" + PackTime + ".apk"); } Debug.Log(PackConfig[index].name + ":打包完成"); EditorUtility.ClearProgressBar(); } private static string GetAPKVersionStr(string folder) { string tpath = _MomPackPath + folder + "/build.gradle"; string[] lines = File.ReadAllLines(tpath); string versionCode = ""; string versionName = ""; string applicationId = ""; foreach (string l in lines) { string lt = l.Trim(); if (lt.StartsWith("versionCode")) { versionCode = lt.Split(' ')[1]; }else if (lt.StartsWith("versionName")) { versionName = lt.Split('\'')[1]; } else if (lt.StartsWith("applicationId")) { applicationId = lt.Split('\'')[1]; } } return string.Format("{0}_{1}({2})", applicationId, versionName, versionCode); } private static void GitUpdate(int index) { EditorUtility.DisplayProgressBar("正在更新母包", "", 0f); ProcessUtil.ProcessCommand(_MomPackPath, "git pull>>" + APKPath + "/_log.txt"); EditorUtility.ClearProgressBar(); } private static void GitCommit(int index) { if (CommitToGit) { string versionStr = GetAPKVersionStr(PackConfig[index].project); EditorUtility.DisplayProgressBar("正在提交修改", "", 0f); string printlog = ">>" + APKPath + "/_log.txt"; string[] commands = new string[]{ "echo git add ." + printlog, "git add ." + printlog, "echo git commit -m 'AutoPack:" + PackConfig[index].name +"_" + versionStr + "_" + PackTime + ".apk'" + printlog, "git commit -m 'AutoPack:" + PackConfig[index].name +"_" + versionStr + "_" + PackTime + ".apk'" + printlog, "git push", }; ProcessUtil.ProcessCommand(_MomPackPath + PackConfig[index].project, commands); EditorUtility.ClearProgressBar(); } } //private static void ExportXcode(string _sceneName) //{ // PlayerSettings.productName = "太初行"; // string mainXcodePath = // isZs? "/Volumes/ELEMENTS/JieLing/Packager/IOS/MHT_HW_RELEASE": "/Volumes/ELEMENTS/JieLing/Packager/IOS/MHT_HW_TEST"; // string outPath = isZs?"/Volumes/ELEMENTS/JieLing/Packager/IOS/exXcodePro_Release":"/Volumes/ELEMENTS/JieLing/Packager/IOS/exXcodePro_Test"; // if (Directory.Exists(outPath)) // { // Directory.Delete(outPath, true); // } // // 设置需要打包的场景 // string launchScene = _sceneName; // Debug.Log("打包场景:" + launchScene); // BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions(); // buildPlayerOptions.locationPathName = outPath; // buildPlayerOptions.options = BuildOptions.None; // buildPlayerOptions.options |= BuildOptions.AcceptExternalModificationsToPlayer; // buildPlayerOptions.scenes = new[] { launchScene }; // buildPlayerOptions.target = BuildTarget.iOS; // // 调用开始打包 // BuildPipeline.BuildPlayer(buildPlayerOptions); // Debug.Log("打包完成"); // Debug.Log("导出工程路径:"+ outPath); // if (Directory.Exists(mainXcodePath)&& Directory.Exists(outPath)) // { // Debug.Log("替换xcode资源"); // Directory.Delete(mainXcodePath+"/Data", true); // Directory.Move(outPath+"/Data",mainXcodePath+"/Data"); // Directory.Delete(mainXcodePath+"/Classes/Native", true); // Directory.Move(outPath+"/Classes/Native",mainXcodePath+"/Classes/Native"); // } //} }