using CaoCao.XAsset; using System; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEditor.Build; using UnityEditor.Build.Reporting; using UnityEngine; namespace CaoCao.Editor { public class BuildPlayerAssets : IPreprocessBuildWithReport, IPostprocessBuildWithReport { //打包后自动调用 public void OnPostprocessBuild(BuildReport report) { var dataPath = $"{Application.streamingAssetsPath}/{Assets.Bundles}"; if (!Directory.Exists(dataPath)) return; FileUtil.DeleteFileOrDirectory(dataPath); FileUtil.DeleteFileOrDirectory(dataPath + ".meta"); if (Directory.GetFiles(Application.streamingAssetsPath).Length != 0) return; FileUtil.DeleteFileOrDirectory(Application.streamingAssetsPath); FileUtil.DeleteFileOrDirectory(Application.streamingAssetsPath + ".meta"); } public int callbackOrder { get; } //打包前自动调用 public void OnPreprocessBuild(BuildReport report) { StartNew(); } public static Action CustomBuilder { get; set; } private Versions versions { get; set; } public static void StartNew(Versions versions = null) { new BuildPlayerAssets {versions = versions}.Start(); } private void Start() { //从BuildCache中读取versions.json if (versions == null) versions = Settings.GetDefaultVersions(); if (CustomBuilder != null) { CustomBuilder.Invoke(this); return; } var dataPath = $"{Application.streamingAssetsPath}/{Assets.Bundles}"; var settings = Settings.GetDefaultSettings(); if (Settings.Platform == Platform.iOS) { // iOS 下散文件 IO 效率更高 settings.packPlayerAssets = false; } var playerAssets = settings.GetPlayerAssets(); if (Directory.Exists(dataPath)) { FileUtil.DeleteFileOrDirectory(dataPath); FileUtil.DeleteFileOrDirectory($"{dataPath}.meta"); } //根据versions获取到设置为交付模式为Install Time的bundle包 var bundles = Builder.GetBundlesInBuild(settings, versions); if (bundles.Length > 0) CopyBundles(bundles, playerAssets, settings.bundle.encryption ? XAsset.Utility.WriteOffset : 0); // 保存版本文件 foreach (var version in versions.data) { ////分包版本文件不加入包中 //if (version.subPackage) // continue; var from = Settings.GetDataPath(version.file); var to = Assets.GetPlayerDataPath(version.file); XAsset.Utility.CreateDirectoryIfNecessary(to); File.Copy(from, to, true); } // WebGL 不需要搞 PlayerAssets。 if (Settings.Platform == Platform.WebGL) playerAssets.data.Clear(); var json = JsonUtility.ToJson(playerAssets); // 将playerassets.json文件写入streamingAssetsPath文件夹 var path = Assets.GetPlayerDataPath(PlayerAssets.Filename); XAsset.Utility.CreateDirectoryIfNecessary(path); File.WriteAllText(path, json); // 将version.json文件写入streamingAssetsPath文件夹 path = Assets.GetPlayerDataPath(Versions.Filename); XAsset.Utility.CreateDirectoryIfNecessary(path); versions.Save(path); } //TODO:带修改,加密 private static void CopyBundles(IEnumerable bundles, PlayerAssets playerAssets, ulong offset = 0) { bool bXor = false; if (!playerAssets.packed) { foreach (var bundle in bundles) { bXor = false; var from = Settings.GetDataPath(bundle.file); var to = Assets.GetPlayerDataPath(bundle.file); var file = new FileInfo(from); if (file.Exists) { #if ENABLE_NEWENCRY //@取消贴图加密 //不加密 XAsset.Utility.CreateDirectoryIfNecessary(to); file.CopyTo(to, true); playerAssets.data.Add(PackedAsset.Create(bundle, offset)); #else if (bundle.file.Contains("1_texture")) bXor = true; if (!bXor) { XAsset.Utility.CreateDirectoryIfNecessary(to); file.CopyTo(to, true); playerAssets.data.Add(PackedAsset.Create(bundle, offset)); } else { //把以加密的数据解密回来 using (var writer = new BinaryWriter(File.OpenWrite(to))) { var stream = File.OpenRead(from); using var reader = new BinaryReader(stream); string hash = reader.ReadString(); byte[] hashBytes = System.Text.Encoding.UTF8.GetBytes(hash); //读取剩余数据 ulong len = (ulong)stream.Length - offset; var bytes = reader.ReadBytes((int)len); XAsset.Utility.GetSelfXorBytes(bytes, hashBytes); writer.Write(hash); writer.Write(bytes); reader.Close(); } } #endif } else { XAsset.Logger.E($"File not found: {from}"); } } } else { var path = Assets.GetPlayerDataPath(playerAssets.GetAssetName()); if (File.Exists(path)) { File.Delete(path); } XAsset.Utility.CreateDirectoryIfNecessary(path); using (var writer = new BinaryWriter(File.OpenWrite(path))) { foreach (var bundle in bundles) { bXor = false; var from = Settings.GetDataPath(bundle.file); var file = new FileInfo(from); if (file.Exists) { #if ENABLE_NEWENCRY //@取消贴图加密 playerAssets.data.Add(PackedAsset.Create(bundle, (ulong)writer.BaseStream.Position + offset)); writer.Write(File.ReadAllBytes(from)); #else if (bundle.file.Contains("1_texture")) bXor = true; if (!bXor) { playerAssets.data.Add(PackedAsset.Create(bundle, (ulong)writer.BaseStream.Position + offset)); writer.Write(File.ReadAllBytes(from)); } else { // 安卓下,StreamingAssets内文件不支持C#的IO // 所以把以加密的数据解密回来 playerAssets.data.Add(PackedAsset.Create(bundle, (ulong)writer.BaseStream.Position + offset)); var stream = File.OpenRead(from); using var reader = new BinaryReader(stream); string hash = reader.ReadString(); byte[] hashBytes = System.Text.Encoding.UTF8.GetBytes(hash); //读取剩余数据 ulong len = (ulong)stream.Length - offset; var bytes = reader.ReadBytes((int)len); XAsset.Utility.GetSelfXorBytes(bytes, hashBytes); writer.Write(hash); writer.Write(bytes); reader.Close(); } #endif } else { XAsset.Logger.E($"File not found: {from}"); } } } } #if ENABLE_NEWENCRY //@取消贴图加密 Debug.Log("是“取消贴图加密”模式"); #else Debug.Log("旧模式,非“取消贴图加密”模式"); #endif } } }