update: 更新AppBuilder

feature/Inventory
huyufei 2024-01-06 13:46:25 +08:00
parent ad39f77ed3
commit 6037835671
15 changed files with 614 additions and 12 deletions

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a99ba0cf57ee14adbb2be18231643025
guid: 64abb947fe2af4b9cbc1dd3113da8928
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -0,0 +1,104 @@
namespace Guru.Editor
{
using UnityEngine;
public enum AppBuilderType
{
Editor = 0,
Jenkins,
}
public class AppBuildParam
{
public bool IsBuildRelease;
public bool IsBuildShowLog;
public AppBuilderType BuilderType;
public string BuildVersion = "";
public bool AutoSetBuildNumber = true;
public bool IsBuildAAB;
public bool IsBuildSymbols = false;
public int AndroidTargetVersion = 0;
public bool AndroidUseMinify = false;
public bool DebugWithMono = true;
public string IOSTargetVersion = "";
public string IOSTeamId = "";
public string CompanyName = "";
public bool UseGuruCerts = true; // 使用 Guru 的证书打包
public override string ToString()
{
return $"build params: \n{JsonUtility.ToJson(this, true)}";
}
public static AppBuildParam Build(bool isRelease, AppBuilderType builderType = AppBuilderType.Editor, string version = "", bool autoBuildNumber = true, string companyName = "",
bool buildShowLog = false, bool useGuruCerts = true,
bool buildSymbols = false, bool buildAAB = false, bool useMinify = false, int androidTargetVersion = 0, bool debugWithMono = true,
string iOSTargetVersion = "", string iOSTeamId = "")
{
return new AppBuildParam()
{
IsBuildRelease = isRelease,
IsBuildShowLog = buildShowLog,
BuilderType = builderType,
BuildVersion = version,
AutoSetBuildNumber = autoBuildNumber,
IsBuildAAB = buildAAB,
IsBuildSymbols = buildSymbols,
AndroidTargetVersion = androidTargetVersion,
AndroidUseMinify = useMinify,
DebugWithMono = debugWithMono,
IOSTargetVersion = iOSTargetVersion,
IOSTeamId = iOSTeamId,
CompanyName = companyName,
UseGuruCerts = useGuruCerts,
};
}
/// <summary>
/// 构建Android参数
/// </summary>
/// <param name="isRelease"></param>
/// <param name="version"></param>
/// <param name="autoBuildNumber"></param>
/// <param name="builderType"></param>
/// <param name="companyName"></param>
/// <param name="useGuruCerts"></param>
/// <param name="useMinify"></param>
/// <param name="androidTargetVersion"></param>
/// <param name="debugWithMono"></param>
/// <returns></returns>
public static AppBuildParam AndroidParam(bool isRelease, string version = "", bool autoBuildNumber = true, AppBuilderType builderType = AppBuilderType.Editor,
string companyName = "", bool useGuruCerts = true, bool useMinify = false, int androidTargetVersion = 0, bool debugWithMono = true)
{
bool buildAAB = isRelease;
bool buildShowLog = isRelease;
bool buildSymbols = isRelease;
return Build(isRelease, builderType, version, autoBuildNumber,companyName, buildShowLog, useGuruCerts, buildSymbols, buildAAB, useMinify, androidTargetVersion, debugWithMono);
}
/// <summary>
/// 构建iOS参数
/// </summary>
/// <param name="isRelease"></param>
/// <param name="version"></param>
/// <param name="autoBuildNumber"></param>
/// <param name="builderType"></param>
/// <param name="companyName"></param>
/// <param name="useGuruCerts"></param>
/// <param name="iOSTargetVersion"></param>
/// <param name="iOSTeamId"></param>
/// <returns></returns>
public static AppBuildParam IOSParam(bool isRelease, string version = "", bool autoBuildNumber = true, AppBuilderType builderType = AppBuilderType.Editor,
string companyName = "", bool useGuruCerts = true, string iOSTargetVersion = "", string iOSTeamId = "" )
{
bool buildShowLog = isRelease;
return Build(isRelease, builderType, version, autoBuildNumber, companyName, buildShowLog, useGuruCerts, iOSTargetVersion:iOSTargetVersion, iOSTeamId:iOSTeamId);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c469e92c33ad406b965a1cb92e83015f
timeCreated: 1704418594

View File

@ -0,0 +1,374 @@
namespace Guru.Editor
{
using System.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using NUnit.Framework;
/// <summary>
/// 构建工具
/// </summary>
public partial class AppBuilder
{
public static int AndroidTargetSdkVersion = 33;
public static string IOSTargetOSVersion = "13.0";
public static string GuruIOSTeamId = "39253T242A";
public static string KeystoreName => $"guru_key.jks";
public static string KeystorePath => Application.dataPath + $"/Plugins/Android/{KeystoreName}";
public static string ProguardName => $"proguard-user.txt";
public static string ProguardPath => Application.dataPath + $"/Plugins/Android/{ProguardName}";
#region 构建 Android 接口
/// <summary>
///
/// </summary>
/// <param name="buildParam"></param>
/// <returns></returns>
public static string BuildAndroid(AppBuildParam buildParam)
{
//切换平台
BuildSwitchPlatform(BuildTarget.Android);
//打包通用设置
ChangeBuildPlayerCommonSetting(buildParam, BuildTargetGroup.Android);
var isDebug = !buildParam.IsBuildRelease;
var useMinify = buildParam.AndroidUseMinify;
var buildNumber= GetBuildNumberString(BuildTarget.Android);
if(buildParam.AutoSetBuildNumber) buildNumber= ChangeBuildNumber(BuildTarget.Android);
//android专用打包设置
EditorUserBuildSettings.buildAppBundle = buildParam.IsBuildAAB;
EditorUserBuildSettings.development = isDebug;
EditorUserBuildSettings.androidCreateSymbols = buildParam.IsBuildSymbols? AndroidCreateSymbols.Public : AndroidCreateSymbols.Disabled; //Android 输出SymbolsZip的选项
PlayerSettings.muteOtherAudioSources = false;
// ---- 开启 Minify 后需要配置 proguard-user.txt 文件 ----
if (useMinify) DeployProgaurdTxt();
PlayerSettings.Android.minifyWithR8 = useMinify;
PlayerSettings.Android.minifyRelease = useMinify;
PlayerSettings.Android.minifyDebug = useMinify;
// ---- 部署 Guru 专用的 Keystore ----
if (buildParam.UseGuruCerts && DeployAndroidKeystore())
{
// ---- 使用 Guru 专用的 KeyStore ----
PlayerSettings.Android.useCustomKeystore = true;
PlayerSettings.Android.keystoreName = KeystorePath;
PlayerSettings.Android.keystorePass = "guru0622";
PlayerSettings.Android.keyaliasName = "guru";
PlayerSettings.Android.keyaliasPass = "guru0622";
}
PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARMv7 | AndroidArchitecture.ARM64; //只构建 armv7 和 arm64
PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel22;
if (buildParam.AndroidTargetVersion > 0) AndroidTargetSdkVersion = buildParam.AndroidTargetVersion;
PlayerSettings.Android.targetSdkVersion = (AndroidSdkVersions)AndroidTargetSdkVersion; // 默认设置API为33
//打包
string symbolDefine = buildParam.IsBuildRelease ? GameDefine.MACRO_RELEASE : GameDefine.MACRO_DEBUG;
string apkPath = string.Empty;
string version = Application.version;
string extension = buildParam.IsBuildRelease ? ".aab" : ".apk";
if (EditorUserBuildSettings.exportAsGoogleAndroidProject) extension = ""; // 输出工程
string outputDir = Path.GetFileName($"{Application.dataPath }/../BuildOutput/Android");
apkPath = $"{outputDir}/{Application.productName.Replace(" ","_")}_{symbolDefine}_{version}_{buildNumber}{extension}";
if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir);
BuildOptions opts = isDebug ? BuildOptions.Development : BuildOptions.None;
BuildPipeline.BuildPlayer(GetBuildScenes(), apkPath, BuildTarget.Android, opts);
if (buildParam.BuilderType == AppBuilderType.Editor)
{
Open(outputDir);
}
return apkPath;
}
/// <summary>
/// 部署 Guru 专用的 Keystore
/// </summary>
private static bool DeployAndroidKeystore()
{
var dir = GetWorkingDir();
var from = $"{dir}/{KeystoreName}";
var to = KeystorePath;
if (File.Exists(to)) return true;
if (File.Exists(from))
{
File.Copy(from, to);
return true;
}
return false;
}
/// <summary>
/// 部署混淆用配置
/// </summary>
private static bool DeployProgaurdTxt()
{
var dir = GetWorkingDir();
var from = $"{dir}/{ProguardName}";
var to = ProguardPath;
if (File.Exists(to)) return true;
if (File.Exists(from))
{
File.Copy(from, to);
return true;
}
return false;
}
#endregion
#region 构建 IOS 接口
public static void BuildIOS(AppBuildParam buildParam)
{
//切换平台
BuildSwitchPlatform(BuildTarget.iOS);
//打包通用设置
ChangeBuildPlayerCommonSetting(buildParam, BuildTargetGroup.iOS);
//修改打包版本号
if(buildParam.AutoSetBuildNumber) ChangeBuildNumber(BuildTarget.iOS);
var isDebug = !buildParam.IsBuildRelease;
//ios专用打包设置
PlayerSettings.muteOtherAudioSources = false;
PlayerSettings.iOS.appInBackgroundBehavior = iOSAppInBackgroundBehavior.Custom;
PlayerSettings.iOS.backgroundModes = iOSBackgroundMode.RemoteNotification | iOSBackgroundMode.Fetch; // 后台启动配置
PlayerSettings.iOS.targetDevice = iOSTargetDevice.iPhoneAndiPad;
PlayerSettings.iOS.sdkVersion = iOSSdkVersion.DeviceSDK;
var targetVersion = IOSTargetOSVersion;
if (!string.IsNullOrEmpty(buildParam.IOSTargetVersion)) targetVersion = buildParam.IOSTargetVersion;
PlayerSettings.iOS.targetOSVersionString = targetVersion;
var teamId = buildParam.IOSTeamId;
if (buildParam.UseGuruCerts) teamId = GuruIOSTeamId;
if (!string.IsNullOrEmpty(teamId))
{
PlayerSettings.iOS.appleEnableAutomaticSigning = true;
PlayerSettings.iOS.appleDeveloperTeamID = teamId;
}
//打包
string xcodePath = Application.dataPath + "/../../xcode";
if (Directory.Exists(xcodePath))
{
Directory.Delete(xcodePath, true);
}
// 构建后打开路径
try
{
BuildOptions opts = isDebug ? BuildOptions.Development : BuildOptions.None;
BuildPipeline.BuildPlayer(GetBuildScenes(), xcodePath, BuildTarget.iOS, BuildOptions.None);
if (buildParam.BuilderType == AppBuilderType.Editor)
{
Open(xcodePath);
}
}
catch (Exception e)
{
Debug.LogError(e.Message);
}
}
#endregion
#region 通用接口
/// <summary>
/// 获取工作目录
/// </summary>
/// <returns></returns>
private static string GetWorkingDir()
{
var guids = AssetDatabase.FindAssets($"{nameof(AppBuilder)} t:Script");
if (guids.Length > 0)
{
var path = "";
foreach (var guid in guids)
{
path = AssetDatabase.GUIDToAssetPath(guids[0]);
if (path.Contains($"Editor/BuildTool/{nameof(AppBuilder)}"))
{
return Directory.GetParent(path)!.FullName;
}
}
}
return Path.GetFullPath("Packages/com.guru.unity.sdk.core/Editor/BuildTool/");
}
/// <summary>
/// 平台切换
/// </summary>
/// <param name="targetPlatform"></param>
private static void BuildSwitchPlatform(BuildTarget targetPlatform)
{
if (EditorUserBuildSettings.activeBuildTarget != targetPlatform)
{
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildPipeline.GetBuildTargetGroup(targetPlatform), targetPlatform);
AssetDatabase.Refresh();
}
}
private static void ChangeBuildPlayerCommonSetting(AppBuildParam buildParam, BuildTargetGroup buildTargetGroup)
{
EditorUserBuildSettings.development = !buildParam.IsBuildRelease;
EditorUserBuildSettings.allowDebugging = false;
EditorUserBuildSettings.connectProfiler = false;
EditorUserBuildSettings.buildScriptsOnly = false;
var backend = ScriptingImplementation.IL2CPP;
if (buildTargetGroup == BuildTargetGroup.Android
&& !buildParam.IsBuildRelease && buildParam.DebugWithMono)
{
backend = ScriptingImplementation.Mono2x;
}
PlayerSettings.SetScriptingBackend(buildTargetGroup, backend);
var companyName = buildParam.CompanyName;
if(string.IsNullOrEmpty(companyName)) companyName = GameDefine.CompanyName;
PlayerSettings.companyName = companyName;
var bundleVersion = buildParam.BuildVersion;
if(!string.IsNullOrEmpty(bundleVersion)) PlayerSettings.bundleVersion = bundleVersion;
// -------- Defines --------
List<string> defines = new List<string>();
var str = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup);
if (!string.IsNullOrEmpty(str))
{
defines = str.Split(';').ToList();
}
if (defines.Count > 0)
{
defines.Remove(GameDefine.MACRO_RELEASE);
defines.Remove(GameDefine.MACRO_DEBUG);
}
defines.Add(buildParam.IsBuildRelease ? GameDefine.MACRO_RELEASE : GameDefine.MACRO_DEBUG);
if (!buildParam.IsBuildRelease || buildParam.IsBuildShowLog)
{
defines.Add(GameDefine.MACRO_LOG);
}
// defines.Add("mopub_manager");
PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, defines.ToArray());
PlayerSettings.stripEngineCode = true;
PlayerSettings.SetManagedStrippingLevel(buildTargetGroup, ManagedStrippingLevel.Low);
PlayerSettings.SetApiCompatibilityLevel(buildTargetGroup, ApiCompatibilityLevel.NET_4_6);
}
/// <summary>
/// 修改打包版本号
/// </summary>
/// <param name="buildTarget"></param>
/// <param name="isRelease"></param>
private static string ChangeBuildNumber(BuildTarget buildTarget)
{
var nowDate = DateTime.Now;
string strBuildNumber = $"{nowDate.Year - 2000}{nowDate.Month:00}{nowDate.Day:00}{(nowDate.Hour * 60 + nowDate.Minute) / 15}";
int buildNumber = int.Parse(strBuildNumber);
if (buildTarget == BuildTarget.iOS)
{
PlayerSettings.iOS.buildNumber = buildNumber.ToString();
}
else if (buildTarget == BuildTarget.Android)
{
PlayerSettings.Android.bundleVersionCode = buildNumber;
}
return strBuildNumber;
}
/// <summary>
/// 获取构建数变量
/// </summary>
/// <returns></returns>
private static string GetBuildNumberString(BuildTarget buildTarget)
{
if (buildTarget == BuildTarget.iOS)
{
return PlayerSettings.iOS.buildNumber;
}
if (buildTarget == BuildTarget.Android)
{
return PlayerSettings.Android.bundleVersionCode.ToString();
}
return "";
}
/// <summary>
/// 获取打包场景
/// </summary>
/// <returns></returns>
public static string[] GetBuildScenes()
{
List<string> names = new List<string>();
foreach (var e in EditorBuildSettings.scenes)
{
if(e == null)
continue;
if(e.enabled)
names.Add(e.path);
}
return names.ToArray();
}
/// <summary>
/// 打开路径
/// </summary>
/// <param name="path"></param>
public static void Open(string path)
{
#if UNITY_EDITOR_OSX
EditorUtility.RevealInFinder(path);
#else
Application.Open($"file://{path}");
#endif
}
#endregion
#region 单元测试
[Test]
public static void TEST_GetWorkingDir()
{
var path = GetWorkingDir();
Debug.Log(path);
if (Directory.Exists(path))
{
Open(path);
}
else
{
Debug.LogError($"path not found: {path}");
}
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 483f16ab603d2421bae5fddb0310778b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,61 @@
-keep class com.unity3d.plugin.* { *; }
-keep public class com.adjust.sdk.** { *; }
-keep class com.amazon.device.ads.** { *; }
-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient {
com.google.android.gms.ads.identifier.AdvertisingIdClient$Info getAdvertisingIdInfo(android.content.Context);
}
-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient$Info {
java.lang.String getId();
boolean isLimitAdTrackingEnabled();
}
-keep public class com.android.installreferrer.** { *; }
-keepclassmembers class com.ironsource.sdk.controller.IronSourceWebView$JSInterface {
public *;
}
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keep public class com.google.android.gms.ads.** {
public *;
}
-keep class com.ironsource.adapters.** { *; }
-dontwarn com.ironsource.mediationsdk.**
-dontwarn com.ironsource.adapters.**
-keepattributes JavascriptInterface
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
-keep class com.bytedance.sdk.** { *; }
-keep class com.pgl.sys.ces.* { *; }
-keep class com.facebook.** { *; }
-keep class com.google.android.play.core.** { *; }
-keep class com.google.games.bridge.** { *; }
-keep class com.google.android.gms.** { *; }
-keep class com.google.android.gms.games.leaderboard.** { *; }
-keep class com.google.android.gms.games.snapshot.** { *; }
-keep class com.google.android.gms.games.achievement.** { *; }
-keep class com.google.android.gms.games.event.** { *; }
-keep class com.google.android.gms.games.stats.** { *; }
-keep class com.google.android.gms.games.video.** { *; }
-keep class com.google.android.gms.games.* { *; }
-keep class com.google.android.gms.common.api.ResultCallback { *; }
-keep class com.google.android.gms.signin.** { *; }
-keep class com.google.android.gms.dynamic.** { *; }
-keep class com.google.android.gms.dynamite.** { *; }
-keep class com.google.android.gms.tasks.** { *; }
-keep class com.google.android.gms.security.** { *; }
-keep class com.google.android.gms.base.** { *; }
-keep class com.google.android.gms.actions.** { *; }
-keep class com.google.android.gms.common.ConnectionResult { *; }
-keep class com.google.android.gms.common.GooglePlayServicesUtil { *; }
-keep class com.google.android.gms.common.api.** { *; }
-keep class com.google.android.gms.common.data.DataBufferUtils { *; }
-keep class com.google.android.gms.games.quest.** { *; }
-keep class com.google.android.gms.nearby.** { *; }
-keep class com.pubmatic.sdk.** { *; }
-keep class com.guru.** { *; }
-keep class guru.core.** { *; }
-keep class com.onevcat.uniwebview.* { *; }
-keep class com.iab.omid.* { *; }

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bae923e58d92494697743da9d051e24a
timeCreated: 1704420048

18
Editor/Guru.Editor.asmdef Normal file
View File

@ -0,0 +1,18 @@
{
"name": "Guru.Editor",
"rootNamespace": "",
"references": [
"Guru.Runtime"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 06333683107744765b2aba72701ca0a2
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -13,7 +13,11 @@ namespace Guru
#region 启动服务
public static void StartService()
/// <summary>
/// Adjust启动服务
/// </summary>
/// <param name="fbAppId">MIR 追踪 AppID</param>
public static void StartService(string fbAppId = "")
{
string appToken = GuruSettings.Instance.AdjustSetting.GetAppToken();
if (string.IsNullOrEmpty(appToken))
@ -21,7 +25,7 @@ namespace Guru
Log.E(LOG_TAG, "Adjust没有设置token无法进行初始化");
return;
}
InstallEvent(IPMConfig.FIREBASE_ID, IPMConfig.IPM_DEVICE_ID); // 注入启动参数
AdjustEnvironment environment = GetAdjustEnvironment();
@ -29,6 +33,14 @@ namespace Guru
config.setLogLevel(GetAdjustLogLevel());
config.setDelayStart(DelayTime);
#if UNITY_ANDROID
if (!string.IsNullOrEmpty(fbAppId))
{
config.setFbAppId(fbAppId);
}
#endif
#if UNITY_EDITOR || DEBUG
config.setLogDelegate(log => Log.I(LOG_TAG, log));
config.setEventSuccessDelegate(OnEventSuccessCallback);
@ -360,9 +372,16 @@ namespace Guru
adRevenue.setAdRevenuePlacement(adInfo.Placement);
Adjust.trackAdRevenue(adRevenue);
}
public static string GetAdID()
{
string adid = Adjust.getAdid();
#if UNITY_EDITOR
adid = "adjust_adid_empty_in_editor";
#endif
return adid;
}
}
}

View File

@ -96,7 +96,7 @@ namespace Guru
{
if (_hasGotAdjustId) return;
string adjustId = Adjust.getAdid();
string adjustId = AdjustService.GetAdID();
if (!string.IsNullOrEmpty(adjustId)
&& string.IsNullOrEmpty(IPMConfig.ADJUST_ID))
{

View File

@ -31,8 +31,8 @@ namespace Guru
}
private static void InitializeFirebaseComp()
{
InitCrashlytics();
InitRemoteConfig();
InitCrashlytics(); // 老项目沿用此逻辑
InitRemoteConfig(); // 老项目沿用此逻辑
Analytics.InstallGuruAnalytics(_isDebug); // 初始化Guru自打点
Analytics.InitAnalytics();

View File

@ -5,7 +5,9 @@ namespace Guru
/// </summary>
public partial class GameDefine
{
public static string MACRO_DEBUG = "DEBUG";
public static string MACRO_RELEASE = "RELEASE";
public static string CompanyName = "Guru Fun Game Studio";
public const string MACRO_LOG = "ENABLE_LOG";
public const string MACRO_DEBUG = "DEBUG";
public const string MACRO_RELEASE = "RELEASE";
}
}