/// <summary>
        /// 备份当前版本BuildCache资源包
        /// </summary>
        private static string BackupBuildCache(AssetBundleManifest manifest)
        {
            if (manifest == null)
            {
                return(null);
            }

            var    curResVer    = GetCurResVersion();
            string platformName = ResManager.GetBuildPlatformName();
            var    buildDir     = BundleBuildCachePath;
            var    backupDir    = BackupExportPath + "/res_ver_" + curResVer;

            //先删除之前已存在的资源目录
            if (Directory.Exists(backupDir))
            {
                Directory.Delete(backupDir, true);
                Debug.Log("旧版本资源目录已存在,将清空后重新备份:" + backupDir);
            }
            Directory.CreateDirectory(backupDir);

            //先备份AssetBundleManifest信息
            CopyFile(buildDir + "/" + platformName, backupDir + "/" + platformName, true);

            var sb = new StringBuilder();
            var allAssetBundles = manifest.GetAllAssetBundles();

            for (var index = 0; index < allAssetBundles.Length; index++)
            {
                var    assetBundle = allAssetBundles[index];
                string bundlePath  = buildDir + "/" + assetBundle;
                sb.AppendLine("[Backup Bundle]=========================");
                sb.AppendLine(assetBundle);
                sb.AppendLine("Hash:" + manifest.GetAssetBundleHash(assetBundle));
                uint crc;
                BuildPipeline.GetCRCForAssetBundle(bundlePath, out crc);
                sb.AppendLine("CRC:" + crc);

                CopyFile(bundlePath, backupDir + "/" + assetBundle, true);
                int finishCount = index + 1;
                EditorUtility.DisplayProgressBar("备份AssetBundle中",
                                                 String.Format(" {0} / {1} ", finishCount, allAssetBundles.Length),
                                                 finishCount / (float)allAssetBundles.Length);
                sb.AppendLine();
            }
            EditorUtility.ClearProgressBar();

            CopyFile(ResVerPath, backupDir + "/" + ResourceModuleConfig.ResVerFileName);
            Debug.Log(sb);
            return(backupDir);
        }
        public static void CopyToStreamingAssets(string backupDir)
        {
            if (string.IsNullOrEmpty(backupDir))
            {
                return;
            }

            string platformName = ResManager.GetBuildPlatformName();
            string manifestPath = backupDir + "/" + platformName;
            var    manifest     = LoadAssetBundleManifest(manifestPath);

            if (manifest != null)
            {
                string packageDir = Application.streamingAssetsPath + "/" + platformName;
                //先删除之前已存在的资源目录
                if (Directory.Exists(packageDir))
                {
                    Directory.Delete(packageDir, true);
                }
                Directory.CreateDirectory(packageDir);

                //先拷贝AssetBundleManifest
                CopyFile(manifestPath, packageDir + "/" + platformName);

                var sb = new StringBuilder();
                sb.AppendLine("[CopyToStreamingAssets]=========================");
                var allAssetBundles = manifest.GetAllAssetBundles();
                for (var index = 0; index < allAssetBundles.Length; index++)
                {
                    var    assetBundle = allAssetBundles[index];
                    string bundlePath  = backupDir + "/" + assetBundle;
                    sb.AppendLine(bundlePath);
                    CopyFile(bundlePath, packageDir + "/" + assetBundle);
                    int finishCount = index + 1;
                    EditorUtility.DisplayProgressBar("拷贝AssetBundle中",
                                                     String.Format(" {0} / {1} ", finishCount, allAssetBundles.Length),
                                                     finishCount / (float)allAssetBundles.Length);
                }
                EditorUtility.ClearProgressBar();

                CopyFile(backupDir + "/" + ResourceModuleConfig.ResVerFileName, packageDir + "/" + ResourceModuleConfig.ResVerFileName);
                Debug.Log(sb);
                AssetDatabase.Refresh();
            }
        }
        public static bool GenPatchPackages(string oldResDir, string newResDir)
        {
            if (!Directory.Exists(oldResDir) || !Directory.Exists(newResDir))
            {
                return(false);
            }

            var oldResVer = GetResVersion(oldResDir);
            var newResVer = GetResVersion(newResDir);

            if (oldResVer == null || newResVer == null)
            {
                Debug.LogError("资源版本信息加载失败");
                return(false);
            }

            if (oldResVer > newResVer)
            {
                Debug.LogErrorFormat("oldResVer > newResVer:{0} {1}", oldResVer, newResVer);
                return(false);
            }
            else if (oldResVer == newResVer)
            {
                //最新版本资源,无需生成补丁包
                GenLastestPatchInfo(newResVer);
                return(true);
            }

            string platformName = ResManager.GetBuildPlatformName();
            var    oldManifest  = LoadAssetBundleManifest(oldResDir + "/" + platformName);
            var    newManifest  = LoadAssetBundleManifest(newResDir + "/" + platformName);

            var oldBundleNames = oldManifest.GetAllAssetBundles();
            var newBundleNames = newManifest.GetAllAssetBundles();
            var allNameSet     = new HashSet <string>(oldBundleNames);

            allNameSet.UnionWith(newBundleNames);

            var patchedNames = new List <string>();
            var sb           = new StringBuilder();
            int index        = 0;

            foreach (var bundleName in allNameSet)
            {
                string oldResPath   = oldResDir + "/" + bundleName;
                string newResPath   = newResDir + "/" + bundleName;
                bool   oldResExists = File.Exists(oldResPath);
                bool   newResExists = File.Exists(newResPath);
                if (oldResExists && newResExists)
                {
                    //新旧版本都存在的,读取Bundle的Hash和CRC判断
                    var oldHash = oldManifest.GetAssetBundleHash(bundleName);
                    var newHash = newManifest.GetAssetBundleHash(bundleName);
                    if (oldHash != newHash)
                    {
                        patchedNames.Add(bundleName);
                        sb.AppendFormat("[Patched] 新旧Hash值不一致:{0}\n{1}\n{2}\n\n", bundleName, oldHash, newHash);
                    }
                    else
                    {
                        uint oldCRC;
                        uint newCRC;
                        BuildPipeline.GetCRCForAssetBundle(oldResPath, out oldCRC);
                        BuildPipeline.GetCRCForAssetBundle(newResPath, out newCRC);
                        if (oldCRC != newCRC)
                        {
                            patchedNames.Add(bundleName);
                            sb.AppendFormat("[Patched] 新旧CRC值不一致:{0}\n{1}\n{2}\n\n", bundleName, oldCRC, newCRC);
                        }
                        else
                        {
                            sb.AppendFormat("[ignored] 资源未变更:{0}\n{1}\n{2}\n\n", bundleName, newHash, newCRC);
                        }
                    }
                }
                else if (!oldResExists && newResExists)
                {
                    patchedNames.Add(bundleName);
                    sb.AppendFormat("[Patched] 新增版本资源:{0}\n\n", bundleName);
                }
                else if (oldResExists)
                {
                    sb.AppendFormat("[ignored] 新版本资源被移除或者BundleName变更:{0}\n\n", bundleName);
                }
                else
                {
                    throw new Exception(string.Format("[Error] Backup目录文件被异常删除:{0}\n\n", newResPath));
                }

                index++;
                EditorUtility.DisplayProgressBar("对比Bundle包版本信息", String.Format(" {0} / {1} ", index, allNameSet.Count),
                                                 index / (float)allNameSet.Count);
            }
            Debug.Log(sb);

            if (patchedNames.Count > 0)
            {
                string patchDir = string.Format("{0}/patch_{1}_{2}", PatchExportPath, oldResVer, newResVer);
                EditorUtility.DisplayProgressBar("生成补丁包中", patchDir, 0);
                if (Directory.Exists(patchDir))
                {
                    Directory.Delete(patchDir, true);
                }

                //AssetBundleManifest也需要拷贝
                Dictionary <string, string> fileHash = new Dictionary <string, string>();
                patchedNames.Add(ResManager.GetBuildPlatformName());
                foreach (var patchedName in patchedNames)
                {
                    string patchFile = patchDir + "/" + patchedName;
                    CopyFile(newResDir + "/" + patchedName, patchFile);
                    fileHash[patchedName] = SHA256Hashing.HashFile(patchFile);
                }

                string zipFile = patchDir + ".zip";
                ZipTool.CompressFolder(zipFile, patchDir);
                string zipHash      = MD5Hashing.HashFile(zipFile);
                long   fileSize     = new FileInfo(zipFile).Length;
                string finalZipFile = string.Format("{0}-{1}.zip", patchDir, zipHash);
                if (File.Exists(finalZipFile))
                {
                    File.Delete(finalZipFile);
                }
                File.Move(zipFile, finalZipFile);
                var patchInfo = new PatchInfo
                {
                    version  = oldResVer.ToString(),
                    nextVer  = newResVer.ToString(),
                    hash     = zipHash,
                    fileSize = fileSize,
                    fileName = Path.GetFileName(finalZipFile),
                    fileHash = fileHash,
                };

                string jsonPath = string.Format("{0}/{1}_{2}.json", PatchExportPath, ResourceModuleConfig.PatchInfoPrefix, oldResVer);
                FileExt.SaveJsonObj(patchInfo, jsonPath, false, true);
                Directory.Delete(patchDir, true);
                Debug.Log("Build Patch Package:" + finalZipFile);
            }
            else
            {
                Debug.Log("Build Patch Package Skip!!!");
            }
            EditorUtility.ClearProgressBar();

            return(true);
        }