/// <summary> /// 获取改动的Assets /// </summary> public BuildAssetsInfo GetChangedAssets(BuildAssetsInfo newBuildAssetsInfo, BuildTarget buildTarget) { Debug.Log("<color=red>【增量资源】开始变动资源分析...</color>"); BuildAssetsInfo lastBuildAssetsInfo = 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); lastBuildAssetsInfo = JsonMapper.ToObject <BuildAssetsInfo>(configContent); } //根据变动的list 刷出关联 //I.单ab 单资源,直接重打 //II.单ab 多资源的 整个ab都要重新打包 if (lastBuildAssetsInfo != null && lastBuildAssetsInfo.AssetDataMaps.Count != 0) { #region 文件改动 var changedAssetList = new List <KeyValuePair <string, BuildAssetsInfo.BuildAssetData> >(); var changedAssetNameList = new List <string>(); //1.找出差异文件:不一致 或者没有 foreach (var newAssetItem in newBuildAssetsInfo.AssetDataMaps) { if (lastBuildAssetsInfo.AssetDataMaps.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, BuildAssetsInfo.BuildAssetData> >(); //AB颗粒度 var lastABUnitMap = lastBuildAssetsInfo.PreviewAssetbundleUnit(); var newABUnitMap = newBuildAssetsInfo.PreviewAssetbundleUnit(); //遍历处理 foreach (var newAssetItem in newBuildAssetsInfo.AssetDataMaps) { if (lastBuildAssetsInfo.AssetDataMaps.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 newBuildAssetsInfo.AssetDataMaps) { 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 = newBuildAssetsInfo.AssetDataMaps.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, BuildAssetsInfo.BuildAssetData> >(); foreach (var abname in changedAssetNameList) { var findAssets = newBuildAssetsInfo.AssetDataMaps.Where((asset) => asset.Value.ABName == abname); allRebuildAssets.AddRange(findAssets); } //去重 var changedBuildInfo = new BuildAssetsInfo(); foreach (var kv in allRebuildAssets) { changedBuildInfo.AssetDataMaps[kv.Key] = kv.Value; } Debug.LogFormat("<color=red>【增量资源】总重打资源数:{0}</color>", changedBuildInfo.AssetDataMaps.Count); var changedFiles = new List <string>(); foreach (var item in changedBuildInfo.AssetDataMaps) { changedFiles.Add(item.Key); } Debug.Log(JsonMapper.ToJson(changedFiles, true)); var ablist = changedBuildInfo.AssetDataMaps.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(newBuildAssetsInfo); }
/// <summary> /// 开始构建AB /// </summary> public void StartBuildAssetBundle(BuildTarget buildTarget) { //-----------------------开始打包AssetBundle逻辑--------------------------- Debug.Log("【BuildAssetbundle】执行Build..."); //设置编辑器状态 BDEditorApplication.EditorStatus = BDFrameworkEditorStatus.BuildAssetBundle; var platform = BApplication.GetRuntimePlatform(buildTarget); //1.整理abname this.MergeABName(BuildAssetsInfo); //2.对比差异文件 var changedAssetsInfo = GetChangedAssets(BuildAssetsInfo, buildTarget); //3.生成artconfig var assetbundleItemList = this.GenAssetBundleConfig(BuildAssetsInfo, BuildParams, platform); //4.打包 AssetDatabase.StartAssetEditing(); //禁止自动导入 { this.BuildAssetBundle(assetbundleItemList, changedAssetsInfo, BuildParams, platform); } AssetDatabase.StopAssetEditing(); //恢复自动导入 //3.BuildInfo配置处理 var platformOutputPath = IPath.Combine(BuildParams.OutputPath, BApplication.GetPlatformPath(platform)); //设置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(BuildAssetsInfo, true); FileHelper.WriteAllText(buildinfoPath, json); //4.备份Artifacts //this.BackupArtifacts(buildTarget); //5.检测本地的Manifest和构建预期对比 var abRootPath = IPath.Combine(BuildParams.OutputPath, BApplication.GetPlatformPath(platform), BResources.ART_ASSET_ROOT_PATH); var previewABUnitMap = BuildAssetsInfo.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.资源混淆 if (BDEditorApplication.BDFrameWorkFrameEditorSetting.BuildAssetBundle.IsEnableObfuscation) { this.MixAssetBundle(BuildParams.OutputPath, platform); } //恢复编辑器状态 BDEditorApplication.EditorStatus = BDFrameworkEditorStatus.Idle; //BD生命周期触发 BDFrameworkPipelineHelper.OnEndBuildAssetBundle(this); //GenAssetBundleItemCacheList = abConfigList.ToList(); }