/// <summary> /// 获取改动的Assets /// </summary> public BuildingAssetInfos GetChangedAssets(BuildingAssetInfos newBuildingAssetInfos, BuildTarget buildTarget) { Debug.Log("<color=red>【增量资源】开始变动资源分析...</color>"); BuildingAssetInfos lastBuildingAssetInfos = null; var buildinfoPath = IPath.Combine(this.BuildParams.OutputPath, BApplication.GetPlatformPath(buildTarget), BResources.EDITOR_ART_ASSET_BUILD_INFO_PATH); Debug.Log("旧资源地址:" + buildinfoPath); if (File.Exists(buildinfoPath)) { var configContent = File.ReadAllText(buildinfoPath); lastBuildingAssetInfos = JsonMapper.ToObject <BuildingAssetInfos>(configContent); } //根据变动的list 刷出关联 //I.单ab 单资源,直接重打 //II.单ab 多资源的 整个ab都要重新打包 if (lastBuildingAssetInfos != null && lastBuildingAssetInfos.AssetInfoMap.Count != 0) { #region 文件改动 var changedAssetList = new List <KeyValuePair <string, BuildingAssetInfos.AssetInfo> >(); var changedAssetNameList = new List <string>(); //1.找出差异文件:不一致 或者没有 foreach (var newAssetItem in newBuildingAssetInfos.AssetInfoMap) { if (lastBuildingAssetInfos.AssetInfoMap.TryGetValue(newAssetItem.Key, out var lastAssetItem)) { //文件hash相同 if (lastAssetItem.Hash == newAssetItem.Value.Hash) { //依赖完全相同 var except = lastAssetItem.DependAssetList.Except(newAssetItem.Value.DependAssetList); if (except.Count() == 0) { continue; } } } changedAssetList.Add(newAssetItem); } Debug.LogFormat("<color=red>【增量资源】变动文件数:{0}</color>", changedAssetList.Count); var changedAssetContentFiles = new List <string>(); foreach (var item in changedAssetList) { changedAssetContentFiles.Add(item.Key + " - " + item.Value.Hash); } Debug.Log(JsonMapper.ToJson(changedAssetContentFiles, true)); #endregion #region ABName修改、颗粒度修改 //abName修改会导致引用该ab的所有资源重新构建 才能保证正常引用关系 上线项目尽量不要有ab修改的情况 var changedAssetBundleAssetList = new List <KeyValuePair <string, BuildingAssetInfos.AssetInfo> >(); //AB颗粒度 var lastABUnitMap = lastBuildingAssetInfos.PreviewAssetbundleUnit(); var newABUnitMap = newBuildingAssetInfos.PreviewAssetbundleUnit(); //遍历处理 foreach (var newAssetItem in newBuildingAssetInfos.AssetInfoMap) { if (lastBuildingAssetInfos.AssetInfoMap.TryGetValue(newAssetItem.Key, out var lastAssetItem)) { //AB名修改 if (lastAssetItem.ABName != newAssetItem.Value.ABName) { changedAssetBundleAssetList.Add(newAssetItem); } //AB 颗粒度修改 else { var lastABUnit = lastABUnitMap[lastAssetItem.ABName]; var newABUnit = newABUnitMap[newAssetItem.Value.ABName]; //颗粒度修改 var except = lastABUnit.Except(newABUnit); //差集 if (except.Count() != 0) { changedAssetBundleAssetList.Add(newAssetItem); } } } } Debug.LogFormat("<color=red>【增量资源】修改ABName(颗粒度) 文件数:{0}</color>", changedAssetBundleAssetList.Count); var changeABNameFiles = new List <string>(); foreach (var item in changedAssetBundleAssetList) { changeABNameFiles.Add(item.Key); } Debug.Log(JsonMapper.ToJson(changeABNameFiles, true)); //引用该资源的也要重打,以保证AB正确的引用关系 var changedCount = changedAssetBundleAssetList.Count; for (int i = 0; i < changedCount; i++) { var asset = changedAssetBundleAssetList[i]; var abname = asset.Value.ABName; foreach (var item in newBuildingAssetInfos.AssetInfoMap) { if (item.Value.DependAssetList.Contains(abname)) { changedAssetBundleAssetList.Add(item); } } } changedAssetBundleAssetList = changedAssetBundleAssetList.Distinct().ToList(); //log Debug.LogFormat("<color=red>【增量资源】修改ABName(颗粒度)影响文件数:{0},{1}</color>", changedAssetBundleAssetList.Count, "线上修改谨慎!"); changeABNameFiles = new List <string>(); foreach (var item in changedAssetBundleAssetList) { changeABNameFiles.Add(item.Key); } #endregion //合并 changedAssetList.AddRange(changedAssetBundleAssetList); //2.依赖资源也要重新打,不然会在这次导出过程中unity默认会把依赖和该资源打到一个ab中 foreach (var changedAsset in changedAssetList) { //1.添加自身的ab changedAssetNameList.Add(changedAsset.Value.ABName); //2.添加所有依赖的ab changedAssetNameList.AddRange(changedAsset.Value.DependAssetList); } changedAssetNameList = changedAssetNameList.Distinct().ToList(); //3.搜索相同的ab name的资源,都要重新打包 var count = changedAssetNameList.Count; for (int i = 0; i < count; i++) { var rebuildABName = changedAssetNameList[i]; var theSameABNameAssets = newBuildingAssetInfos.AssetInfoMap.Where((asset) => asset.Value.ABName == rebuildABName); if (theSameABNameAssets != null) { foreach (var mainAssetItem in theSameABNameAssets) { //添加资源本体 changedAssetNameList.Add(mainAssetItem.Value.ABName); //添加影响的依赖文件 changedAssetNameList.AddRange(mainAssetItem.Value.DependAssetList); } } } changedAssetNameList = changedAssetNameList.Distinct().ToList(); //4.根据影响的ab,寻找出所有文件 var allRebuildAssets = new List <KeyValuePair <string, BuildingAssetInfos.AssetInfo> >(); foreach (var abname in changedAssetNameList) { var findAssets = newBuildingAssetInfos.AssetInfoMap.Where((asset) => asset.Value.ABName == abname); allRebuildAssets.AddRange(findAssets); } //去重 var changedBuildInfo = new BuildingAssetInfos(); foreach (var kv in allRebuildAssets) { changedBuildInfo.AssetInfoMap[kv.Key] = kv.Value; } Debug.LogFormat("<color=red>【增量资源】总重打资源数:{0}</color>", changedBuildInfo.AssetInfoMap.Count); var changedFiles = new List <string>(); foreach (var item in changedBuildInfo.AssetInfoMap) { changedFiles.Add(item.Key); } Debug.Log(JsonMapper.ToJson(changedFiles, true)); var ablist = changedBuildInfo.AssetInfoMap.Values.Select((a) => a.ABName).Distinct().ToList(); Debug.LogFormat("<color=red>【增量资源】变动Assetbundle:{0}</color>", ablist.Count); Debug.Log(JsonMapper.ToJson(ablist, true)); return(changedBuildInfo); } else { Debug.Log("<color=yellow>【增量资源】本地无资源,全部重打!</color>"); } return(newBuildingAssetInfos); }
/// <summary> /// 开始构建AB /// </summary> public void StartBuildAssetBundle(BuildTarget buildTarget) { //-----------------------开始打包AssetBundle逻辑--------------------------- Debug.Log("【BuildAssetbundle】执行Build..."); //设置编辑器状态 BDEditorApplication.EditorStatus = BDFrameworkEditorStatus.BuildAssetBundle; var platform = BApplication.GetRuntimePlatform(buildTarget); var platformOutputPath = IPath.Combine(BuildParams.OutputPath, BApplication.GetPlatformPath(platform)); string abOutputPath = IPath.Combine(platformOutputPath, BResources.ART_ASSET_ROOT_PATH); //--------------------------------开始打包---------------------------------- //1.打包 Debug.Log("<color=green>----->1.进入打包逻辑</color>"); //整理abname this.MergeABName(BuildingAssetInfos); //对比差异文件 var changedAssetsInfo = GetChangedAssets(BuildingAssetInfos, buildTarget); //生成artconfig var assetbundleItemList = this.GenAssetBundleConfig(BuildingAssetInfos, BuildParams, platform); //打包 AssetDatabase.StartAssetEditing(); //禁止自动导入 { this.BuildAssetBundle(assetbundleItemList, changedAssetsInfo, BuildParams, platform); } AssetDatabase.StopAssetEditing(); //恢复自动导入 //2.清理 Debug.Log("<color=green>----->2.清理旧ab</color>"); //移除所有的ab RemoveAllAssetbundleName(); //删除本地没有的资源 var allABList = Directory.GetFiles(abOutputPath, "*", SearchOption.AllDirectories).Where((p) => string.IsNullOrEmpty(Path.GetExtension(p))); foreach (var abpath in allABList) { var abname = Path.GetFileName(abpath); var ret = assetbundleItemList.FirstOrDefault((abdata) => abdata.AssetBundlePath == abname); if (ret == null) { // File.Delete(abpath); File.Delete(abpath + ".manifest"); // var path = AssetDatabase.GUIDToAssetPath(abname); Debug.Log("【删除旧ab:】" + abname + " - " + path); } } //3.BuildInfo配置处理 Debug.Log("<color=green>----->3.BuildInfo相关生成</color>"); //设置ab的hash foreach (var abi in assetbundleItemList) { if (string.IsNullOrEmpty(abi.AssetBundlePath)) { continue; } var abpath = IPath.Combine(platformOutputPath, BResources.ART_ASSET_ROOT_PATH, abi.AssetBundlePath); var hash = FileHelper.GetMurmurHash3(abpath); abi.Hash = hash; } //获取上一次打包的数据,跟这次打包数据合并 var configPath = IPath.Combine(platformOutputPath, BResources.ART_ASSET_CONFIG_PATH); if (File.Exists(configPath)) { var lastAssetbundleItemList = CsvSerializer.DeserializeFromString <List <AssetBundleItem> >(File.ReadAllText(configPath)); foreach (var newABI in assetbundleItemList) { if (string.IsNullOrEmpty(newABI.AssetBundlePath)) { continue; } // //判断是否在当前打包列表中 // var ret = changedAssetsInfo.AssetDataMaps.Values.FirstOrDefault((a) => a.ABName.Equals(newABI.AssetBundlePath, StringComparison.OrdinalIgnoreCase)); var lastABI = lastAssetbundleItemList.FirstOrDefault((last) => newABI.AssetBundlePath.Equals(last.AssetBundlePath, StringComparison.OrdinalIgnoreCase)); //AB名相等 //&& newABI.Hash == last.Hash); //hash相等 //没重新打包,则用上一次的mix信息 if (lastABI != null && lastABI.Hash == newABI.Hash) { newABI.Mix = lastABI.Mix; } //否则mix = 0 } } //保存artconfig.info var csv = CsvSerializer.SerializeToString(assetbundleItemList); FileHelper.WriteAllText(configPath, csv); //保存BuildInfo配置 var buildinfoPath = IPath.Combine(platformOutputPath, BResources.EDITOR_ART_ASSET_BUILD_INFO_PATH); //缓存buildinfo var json = JsonMapper.ToJson(BuildingAssetInfos, true); FileHelper.WriteAllText(buildinfoPath, json); //4.备份Artifacts //this.BackupArtifacts(buildTarget); //5.检测本地的Manifest和构建预期对比 Debug.Log("<color=green>----->5.校验AB依赖</color>"); var abRootPath = IPath.Combine(BuildParams.OutputPath, BApplication.GetPlatformPath(platform), BResources.ART_ASSET_ROOT_PATH); var previewABUnitMap = BuildingAssetInfos.PreviewAssetbundleUnit(); var manifestList = Directory.GetFiles(abRootPath, "*.manifest", SearchOption.AllDirectories); //解析 manifestBuildParams.OutputPath for (int i = 0; i < manifestList.Length; i++) { var manifest = manifestList[i].Replace("\\", "/"); if (manifest.Equals(abRootPath + ".manifest")) { continue; } var lines = File.ReadLines(manifest); List <string> manifestDependList = new List <string>(); bool isStartRead = false; foreach (var line in lines) { if (!isStartRead && line.Equals("Assets:")) { isStartRead = true; } else if (line.Contains("Dependencies:")) { break; } else if (isStartRead) { var file = line.Replace("- ", ""); manifestDependList.Add(file.ToLower()); } } //对比依赖 var abname = Path.GetFileNameWithoutExtension(manifest); if (abname.Equals(BResources.ART_ASSET_ROOT_PATH, StringComparison.OrdinalIgnoreCase)) { continue; } previewABUnitMap.TryGetValue(abname, out var previewABDependList); if (previewABDependList == null) { Debug.LogError("【AssetbundleV2-验证】本地ab的配置不不存在:" + abname); Debug.LogError("path:" + AssetDatabase.GUIDToAssetPath(abname)); } else { //求差集 var except = manifestDependList.Except(previewABDependList); if (except.Count() != 0) { var local = JsonMapper.ToJson(manifestDependList, true); var preview = JsonMapper.ToJson(previewABDependList, true); Debug.LogError($"【AssetbundleV2-验证】本地AssetBundle依赖与预期不符:\n 本地:{local} \n 预期:{preview}"); } } } //6.资源混淆 Debug.Log("<color=green>----->6.混淆AB</color>"); if (BDEditorApplication.BDFrameworkEditorSetting.BuildAssetBundleSetting.IsEnableObfuscation) { AssetBundleEditorToolsV2.MixAssetBundle(BuildParams.OutputPath, platform); } //恢复编辑器状态 BDEditorApplication.EditorStatus = BDFrameworkEditorStatus.Idle; //BD生命周期触发 BDFrameworkPipelineHelper.OnEndBuildAssetBundle(this); //GenAssetBundleItemCacheList = abConfigList.ToList(); }