#if UNITY_ANDROID //using ICSharpCode.SharpZipLib.Zip; using System; using System.IO; using System.Text; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; namespace XGame.Editor.Build { public static class ObbUtil { public static void GenerateObb(string pathToBuiltProject) { var outputPath = Path.GetDirectoryName(pathToBuiltProject).Replace("\\", "/"); var obbRoot = $"{outputPath}/obb/"; var obbAssets = $"{obbRoot}assets"; //Debug.Log($"directory:{outputPath} obb:{obbRoot}"); if (!Directory.Exists(obbAssets)) { return; } string apkFolder = null; string manifestPath = null; if (EditorUserBuildSettings.exportAsGoogleAndroidProject) { manifestPath = $"{pathToBuiltProject}/unityLibrary/src/main/AndroidManifest.xml"; } else { //解压apk apkFolder = UnCompressApk(pathToBuiltProject); if (!string.IsNullOrEmpty(apkFolder)) { manifestPath = $"{apkFolder}/AndroidManifest.xml"; } } if (!string.IsNullOrEmpty(manifestPath)) { //取出Unity的build-id Regex regex = new Regex(@"", RegexOptions.Multiline); var manifest = File.ReadAllText(manifestPath); var match = regex.Match(manifest); if (match.Success) { BuildLog.Log($"unity.build-id:{match.Groups[1].Value}"); File.WriteAllText($"{obbAssets}/{match.Groups[1].Value}", "", Encoding.UTF8); } else { BuildLog.Error($"找不到unity.build-id ManifestPath:{manifestPath}"); return; } try { //生成新的obb var zip = $"{outputPath}/main.{PlayerSettings.Android.bundleVersionCode}.{PlayerSettings.applicationIdentifier}.obb"; ProcessCommand(SevenZipExePath, "-tZip a " + zip + " " + obbAssets + " -mx0"); //using (var zipFile = File.Create($"{outputPath}/main.{PlayerSettings.Android.bundleVersionCode}.{PlayerSettings.applicationIdentifier}.obb")) //{ // using (ZipOutputStream zipOutStream = new ZipOutputStream(zipFile)) // { // zipOutStream.SetLevel(0);// 0 - store only to 9 - means best compression // ZipCrc32 crc = new ZipCrc32(); // ZipDirectory(obbRoot, obbAssets, zipOutStream, crc); // } //} } catch (Exception ex) { BuildLog.Error("生成obb文件失败"); BuildLog.Exception(ex); } //删除obb文件夹 UnityEditor.FileUtil.DeleteFileOrDirectory(obbRoot); //删除解压的apk文件夹 if (!string.IsNullOrEmpty(apkFolder)) { UnityEditor.FileUtil.DeleteFileOrDirectory(apkFolder); } } } #region 解压apk //[MenuItem("Build/UnCompressApk")] //public static void _UnCompressApk() //{ // UnCompressApk("D:/WorkSpaces/XGameBuild/output/xbuild.apk"); //} private static string UnCompressApk(string apkPath) { var apkToolPath = ApkToolPath; if (string.IsNullOrEmpty(apkToolPath)) { BuildLog.Error("找不到Apktool!!!!!!!!!"); return string.Empty; } //apktool固定解压到工程主目录下 var apkFolder = Path.GetFullPath($"{Application.dataPath}/../{Path.GetFileNameWithoutExtension(apkPath)}").Replace("\\", "/"); //先删除旧文件夹 if (Directory.Exists(apkFolder)) { BuildLog.Log($"存在apk文件夹,先删除。Path:{apkFolder}"); UnityEditor.FileUtil.DeleteFileOrDirectory(apkFolder); } ProcessCommand("java.exe", "-jar " + apkToolPath + " d " + apkPath); return apkFolder; } private static readonly string _apktoolRelativePath = "Build/Editor/BuildPlayer/apktool/apktool.jar"; private static string ApkToolPath { get { var guids = AssetDatabase.FindAssets("apktool"); foreach (var guid in guids) { var assetPath = AssetDatabase.GUIDToAssetPath(guid); if (assetPath.EndsWith(_apktoolRelativePath)) { var path = Path.GetFullPath(assetPath).Replace("\\", "/"); BuildLog.Log($"ApkToolPath:{path}"); return path; } } return string.Empty; } } private static readonly string _zipExeRelativePath = "Build/Editor/BuildPlayer/7z/sevenZip.exe"; private static string SevenZipExePath { get { var guids = AssetDatabase.FindAssets("sevenZip"); foreach (var guid in guids) { var assetPath = AssetDatabase.GUIDToAssetPath(guid); if (assetPath.EndsWith(_zipExeRelativePath)) { var path = Path.GetFullPath(assetPath).Replace("\\", "/"); BuildLog.Log($"SevenZipExePath:{path}"); return path; } } return string.Empty; } } private static void ProcessCommand(string command, string argument, bool shell = true) { var start = new System.Diagnostics.ProcessStartInfo(command) { Arguments = argument, CreateNoWindow = false, ErrorDialog = true, UseShellExecute = true }; if (start.UseShellExecute) { start.RedirectStandardOutput = false; start.RedirectStandardError = false; start.RedirectStandardInput = false; } else { start.RedirectStandardOutput = true; start.RedirectStandardError = true; start.RedirectStandardInput = true; start.StandardOutputEncoding = Encoding.UTF8; start.StandardErrorEncoding = Encoding.UTF8; } var process = System.Diagnostics.Process.Start(start); if (!start.UseShellExecute) { BuildLog.Log(process.StandardOutput.ReadToEnd()); BuildLog.Error(process.StandardError.ReadToEnd()); } process.WaitForExit(); process.Close(); } #endregion #region 打包obb /// /// 递归遍历目录 /// //private static void ZipDirectory(string root, string directoryToZip, ZipOutputStream zipOutput, ZipCrc32 crc) //{ // var filenames = Directory.GetFileSystemEntries(directoryToZip); // foreach (string file in filenames)// 遍历所有的文件和目录 // { // if (Directory.Exists(file))// 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件 // { // ZipDirectory(root, file, zipOutput, crc); // } // else // 否则直接压缩文件 // { // //打开压缩文件 // using (FileStream fileStream = File.OpenRead(file)) // { // var buffer = new byte[fileStream.Length]; // fileStream.Read(buffer, 0, buffer.Length); // //string fileName = parentPath + file.Substring(file.LastIndexOf("\\") + 1); // var entry = new ZipEntry(file.Replace("\\", "/").Replace(root, "")) // { // DateTime = DateTime.Now, // Size = fileStream.Length // }; // fileStream.Close(); // crc.Reset(); // crc.Update(buffer); // entry.Crc = crc.Value; // zipOutput.PutNextEntry(entry); // zipOutput.Write(buffer, 0, buffer.Length); // } // } // } //} #endregion } } #endif