556 lines
19 KiB
C#
556 lines
19 KiB
C#
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 PublishAsProjectPath = Application.dataPath + "/../BFVersions/android/publish_release";
|
||
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);
|
||
var dir = Path.Combine(Application.dataPath, "../", AS_PROJECT_PATH, buildInfo.mode);
|
||
BFEditorUtils.RunCommond("gradle", " assembleDebug", dir, (msg) => {
|
||
}, (errorMsg) => {
|
||
Debug.LogError("[bferror] " + errorMsg);
|
||
});
|
||
}
|
||
else if(buildInfo.IsLanRelease())
|
||
{
|
||
MergeProject(buildInfo, LanReleaseAsProjectPath);
|
||
}
|
||
else if(buildInfo.IsGPChannel())
|
||
{
|
||
MergeProject(buildInfo, GoogleAsProjectPath);
|
||
FixGradleVersion(buildInfo.version_code, buildInfo.version);
|
||
}
|
||
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(PublishAsProjectPath, "launcher", "build.gradle");
|
||
var text = File.ReadAllText(gradleFilePath);
|
||
var regex = new Regex("versionCode 1");
|
||
text = regex.Replace(text, string.Format("versionCode {0}", versionCode));
|
||
var regex2 = new Regex("versionName '0.1.0'");
|
||
text = regex2.Replace(text, string.Format("versionName '{0}'", versionName));
|
||
File.WriteAllText(gradleFilePath, text);
|
||
|
||
var gradleFilePath2 = Path.Combine(PublishAsProjectPath, "unityLibrary", "build.gradle");
|
||
var text2 = File.ReadAllText(gradleFilePath2);
|
||
text2 = regex.Replace(text2, string.Format("versionCode {0}", versionCode));
|
||
text2 = regex2.Replace(text, string.Format("versionName '{0}'", versionName));
|
||
File.WriteAllText(gradleFilePath2, text2);
|
||
}
|
||
|
||
/// <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();
|
||
}
|
||
}
|
||
}
|
||
}
|