using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using BFEditor.Resource;
using BF;
namespace BFEditor.Build
{
public static class BuildProjectTools
{
static string AssetBundleITPath = Application.dataPath + "/../Build/output/{0}";
static string AssetBundleCachePath = Application.dataPath + "/../HistoryAssetBundles";
static BuildProjectTools()
{
BuildAndroidUtils.EnsureJavaHome();
}
///
/// 提供给neo出包接口
///
public static void BuildBFPlayer()
{
var dict = BFEditorUtils.GetCommandLineArgs();
if (dict.TryGetValue("data", out string dataStr))
{
Debug.Log("BuildBFPlayer " + dataStr);
var json = "{\"infos\":" + dataStr + "}";
var buildInfoCollection = JsonUtility.FromJson(json);
if (!BuildBFPlayer(buildInfoCollection.GetFirstInfo()))
{
throw new Exception();
}
}
else
{
throw new Exception();
}
}
public static bool BuildBFPlayer(BuildInfo buildInfo)
{
// assetbundles
if (!BuildResources(buildInfo, Application.streamingAssetsPath, true))
{
return false;
}
// 删除不进包的多语言
// if (!DeleteOverLanguageAb(buildInfo))
// {
// return false;
// }
// 打包
if (!BuildPlayer(buildInfo))
{
Debug.LogError("[bferror]buildPlayer失败");
return false;
}
AssetDatabase.Refresh();
return true;
}
static bool BuildPlayer(BuildInfo buildInfo)
{
Debug.Log("[bfinfo]开始打包, bundleName : " + buildInfo.bundleName + " version : " + buildInfo.version + " mode : " + buildInfo.mode);
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
var result = false;
if (buildInfo.IsAndroidPlatform() && BuildAndroidUtils.BuildAndroidPlayer(buildInfo))
{
result = true;
}
#if UNITY_EDITOR_OSX
if (buildInfo.IsIOSPlatform() && BuildIOSUtils.BuildIOSPlayer(buildInfo))
{
result = true;
}
#endif
if (result)
{
watch.Stop();
Debug.Log("[bfinfo]打包完成,耗时: " + BFEditorUtils.GetTimeStr(watch.ElapsedMilliseconds));
}
return result;
}
///
/// 提供给neo打热更接口
///
public static void BuildResources()
{
var dict = BFEditorUtils.GetCommandLineArgs();
if (dict.TryGetValue("data", out string dataStr))
{
Debug.Log("BuildResources " + dataStr);
var json = "{\"infos\":" + dataStr + "}";
var buildInfoCollection = JsonUtility.FromJson(json);
var bulidInfo = buildInfoCollection.GetFirstInfo();
var itPath = string.Format(AssetBundleITPath, bulidInfo.mode);
if (!BuildResources(bulidInfo, itPath, false))
{
throw new Exception();
}
}
else
{
throw new Exception();
}
}
public static bool BuildResources(BuildInfo buildInfo, string outputPath, bool needCopyToITPath)
{
if (Directory.Exists(outputPath))
{
Directory.Delete(outputPath, true);
}
// 首先尝试从缓存获取
// if (TryGetAbFromCache(buildInfo, outputPath))
// {
// // 拷贝资源到it上传路径
// // if (needCopyToITPath)
// // {
// // CopyResToITPath(buildInfo, outputPath);
// // }
// return true;
// }
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
// var buildTarget = buildInfo.IsIOSPlatform() ? BuildTarget.iOS : BuildTarget.Android;
var isRelease = buildInfo.IsReleaseChannel();
Debug.Log("[bfinfo]开始打包资源, bundleName : " + buildInfo.bundleName + " version : " + buildInfo.version + " mode : " + buildInfo.mode);
// // 检查平台
// if (EditorUserBuildSettings.activeBuildTarget != buildTarget)
// {
// Debug.LogError("[bferror]当前没有在对应平台");
// return false;
// }
// 更新atlas
MainAtlasTools.UpdateMainAtlas();
// LanguageAtlasTools.UpdateLanguageAtlas();
// 生成tmp字体
TMPTools.GenFormalFontAsset(false);
// 清理fbx默认材质
MaterialTools.ClearFbxDefaultMaterial();
// 清理shader依赖资源
ShaderDependenciesTools.ClearAllShaderDependencies();
// 收集shader变体
ShaderVariantsTools.GenerateVariantCollection();
// ios因为环境问题,先不编译,打版本前提前编译好
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
{
// 编译并且加密lua代码
if (!CompileScriptsUtils.CompileAndEncryptLua(!isRelease))
{
Debug.LogError("[bferror]lua代码编译失败");
return false;
}
}
// 设置abName
AssetBundleUtils.SetAllAssetsBundleName();
// 打ab资源
if (!AssetBundleUtils.BuildAssetBundles(EditorUserBuildSettings.activeBuildTarget, outputPath, isRelease, BuildAssetBundleOptions.ChunkBasedCompression,
buildInfo.GetLanguageInfo(), buildInfo.version))
{
Debug.LogError("[bferror]打ab失败");
return false;
}
// 检查循环依赖
if (!ABCycleDependUtils.CheckABCycleDepend(outputPath))
{
Debug.LogError("[bferror]打ab失败,ab存在循环依赖");
return false;
}
// 本地缓存ab
if (buildInfo.IsReleaseChannel())
{
Debug.Log("[bfinfo]正在缓存assetbundles...");
BFEditorUtils.CopyDirWithIgnore(outputPath, Path.Combine(AssetBundleCachePath, buildInfo.version), new List { ".meta" });
}
// 拷贝资源到it上传路径
// if (needCopyToITPath)
// {
// CopyResToITPath(buildInfo, outputPath);
// }
watch.Stop();
Debug.Log("[bfinfo]资源打包完成,耗时: " + BFEditorUtils.GetTimeStr(watch.ElapsedMilliseconds));
return true;
}
///
/// 尝试从缓存中获取ab,会进行md5校验
///
static bool TryGetAbFromCache(BuildInfo buildInfo, string outputPath)
{
var cachePath = Path.Combine(AssetBundleCachePath, buildInfo.version);
if (!Directory.Exists(cachePath))
{
return false;
}
if (CheckCacheAbMd5(cachePath, buildInfo))
{
Debug.Log(string.Format("[bfinfo]正在拷贝本地缓存资源 {0} ---> {1}", cachePath, outputPath));
BFEditorUtils.CopyDirWithIgnore(cachePath, outputPath, new List { ".meta" });
}
return true;
}
public static void CopyResToITPath(BuildInfo buildInfo, string outputPath)
{
Debug.Log("[bfinfo]正在拷贝assetbundles到运维上传路径...");
var itPath = string.Format(AssetBundleITPath, buildInfo.mode);
if (Directory.Exists(itPath))
{
Directory.Delete(itPath, true);
}
BFEditorUtils.CopyDirWithIgnore(outputPath, itPath, new List { ".meta" });
}
///
/// 校验缓存资源
///
static bool CheckCacheAbMd5(string abPath, BuildInfo buildInfo)
{
Debug.Log("[bfinfo]正在校验缓存资源...");
var abccPath = Path.Combine(abPath, "ab_config.bytes");
if (!File.Exists(abccPath))
{
Debug.LogError("[bferror]校验缓存资源失败 ab_config.bytes不存在");
return false;
}
var bytes = File.ReadAllBytes(abccPath);
var json = AssetBundleConfigCollection.Decompress(bytes);
var abcc = AssetBundleConfigCollection.Create(json);
foreach (var abc in abcc.mainConfigs)
{
var path = Path.Combine(abPath, abc.assetBundlePath);
if (!File.Exists(path))
{
Debug.LogError(string.Format("[bferror]校验缓存资源失败 {0} 文件丢失", abc.assetBundlePath));
return false;
}
var md5 = GameLaunchUtils.GetFileMD5(path);
if (md5 != abc.md5)
{
Debug.LogError(string.Format("[bferror]校验缓存资源失败 {0} 文件md5不一致", abc.assetBundlePath));
return false;
}
}
// 只有版本号不一样, 则修改abConfig的版本号
if (abcc.version != buildInfo.version)
{
Debug.Log(string.Format("[bfinfo]资源版本号不一样,修改版本号,缓存资源版本{0}, 目标版本{1}", abcc.version, buildInfo.version));
abcc.version = buildInfo.version;
var newJson = abcc.ToJson();
var newBytes = AssetBundleConfigCollection.Compress(newJson);
File.WriteAllBytes(abccPath, newBytes);
}
Debug.Log("[bfinfo]缓存资源校验完成");
return true;
}
///
/// 剔除冗余的多语言资源
///
static bool DeleteOverLanguageAb(BuildInfo buildInfo)
{
var bundleName = buildInfo.bundleName;
var languageInfo = BFPlatform.GetLanguageInfo(bundleName);
if (languageInfo == null)
{
Debug.LogError("[bferror]没有对应的多语言info " + bundleName);
return false;
}
foreach (var languagePath in AssetBundleUtils.languagePathList)
{
var languageAbDirPath = Application.streamingAssetsPath + "/" + languagePath;
var subLanguageDirs = Directory.GetDirectories(languageAbDirPath);
foreach (var dir in subLanguageDirs)
{
var dirInfo = new DirectoryInfo(dir);
var name = dirInfo.Name;
if (languageInfo.Contains(name))
{
continue;
}
Debug.Log("[bfinfo]剔除不进包的多语言资源 " + dirInfo.FullName);
dirInfo.Delete(true);
}
}
return true;
}
}
}