新建脚本,继承自BuildScriptPackedMode,添加特性菜单,生成资源,重写3个方法,把这3个方法复制过来,并修改源码方法为virtual。
Name方法,修改返回的名字,就是你Build看见的名字。
BuildDataImplementation 这里修改的主要是初始化BuildInData,创建Resources/Version目录,存放BuildInData序列化后内容,然后打进包里。
PostProcessBundles 这里修改的主要是,把Bundle生成的名字记录到BuildInData(为准确加载准备,Bundle名字为组名+hash,所以可以直接判断名字),把打出来的Bundle复制到Library(因为都设置为远程加载了),使其可以复制到StreamAssets目录打进包里。
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using UnityEditor.AddressableAssets.Build; using UnityEditor.AddressableAssets.Build.DataBuilders; using UnityEditor.AddressableAssets.Settings; using UnityEditor.AddressableAssets.Settings.GroupSchemas; using UnityEditor.Build.Pipeline.Interfaces; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets.Initialization; using UnityEngine.AddressableAssets.ResourceLocators; using UnityEngine.ResourceManagement.ResourceProviders; [CreateAssetMenu(fileName = "MyBuildScriptPackedMode.asset", menuName = "Addressable Assets/Data Builders/MyBuildScriptPackedMode")] public class MyBuildScriptPackedMode : BuildScriptPackedMode { public override string Name { get { return "My Build"; }//自定义Build的名字 } protected override TResult BuildDataImplementation<TResult>(AddressablesDataBuilderInput builderInput) { TResult result = default(TResult); var timer = new Stopwatch(); timer.Start(); InitializeBuildContext(builderInput, out AddressableAssetsBuildContext aaContext); using (m_Log.ScopedStep(LogLevel.Info, "ProcessAllGroups")) { var errorString = ProcessAllGroups(aaContext); if (!string.IsNullOrEmpty(errorString)) result = AddressableAssetBuildResult.CreateResult<TResult>(null, 0, errorString); } /////START 初始化buildInData AssetBundleManager.GetInstance().buildInData = new BuildInBundleData(); var targetDir = Path.Combine(Application.dataPath, "Resources"); if (!Directory.Exists(targetDir)) Directory.CreateDirectory(targetDir); targetDir = Path.Combine(targetDir, "Version"); if (!Directory.Exists(targetDir)) Directory.CreateDirectory(targetDir); var targetPath = Path.Combine(targetDir, "BuildInBundleName.bytes"); if (File.Exists(targetPath)) { File.Delete(targetPath); } /////END 初始化buildInData if (result == null) { result = DoBuild<TResult>(builderInput, aaContext); } if (result != null) result.Duration = timer.Elapsed.TotalSeconds; ////START 序列化保存本次打包的内置包列表 var BuildInJson = JsonUtility.ToJson(AssetBundleManager.GetInstance().buildInData); File.WriteAllText(targetPath, BuildInJson); ////END 序列化保存本次打包的内置包列表 return result; } public override void PostProcessBundles(AddressableAssetGroup assetGroup, List<string> buildBundles, List<string> outputBundles, IBundleBuildResults buildResult, ResourceManagerRuntimeData runtimeData, List<ContentCatalogDataEntry> locations, FileRegistry registry, Dictionary<string, ContentCatalogDataEntry> primaryKeyToCatalogEntry, Dictionary<string, string> bundleRenameMap, List<Action> postCatalogUpdateCallbacks) { var schema = assetGroup.GetSchema<BundledAssetGroupSchema>(); if (schema == null) return; var path = schema.BuildPath.GetValue(assetGroup.Settings); if (string.IsNullOrEmpty(path)) return; for (int i = 0; i < buildBundles.Count; ++i) { if (primaryKeyToCatalogEntry.TryGetValue(buildBundles[i], out ContentCatalogDataEntry dataEntry)) { var info = buildResult.BundleInfos[buildBundles[i]]; var requestOptions = new AssetBundleRequestOptions { Crc = schema.UseAssetBundleCrc ? info.Crc : 0, UseCrcForCachedBundle = schema.UseAssetBundleCrcForCachedBundles, UseUnityWebRequestForLocalBundles = schema.UseUnityWebRequestForLocalBundles, Hash = schema.UseAssetBundleCache ? info.Hash.ToString() : "", ChunkedTransfer = schema.ChunkedTransfer, RedirectLimit = schema.RedirectLimit, RetryCount = schema.RetryCount, Timeout = schema.Timeout, BundleName = Path.GetFileNameWithoutExtension(info.FileName), BundleSize = GetFileSize(info.FileName), ClearOtherCachedVersionsWhenLoaded = schema.AssetBundledCacheClearBehavior == BundledAssetGroupSchema.CacheClearBehavior.ClearWhenWhenNewVersionLoaded }; dataEntry.Data = requestOptions; int extensionLength = Path.GetExtension(outputBundles[i]).Length; string[] deconstructedBundleName = outputBundles[i].Substring(0, outputBundles[i].Length - extensionLength).Split('_'); string reconstructedBundleName = string.Join("_", deconstructedBundleName, 1, deconstructedBundleName.Length - 1) + ".bundle"; outputBundles[i] = ConstructAssetBundleName(assetGroup, schema, info, reconstructedBundleName); dataEntry.InternalId = dataEntry.InternalId.Remove(dataEntry.InternalId.Length - buildBundles[i].Length) + outputBundles[i]; dataEntry.Keys[0] = outputBundles[i]; ReplaceDependencyKeys(buildBundles[i], outputBundles[i], locations); if (!m_BundleToInternalId.ContainsKey(buildBundles[i])) m_BundleToInternalId.Add(buildBundles[i], dataEntry.InternalId); if (dataEntry.InternalId.StartsWith("http:\\")) dataEntry.InternalId = dataEntry.InternalId.Replace("http:\\", "http://").Replace("\\", "/"); if (dataEntry.InternalId.StartsWith("https:\\")) dataEntry.InternalId = dataEntry.InternalId.Replace("https:\\", "https://").Replace("\\", "/"); } else { UnityEngine.Debug.LogWarningFormat("Unable to find ContentCatalogDataEntry for bundle {0}.", outputBundles[i]); } UnityEngine.Debug.Log(outputBundles[i]); if (!AssetBundleManager.GetInstance().buildInData.BuildInBundleNames.Contains(outputBundles[i])) { //添加打包的Bundle记录,内置Bundle AssetBundleManager.GetInstance().buildInData.BuildInBundleNames.Add(outputBundles[i]); } var targetPath = Path.Combine(path, outputBundles[i]); var srcPath = Path.Combine(assetGroup.Settings.buildSettings.bundleBuildPath, buildBundles[i]); bundleRenameMap.Add(buildBundles[i], outputBundles[i]); CopyFileWithTimestampIfDifferent(srcPath, targetPath, m_Log); AddPostCatalogUpdatesInternal(assetGroup, postCatalogUpdateCallbacks, dataEntry, targetPath, registry); //复制到Library 打包到包里面 string RuntimePath = UnityEngine.AddressableAssets.Addressables.RuntimePath; string destPath = Path.Combine(System.Environment.CurrentDirectory, RuntimePath, PlatformMappingService.GetPlatformPathSubFolder().ToString(), outputBundles[i]); if (!Directory.Exists(Path.GetDirectoryName(destPath))) Directory.CreateDirectory(Path.GetDirectoryName(destPath)); if (!File.Exists(destPath)) { File.Copy(targetPath, destPath); } registry.AddFile(targetPath); } } }
设置应用自定义打包
对了,设置AddressableAssetSettings的PlayerVersionOverried为固定版本,打包出来的catalog就都为同一个,更新这个用来检测更新。