2023-06-14 15:46:48 +08:00

543 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using UnityEditor;
using System.IO;
using UnityEditor.Build.Reporting;
using System.Text.RegularExpressions;
using System;
using System.Threading;
namespace BFEditor.Build
{
public static class BuildAndroidUtils
{
const string JAVA_HOME_ENVIRONMENT = "JAVA_HOME";
const string JAVA_HOME_ENVIRONMENT_PATH = "/Applications/Unity/PlaybackEngines/AndroidPlayer/Tools/OpenJDK/MacOS";
const string ANDROID_DEFINE_SYMBOLS = "THREAD_SAFE;USE_AB";
const string AS_PROJECT_PATH = "BFVersions/android";
const string GRADLE_PATH = "/Users/aoddabao/.gradle/wrapper/dists/gradle-5.6.4-all/ankdp27end7byghfw1q2sw75f/gradle-5.6.4/bin/gradle";
const string BUGLY_APP_ID = "1eb4e5e560";
const string BUGLY_APP_KEY = "99e249db-4eeb-440e-83e7-c2bd80e8b5e4";
static Thread buglyUploadThread;
static string ReleaseSOPath = Application.dataPath + "/../BFVersions/android/ub-release/src/main/jniLibs";
static string BuglyPath = Application.dataPath + "/../Bugly";
static string BuglySOPath = Application.dataPath + "/../Bugly/so";
static string GradleExcuteProjectPath = Application.dataPath + "/../BFVersions/android/ub-release";
static string DevAsProjectPath = Application.dataPath + "/../BFVersions/android/dz_dev";
static string LanReleaseAsProjectPath = Application.dataPath + "/../BFVersions/android/dz_release";
static string GoogleAsProjectPath = Application.dataPath + "/../BFVersions/android/dz_google_apk";
static string GoogleCommonProjectPath = Application.dataPath + "/../BFVersions/android/google_common";
static string GPAsProjectPath = Application.dataPath + "/../BFVersions/android/ub-gp"; // gp删档测试渠道
static string GPOfficialAsProjectPath = Application.dataPath + "/../BFVersions/android/ub-google"; // gp正式渠道
static string SignShellPath = Application.dataPath + "/../BFFiles/androidkey";
static string GpAlginShellPath = Application.dataPath + "/../BFFiles/androidkey";
static BuildAndroidUtils()
{
EnsureJavaHome();
}
public static void EnsureJavaHome()
{
// var javaHomeEnvironment = Environment.GetEnvironmentVariable(JAVA_HOME_ENVIRONMENT);
// if (string.IsNullOrEmpty(javaHomeEnvironment))
// {
// Environment.SetEnvironmentVariable(JAVA_HOME_ENVIRONMENT, JAVA_HOME_ENVIRONMENT_PATH);
// }
}
/// <summary>
/// 打包android
/// </summary>
public static bool BuildAndroidPlayer(BuildInfo buildInfo)
{
var buildTarget = BuildTarget.Android;
// 检查平台
if (EditorUserBuildSettings.activeBuildTarget != buildTarget)
{
Debug.LogError("[bferror]当前没有在对应平台");
return false;
}
// 重新生成XLua
CompileScriptsUtils.RegenerateXLuaCode(true);
// 打包设置
BuildSettings(buildInfo);
// 开始打包
var bpOptions = GetBuildOptions(buildInfo);
var report = BuildPipeline.BuildPlayer(bpOptions);
// 打包成功
if (report.summary.result == BuildResult.Succeeded)
{
return BuildAndroidAPK(buildInfo);
}
else
{
Debug.LogError("[bferror]unity打包失败");
return false;
}
}
/// <summary>
/// 打包设置
/// </summary>
static void BuildSettings(BuildInfo buildInfo)
{
// 设置bundleVersion
PlayerSettings.bundleVersion = buildInfo.version;
// 设置VersionCode
PlayerSettings.Android.bundleVersionCode = buildInfo.version_code;
// 设置竖屏
PlayerSettings.defaultInterfaceOrientation = UIOrientation.Portrait;
PlayerSettings.allowedAutorotateToPortrait = false;
PlayerSettings.allowedAutorotateToPortraitUpsideDown = false;
PlayerSettings.allowedAutorotateToLandscapeLeft = false;
PlayerSettings.allowedAutorotateToLandscapeRight = false;
// 安卓构建目标CPU架构
PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARMv7 | AndroidArchitecture.ARM64;
// 强加Internet权限
PlayerSettings.Android.forceInternetPermission = true;
// 关闭启动动画
PlayerSettings.SplashScreen.show = false;
// 设置包名
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, buildInfo.bundleName);
Debug.Log("[bfinfo]设置包名:" + buildInfo.bundleName);
// 跳过版本控制
var symbols = ANDROID_DEFINE_SYMBOLS;
if (buildInfo.skipVersion)
{
symbols = symbols + ";SKIP_VERSION;";
}
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, symbols);
Debug.Log("[bfinfo]设置defineSymbols: " + symbols);
// 是否是dev
var development = buildInfo.IsDevChannel() ? true : false;
EditorUserBuildSettings.development = development;
// 商品名称
// 应用名
if (buildInfo.IsPublish())
{
PlayerSettings.productName = "Knights Combo";
}
else
{
PlayerSettings.productName = development ? "b6-dev" : "b6-release";
}
// BuildType设置dev/release
EditorUserBuildSettings.androidBuildType = development ? AndroidBuildType.Debug : AndroidBuildType.Release;
// 是否导出as工程
// EditorUserBuildSettings.exportAsGoogleAndroidProject = development ? false : true;
EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
// dev使用Mono release使用IL2CPP
var scriptImp = development ? ScriptingImplementation.Mono2x : ScriptingImplementation.IL2CPP;
PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, scriptImp);
}
/// <summary>
/// 获取打包参数
/// </summary>
static BuildPlayerOptions GetBuildOptions(BuildInfo buildInfo)
{
var bpOptions = new BuildPlayerOptions();
bpOptions.scenes = AssetBundleUtils.GetBuildScenes();
bpOptions.target = BuildTarget.Android;
// if (buildInfo.IsDevChannel())
// {
// bpOptions.locationPathName = GetDevApkPathName(buildInfo);
// Debug.Log("[bfinfo]apk path : " + bpOptions.locationPathName);
// }
// else
// {
// bpOptions.locationPathName = GetASProjectPathName();
// Debug.Log("[bfinfo]asProject path : " + bpOptions.locationPathName);
// }
bpOptions.locationPathName = GetASProjectPathName(buildInfo);
BuildOptions options;
if (buildInfo.IsReleaseChannel())
{
options = BuildOptions.None;
}
else
{
options = BuildOptions.Development;
}
bpOptions.options = options;
return bpOptions;
}
static string GetDevApkPathName(BuildInfo buildInfo)
{
var apkName = buildInfo.skipVersion ? "dz_dev_skip_version.apk" : "dz_dev_debug.apk";
var path = Path.Combine(AS_PROJECT_PATH, apkName);
return path;
}
static string GetASProjectPathName(BuildInfo buildInfo)
{
var dir = Path.Combine(AS_PROJECT_PATH, buildInfo.mode);
if (Directory.Exists(dir))
{
Directory.Delete(dir, true);
}
return dir;
}
static bool BuildAPK(BuildInfo buildInfo)
{
if (buildInfo.IsGPChannel())
{
MergeGPToReleaseProject(buildInfo);
FixGradleVersion(buildInfo.version_code, buildInfo.version);
}
if (buildInfo.IsLanRelease())
{
AddBuglyParamsToReleaseProject();
}
Debug.Log("[bfinfo]正在buildApk...");
var success = true;
var args = "";
if (buildInfo.IsReleaseChannel())
{
args += " assembleRelease";
}
else
{
args += " assembleDebug";
}
BFEditorUtils.RunCommond(GRADLE_PATH, args, GradleExcuteProjectPath,
(msg) =>
{
},
(errorMsg) =>
{
if (errorMsg.Contains("BUILD FAILED") || errorMsg.Contains("FAILURE") || errorMsg.Contains("ERROR"))
{
success = false;
Debug.LogError("[bferror] " + errorMsg);
}
});
if (buildInfo.IsGPChannel())
{
// 尝试制作并上传bugly符号表 开新Thread不影响打包流程
if (success)
{
CopySOAndUploadBuglySymbol(buildInfo.bundleName, buildInfo.version);
}
}
return success;
}
static bool BuildAAB(BuildInfo buildInfo)
{
var result = true;
if(buildInfo.IsGPChannel())
{
// MergeGPToReleaseProject(buildInfo);
// FixGradleVersion(buildInfo.version_code, buildInfo.version);
}
return result;
}
static bool BuildAndroidAPK(BuildInfo buildInfo)
{
var result = true;
if(buildInfo.IsDevChannel())
{
MergeProject(buildInfo, DevAsProjectPath);
}
else if(buildInfo.IsLanRelease())
{
MergeProject(buildInfo, LanReleaseAsProjectPath);
}
else if(buildInfo.IsGPChannel())
{
MergeProject(buildInfo, GoogleAsProjectPath);
}
return result;
}
/// <summary>
/// 合并dev工程
/// </summary>
static void MergeProject(BuildInfo buildInfo, String asProjectPath)
{
Debug.Log("[bfinfo]正在整合dev project...");
var dir = Path.Combine(Application.dataPath, "../", AS_PROJECT_PATH, buildInfo.mode);
var javaPath = Path.Combine(dir, "unityLibrary/src/main/java");
var manifestPath = Path.Combine(dir, "unityLibrary/src/main/AndroidManifest.xml");
// 获取到unity打出的build-id
var reader = new StreamReader(new FileStream(manifestPath, FileMode.Open));
string buildIdLine;
while ((buildIdLine = reader.ReadLine()) != null)
{
if (buildIdLine.Contains("unity.build-id"))
{
Debug.Log("[bfinfo]修正build-id: " + buildIdLine);
break;
}
}
reader.Close();
reader.Dispose();
if (Directory.Exists(javaPath))
{
var di = new DirectoryInfo(javaPath);
di.Delete(true);
}
BFEditorUtils.CopyDir(GoogleCommonProjectPath, dir);
// 获取到google_common复制过去的build.gradle和AndroidManifest
var buildGradlePath = Path.Combine(dir, "launcher/build.gradle");
var text = File.ReadAllText(buildGradlePath);
var regex = new Regex("REPLACE_APPLICATION_ID");
text = regex.Replace(text, buildInfo.bundleName);
File.WriteAllText(buildGradlePath, text);
var androidManifestPath = Path.Combine(dir, "launcher/src/main/AndroidManifest.xml");
text = File.ReadAllText(androidManifestPath);
regex = new Regex("REPLACE_APPLICATION_ID");
text = regex.Replace(text, buildInfo.bundleName);
File.WriteAllText(androidManifestPath, text);
BFEditorUtils.CopyDir(asProjectPath, dir);
text = File.ReadAllText(manifestPath);
regex = new Regex("REPLACE_BUILD_ID");
text = regex.Replace(text, buildIdLine);
File.WriteAllText(manifestPath, text);
}
/// <summary>
/// 合并gp工程
/// </summary>
static void MergeGPToReleaseProject(BuildInfo buildInfo)
{
Debug.Log("[bfinfo]正在整合gp渠道sdk...");
var javaPath = GradleExcuteProjectPath + "/src/main/java";
var manifestPath = GradleExcuteProjectPath + "/src/main/AndroidManifest.xml";
// 获取到unity打出的build-id
var reader = new StreamReader(new FileStream(manifestPath, FileMode.Open));
string buildIdLine;
while ((buildIdLine = reader.ReadLine()) != null)
{
if (buildIdLine.Contains("unity.build-id"))
{
Debug.Log("[bfinfo]修正build-id: " + buildIdLine);
break;
}
}
reader.Close();
reader.Dispose();
if (Directory.Exists(javaPath))
{
var di = new DirectoryInfo(javaPath);
di.Delete(true);
}
if (buildInfo.IsGPOfficial())
{
BFEditorUtils.CopyDir(GPOfficialAsProjectPath, GradleExcuteProjectPath);
}
else
{
BFEditorUtils.CopyDir(GPAsProjectPath, GradleExcuteProjectPath);
}
var text = File.ReadAllText(manifestPath);
var regex = new Regex("REPLACE_BUILD_ID");
text = regex.Replace(text, buildIdLine);
File.WriteAllText(manifestPath, text);
}
/// <summary>
/// fix versionCode versionName
/// </summary>
static void FixGradleVersion(int versionCode, string versionName)
{
Debug.Log("[bfinfo]修正build.gradle: VersionCode " + versionCode + " VersionName " + versionName);
var gradleFilePath = Path.Combine(GradleExcuteProjectPath, "build.gradle");
var text = File.ReadAllText(gradleFilePath);
var regex = new Regex("versionCode 1");
text = regex.Replace(text, string.Format("versionCode {0}", versionCode));
regex = new Regex("versionName '0.1'");
text = regex.Replace(text, string.Format("versionName '{0}'", versionName));
File.WriteAllText(gradleFilePath, text);
}
/// <summary>
/// 内网Release包接入Bugly
/// </summary>
static void AddBuglyParamsToReleaseProject()
{
// 修改build.grade
var gradleFilePath = Path.Combine(GradleExcuteProjectPath, "build.gradle");
var text = File.ReadAllText(gradleFilePath);
var regex = new Regex("implementation");
var match = regex.Match(text);
var index = match.Index;
text = text.Insert(index, "\n" +
"implementation 'com.tencent.bugly:crashreport:latest.release'\n" +
"implementation 'com.tencent.bugly:nativecrashreport:latest.release'\n");
File.WriteAllText(gradleFilePath, text);
// 修改AndroidManifest.xml
var manifestPath = GradleExcuteProjectPath + "/src/main/AndroidManifest.xml";
text = File.ReadAllText(manifestPath);
regex = new Regex("<uses-permission");
match = regex.Match(text);
index = match.Index;
text = text.Insert(index, "\n" +
"<uses-permission android:name='android.permission.READ_PHONE_STATE' />\n" +
"<uses-permission android:name='android.permission.ACCESS_WIFI_STATE' />\n" +
"<uses-permission android:name='android.permission.READ_LOGS' />\n" +
"<uses-permission android:name='android.permission.POST_NOTIFICATIONS'/>\n");
File.WriteAllText(manifestPath, text);
// 修改UnityPlayerActivity.java
var javaPath = GradleExcuteProjectPath + "/src/main/java/com/juzu/ub/release/android/UnityPlayerActivity.java";
text = File.ReadAllText(javaPath);
regex = new Regex("import");
match = regex.Match(text);
index = match.Index;
text = text.Insert(index, "\nimport com.tencent.bugly.crashreport.CrashReport;");
regex = new Regex("requestFocus\\(\\);");
match = regex.Match(text);
index = match.Index;
var length = match.Length;
var formatInsertString = string.Format("\nCrashReport.initCrashReport(getApplicationContext(), \"{0}\", false);", BUGLY_APP_ID);
text = text.Insert(index + length, formatInsertString);
File.WriteAllText(javaPath, text);
}
/// <summary>
/// release包加密后签名
/// </summary>
static bool ReleaseApkSign()
{
Debug.Log("[bfinfo]正在签名apk...");
var success = true;
BFEditorUtils.RunCommond("sh", "release_sign.sh", SignShellPath,
(msg) =>
{
},
(errorMsg) =>
{
Debug.LogError("[bferror] " + errorMsg);
success = false;
});
return success;
}
/// <summary>
/// gp包对齐
/// </summary>
static bool GPApkAlign()
{
Debug.Log("[bfinfo]正在对齐apk...");
var success = true;
BFEditorUtils.RunCommond("sh", "gp_align.sh", GpAlginShellPath,
(msg) =>
{
},
(errorMsg) =>
{
Debug.LogError("[bferror] " + errorMsg);
success = false;
});
return success;
}
/// <summary>
/// google official包对齐
/// </summary>
static bool GoogleOfficialApkAlign()
{
Debug.Log("[bfinfo]正在对齐apk...");
var success = true;
BFEditorUtils.RunCommond("sh", "google_align.sh", GpAlginShellPath,
(msg) =>
{
},
(errorMsg) =>
{
Debug.LogError("[bferror] " + errorMsg);
success = false;
});
return success;
}
/// <summary>
/// CopyRelease文件夹内的so到bugly文件夹制作并上传Bugly符号表
/// 因是非出包必要步骤且依赖网络环境和腾讯服务器有时会失败所以开一个Thread来处理
/// </summary>
static void CopySOAndUploadBuglySymbol(string bundleName, string version)
{
// 将release的so复制到bugly文件下
BFEditorUtils.CopyDir(ReleaseSOPath, BuglySOPath);
// 开启Thread处理打包so和上传
TryCloseUploadThread();
var args = "bugly.sh" + " " + BUGLY_APP_ID + " " + BUGLY_APP_KEY + " " + bundleName + " " + version;
buglyUploadThread = new Thread(new ThreadStart(() => { UploadBuglySymbol(args); }));
buglyUploadThread.IsBackground = true;
buglyUploadThread.Start();
}
static void UploadBuglySymbol(string args)
{
BFEditorUtils.RunCommond("sh", args, BuglyPath,
(msg) =>
{
Debug.Log("UploadBuglySymbol: " + msg);
},
(errorMsg) =>
{
Debug.LogError("[bferror] UploadBuglySymbol: " + errorMsg);
});
TryCloseUploadThread();
}
static void TryCloseUploadThread()
{
if (buglyUploadThread != null)
{
var tmp = buglyUploadThread;
buglyUploadThread = null;
tmp.Abort();
}
}
}
}