/// <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();
        }