使用jenkins打包unity工程

embedded/2024/9/21 13:15:41/
Apache配置
  • 安装:arch arm64 brew install httpd
  • 开启:brew services start httpd
  • 重启:brew services restart httpd
  • 停止:brew services stop httpd
  • 配置文件路径:/opt/homebrew/etc/httpd/httpd.conf,默认监听8080端口,更改端口号后,要重启一下brew services restart httpd
  • SSL文件路径 /opt/homebrew/etc/httpd/extra/httpd-ssl.conf,默认监听 8443,Apache 默认使用 443 端口来处理 HTTPS 请求。由于 1024 以下的端口通常需要超级用户权限才能绑定,因此如果您希望 Apache 在没有 `sudo` 权限的情况下运行,您需要将其配置为使用高于 1024 的端口(如 8443) 
  • 服务器文件存放目录 /opt/homebrew/var/www,把文件放到这个文件夹下,别人可以通过访问ip+port+相对地址访问
Jenkins配置
  • 安装:Jenkins自动打包并部署到远程服务器_jenkins客户端打包好处-CSDN博客
  • 局域网ip访问不了jenkins问题:jenkins局域网无法访问 - 简书
  • 批量删除构建历史:
Jenkins.instance.getItemByFullName(jobName).builds.findAll {it.number <= maxNumber
}.each {it.delete()
}
  • Jenkins的参数一切皆字符串,bool类型参数也是字符串,通过when{expression{return BoolParam.toBoolean()}}判断
  • Unity 访问命令行参数:
  • string[] args = System.Environment.GetCommandLineArgs();    
    //每个空格都是一个参数 比如 -project testPath customParam1:111 customParam2:222
    static string GetSingleCommandlineArgs(string[] args, string key)
    {string value = String.Empty;foreach (var arg in args){Debug.Log("命令行参数:args:" + arg);if (arg.Contains(key)){value = arg;break;}}return value;
    }
  • Unity iOS后处理方法,包括更改Build Phase的顺序:
  • #if UNITY_IOSusing UnityEngine;
    using UnityEditor;
    using UnityEditor.Callbacks;
    using System.IO;
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using AMPSDK.Utils;
    using UnityEditor.iOS.Xcode;
    using UnityEditor.iOS.Xcode.Extensions;namespace EditorBuildTool
    {public static class AviaXCodeSetter{private const string BtApplePayMerchantId = "";private const string UtApplePayMerchantId = "";private const string TeamId = "";private const string AppGroup = "";private const string DeepLinkDomain = "";private const string CrashlyticsShellScriptPhaseName = "Crashlytics Run Script";private const string EmbedAppExtensionsPhaseName = "Embed App Extensions";public static bool IsUploadIpa = false;private static string TrustFrameworkPath => Path.Combine(Application.dataPath, "../Archive/iOS/Trustly");private static string GoogleInfoPlistPath =>Path.Combine(Application.dataPath, "../Archive/iOS/Test/GoogleService-Info.plist");[PostProcessBuild(Int32.MaxValue - 1)]public static void OnPostProcessBuild(BuildTarget target, string path2BuildProject){if (target != BuildTarget.iOS)return;Debug.LogWarning(path2BuildProject);ModifyProjectSettings(path2BuildProject);ModifyPodProjectSettings(path2BuildProject);Process(path2BuildProject);}static void ModifyProjectSettings(string path2BuildProject){string projPath = path2BuildProject + "/Unity-iPhone.xcodeproj/project.pbxproj";PBXProject project = new PBXProject();project.ReadFromFile(projPath);AddNotificationTargets(project, path2BuildProject); //临时屏蔽SubModifyProjectSettings(path2BuildProject, project);File.WriteAllText(projPath, project.WriteToString());}static void AddNotificationTargets(PBXProject pbxProject, string path2BuildProject){string notificationTestPath =Path.Combine(Application.dataPath, "../Archive/iOS/NotificationTest/NotificationService");Directory.CreateDirectory(Path.Combine(path2BuildProject, "NotificationService"));CopyFileToPath(path2BuildProject, $"{notificationTestPath}/Info.plist","NotificationService/Info.plist", pbxProject, true);CopyFileToPath(path2BuildProject, $"{notificationTestPath}/NotificationService.h","NotificationService/NotificationService.h", pbxProject, true);string mPath = CopyFileToPath(path2BuildProject, $"{notificationTestPath}/NotificationService.m","NotificationService/NotificationService.m", pbxProject, true);string guid = pbxProject.AddAppExtension(pbxProject.GetUnityMainTargetGuid(), "NotificationService",$"{Application.identifier}.NotificationServices", "NotificationService/Info.plist");pbxProject.AddFileToBuild(guid, mPath);#region 子模块的build settingpbxProject.SetBuildProperty(guid, "CODE_SIGN_IDENTITY", "Apple Development");pbxProject.SetBuildProperty(guid, "IPHONEOS_DEPLOYMENT_TARGET", "12.0");pbxProject.SetBuildProperty(guid, "ARCHS", "arm64");pbxProject.SetBuildProperty(guid, "GENERATE_INFOPLIST_FILE", "YES");pbxProject.SetBuildProperty(guid, "CURRENT_PROJECT_VERSION", "0");pbxProject.SetBuildProperty(guid, "MARKETING_VERSION", "1.2");pbxProject.SetBuildProperty(guid, "GCC_ENABLE_OBJC_EXCEPTIONS", "YES");pbxProject.SetTeamId(guid, TeamId);pbxProject.AddFrameworkToProject(guid, "UserNotifications.framework", false);CopyFileToPath(path2BuildProject, $"{notificationTestPath}/NotificationService.entitlements","NotificationService/NotificationService.entitlements", pbxProject, true);pbxProject.AddBuildPropertyForConfig(pbxProject.BuildConfigByName(guid, "Debug"),"CODE_SIGN_ENTITLEMENTS", "NotificationService/NotificationService.entitlements");pbxProject.AddBuildPropertyForConfig(pbxProject.BuildConfigByName(guid, "Release"),"CODE_SIGN_ENTITLEMENTS", "NotificationService/NotificationService.entitlements");pbxProject.AddBuildPropertyForConfig(pbxProject.BuildConfigByName(guid, "ReleaseForRunning"),"CODE_SIGN_ENTITLEMENTS", "NotificationService/NotificationService.entitlements");pbxProject.AddBuildPropertyForConfig(pbxProject.BuildConfigByName(guid, "ReleaseForProfiling"),"CODE_SIGN_ENTITLEMENTS", "NotificationService/NotificationService.entitlements");if (IsUploadIpa){pbxProject.SetBuildProperty(guid, "CODE_SIGN_STYLE", "Manual");pbxProject.SetBuildProperty(guid, "CODE_SIGN_IDENTITY[sdk=iphoneos*]", "钥匙串中证书的名字");pbxProject.SetBuildProperty(guid, "CODE_SIGN_IDENTITY", "钥匙串中证书的名字");pbxProject.SetBuildProperty(guid, "PROVISIONING_PROFILE_SPECIFIER", "Unity SDK Demo Provision Notification");}else{pbxProject.SetBuildProperty(guid, "CODE_SIGN_STYLE", "Automatic");}#endregion#region 子模块的entitlementstring relativeEntitlementFilePath = "NotificationService/NotificationService.entitlements";string absoluteEntitlementFilePath = path2BuildProject + "/" + relativeEntitlementFilePath;PlistDocument notifyEntitlement = new PlistDocument();if (!string.IsNullOrEmpty(AppGroup)){pbxProject.AddCapability(guid, PBXCapabilityType.AppGroups);string appGroupPlist = "com.apple.security.application-groups";var appGroupArray = new PlistElementArray();appGroupArray.AddString(AppGroup);notifyEntitlement.root[appGroupPlist] = appGroupArray;}else{AviaLogger.AMPLogWarn("app group 为空");}notifyEntitlement.WriteToFile(absoluteEntitlementFilePath);ModifyEntitlementFile(absoluteEntitlementFilePath);#endregion#region 子模块的info.pliststring plistPath = $"{path2BuildProject}/NotificationService/Info.plist";PlistDocument plist = new PlistDocument();plist.ReadFromString(File.ReadAllText(plistPath));PlistElementDict infoDict = plist.root;PlistElementDict bmDict;if (!infoDict.values.ContainsKey("NSAppTransportSecurity"))bmDict = infoDict.CreateDict("NSAppTransportSecurity");elsebmDict = infoDict.values["NSAppTransportSecurity"].AsDict();bmDict.SetBoolean("NSAllowsArbitraryLoads", true);infoDict.SetString("CFBundleDisplayName", "AviaNotificationServiceExtension");infoDict.SetString("CFBundleVersion", PlayerSettings.iOS.buildNumber);File.WriteAllText(plistPath, plist.WriteToString());#endregion}private static void ModifyPodProjectSettings(string path2BuildProject){string projPath = path2BuildProject + "/Pods/Pods.xcodeproj/project.pbxproj";PBXProject project = new PBXProject();project.ReadFromFile(projPath);SubModifyPodProjectSettings(path2BuildProject, project);File.WriteAllText(projPath, project.WriteToString());}private static string CopyFileToPath(string path2BuildProject, string fileAbsolutePath, string fileReactivePath,PBXProject project = null, bool addToProject = true){string newPath = Path.Combine(path2BuildProject, fileReactivePath);if (File.Exists(fileAbsolutePath)){if (File.Exists(newPath)){File.Delete(newPath);}File.Copy(fileAbsolutePath, newPath);if (addToProject){return project?.AddFile(newPath, fileReactivePath, PBXSourceTree.Source);}}else{Debug.LogWarning("文件不存在:" + fileAbsolutePath);}return "";}private static string CopyDirectoryToPath(string path2BuildProject, string fileAbsolutePath,string fileReactivePath,PBXProject project = null, bool addToProject = true){string newPath = Path.Combine(path2BuildProject, fileReactivePath);if (Directory.Exists(fileAbsolutePath)){if (Directory.Exists(newPath)){Directory.Delete(newPath);}FileUtil.CopyFileOrDirectory(fileAbsolutePath, newPath);if (addToProject){return project?.AddFile(newPath, fileReactivePath, PBXSourceTree.Source);}}else{Debug.LogWarning("文件夹不存在:" + fileAbsolutePath);}return "";}private static void SubModifyPodProjectSettings(string path2BuildProject, PBXProject project){string brainTreeDropInGuid = project.TargetGuidByName("BraintreeDropIn-BraintreeDropIn-Localization");project.SetTeamId(brainTreeDropInGuid, TeamId);string checkoutFrameGuid = project.TargetGuidByName("Frames-Frames");if (!string.IsNullOrEmpty(checkoutFrameGuid)){project.SetTeamId(checkoutFrameGuid, TeamId);}string adyenFrameGuid = project.TargetGuidByName("Adyen-Adyen");if (!string.IsNullOrEmpty(adyenFrameGuid)){project.SetTeamId(adyenFrameGuid, TeamId);string adyenActionFrameGuid = project.TargetGuidByName("Adyen-AdyenActions");project.SetTeamId(adyenActionFrameGuid, TeamId);string adyenCardFrameGuid = project.TargetGuidByName("Adyen-AdyenCard");project.SetTeamId(adyenCardFrameGuid, TeamId);}string awsCoreGuid = project.TargetGuidByName("AWSCore");if (!string.IsNullOrEmpty(awsCoreGuid))project.SetBuildProperty(awsCoreGuid, "IPHONEOS_DEPLOYMENT_TARGET", "12.0");string awsS3Guid = project.TargetGuidByName("AWSS3");if (!string.IsNullOrEmpty(awsS3Guid))project.SetBuildProperty(awsS3Guid, "IPHONEOS_DEPLOYMENT_TARGET", "12.0");string masonryGuid = project.TargetGuidByName("Masonry");if (!string.IsNullOrEmpty(masonryGuid))project.SetBuildProperty(masonryGuid, "IPHONEOS_DEPLOYMENT_TARGET", "12.0");string openUdidGuid = project.TargetGuidByName("OpenUDID");if (!string.IsNullOrEmpty(openUdidGuid))project.SetBuildProperty(openUdidGuid, "IPHONEOS_DEPLOYMENT_TARGET", "12.0");string reachabilityGuid = project.TargetGuidByName("Reachability");if (!string.IsNullOrEmpty(reachabilityGuid))project.SetBuildProperty(reachabilityGuid, "IPHONEOS_DEPLOYMENT_TARGET", "12.0");string uicKeyChainStoreGuid = project.TargetGuidByName("UICKeyChainStore");if (!string.IsNullOrEmpty(uicKeyChainStoreGuid))project.SetBuildProperty(uicKeyChainStoreGuid, "IPHONEOS_DEPLOYMENT_TARGET", "12.0");}private static void SubModifyProjectSettings(string path2BuildProject, PBXProject project){string unityFrameworkTargetGuid = project.GetUnityFrameworkTargetGuid();string unityMainTargetGuid = project.GetUnityMainTargetGuid();string unityProjectGuid = project.ProjectGuid();string iosFolderPath = Path.Combine(Application.dataPath, $"../Archive/iOS/Test");if (!Directory.Exists(iosFolderPath)){Debug.LogError($"haven't found folder:{iosFolderPath}");return;}//var info = new DirectoryInfo(iosFolderPath);//iosFolderPath = info.FullName;// 拷贝Podfile文件到工程//CopyToPath(path2BuildProject, $"{iosFolderPath}/Podfile", "Podfile");// 签名信息(可以没有,打包机上ExportOptions里有配置,但不用打包机的情况下,还是可以加一下的)ps:加了也没关系,还是打包机优先级最高if (!string.IsNullOrEmpty(TeamId))project.SetTeamId(unityMainTargetGuid, TeamId);elseAviaLogger.AMPLogWarn("team id 为空");CopyFileToPath(path2BuildProject, GoogleInfoPlistPath, "GoogleService-Info.plist", project, true);#region 添加frameworkproject.AddFrameworkToProject(unityFrameworkTargetGuid, "AdSupport.framework", false);project.AddFrameworkToProject(unityFrameworkTargetGuid, "AppTrackingTransparency.framework", false);project.AddFrameworkToProject(unityFrameworkTargetGuid, "Photos.framework", false);project.AddFrameworkToProject(unityFrameworkTargetGuid, "UserNotifications.framework", false);// 添加非系统框架,及文件string payFrameworkGuid = CopyDirectoryToPath(path2BuildProject,$"{TrustFrameworkPath}/PayWithMyBank.xcframework","Frameworks/PayWithMyBank.xcframework", project, true);// if (!string.IsNullOrEmpty(payFrameworkGuid))// {//     project.AddFileToEmbedFrameworks(unityIPhoneGUID, payFrameworkGuid);//     project.AddFileToEmbedFrameworks(unityFrameworkGUID, payFrameworkGuid);// }// else// {//     Debug.LogWarning("trust frame work 不存在");// }#endregion#region 调整BuildSettingsproject.SetBuildProperty(unityMainTargetGuid, "CODE_SIGN_IDENTITY", "Apple Development");project.SetBuildProperty(unityMainTargetGuid, "IPHONEOS_DEPLOYMENT_TARGET", "12.0");project.SetBuildProperty(unityFrameworkTargetGuid, "IPHONEOS_DEPLOYMENT_TARGET", "12.0");project.SetBuildProperty(unityProjectGuid, "IPHONEOS_DEPLOYMENT_TARGET", "12.0");project.SetBuildProperty(unityMainTargetGuid, "GCC_C_LANGUAGE_STANDARD", "c99");project.SetBuildProperty(unityFrameworkTargetGuid, "GCC_C_LANGUAGE_STANDARD", "c99");project.SetBuildProperty(unityProjectGuid, "GCC_C_LANGUAGE_STANDARD", "c99");project.SetBuildProperty(unityFrameworkTargetGuid, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "NO");Debug.Log("----------build ipa--------------"+IsUploadIpa);if (IsUploadIpa){project.SetBuildProperty(unityProjectGuid, "CODE_SIGN_STYLE", "Manual");project.SetBuildProperty(unityMainTargetGuid, "CODE_SIGN_STYLE", "Manual");project.SetBuildProperty(unityMainTargetGuid, "CODE_SIGN_IDENTITY[sdk=iphoneos*]", "钥匙串中证书的名字");project.SetBuildProperty(unityMainTargetGuid, "CODE_SIGN_IDENTITY", "钥匙串中证书的名字");project.SetBuildProperty(unityMainTargetGuid, "PROVISIONING_PROFILE_SPECIFIER", "provision 文件的名字,不带后缀");}else{project.SetBuildProperty(unityMainTargetGuid, "CODE_SIGN_STYLE", "Automatic");}var token = project.GetBuildPropertyForAnyConfig(unityProjectGuid, "USYM_UPLOAD_AUTH_TOKEN");if (string.IsNullOrEmpty(token)){token = "FakeToken";}project.SetBuildProperty(unityMainTargetGuid, "USYM_UPLOAD_AUTH_TOKEN", token);project.SetBuildProperty(unityProjectGuid, "USYM_UPLOAD_AUTH_TOKEN", token);project.SetBuildProperty(unityFrameworkTargetGuid, "USYM_UPLOAD_AUTH_TOKEN", token);project.SetBuildProperty(unityMainTargetGuid, "GCC_ENABLE_OBJC_EXCEPTIONS", "YES");project.SetBuildProperty(unityFrameworkTargetGuid, "GCC_ENABLE_OBJC_EXCEPTIONS", "YES");project.SetBuildProperty(unityMainTargetGuid, "ENABLE_BITCODE", "FALSE");project.SetBuildProperty(unityFrameworkTargetGuid, "ENABLE_BITCODE", "FALSE");project.AddBuildProperty(unityProjectGuid, "OTHER_LDFLAGS", "-ObjC -ld_classic");project.SetBuildProperty(unityMainTargetGuid, "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES","YES");project.SetBuildProperty(unityFrameworkTargetGuid, "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES","YES");// entitlements : Apple Pay Keychain ...CopyFileToPath(path2BuildProject, $"{iosFolderPath}/Unity-iPhoneDebug.entitlements","Unity-iPhoneDebug.entitlements", project, true);project.AddBuildPropertyForConfig(project.BuildConfigByName(unityMainTargetGuid, "Debug"),"CODE_SIGN_ENTITLEMENTS", "Unity-iPhoneDebug.entitlements");CopyFileToPath(path2BuildProject, $"{iosFolderPath}/Unity-iPhoneRelease.entitlements","Unity-iPhoneRelease.entitlements", project, true);project.AddBuildPropertyForConfig(project.BuildConfigByName(unityMainTargetGuid, "Release"),"CODE_SIGN_ENTITLEMENTS", "Unity-iPhoneRelease.entitlements");project.AddBuildPropertyForConfig(project.BuildConfigByName(unityMainTargetGuid, "ReleaseForProfiling"),"CODE_SIGN_ENTITLEMENTS", "Unity-iPhoneRelease.entitlements");project.AddBuildPropertyForConfig(project.BuildConfigByName(unityMainTargetGuid, "ReleaseForRunning"),"CODE_SIGN_ENTITLEMENTS", "Unity-iPhoneRelease.entitlements");#endregion// Info.plistAddCapability(project, path2BuildProject);}private static void AddCapability(PBXProject project, string pathToBuiltProject){string target = project.GetUnityMainTargetGuid();// Need Create entitlements#region 修改info.pliststring plistPath = pathToBuiltProject + "/Info.plist";PlistDocument plist = new PlistDocument();plist.ReadFromString(File.ReadAllText(plistPath));PlistElementDict infoDict = plist.root;project.AddCapability(target, PBXCapabilityType.BackgroundModes);PlistElementArray bmArray;if (!infoDict.values.ContainsKey("UIBackgroundModes"))bmArray = infoDict.CreateArray("UIBackgroundModes");elsebmArray = infoDict.values["UIBackgroundModes"].AsArray();bmArray.values.Clear();bmArray.AddString("remote-notification");PlistElementDict bmDict;if (!infoDict.values.ContainsKey("NSAppTransportSecurity"))bmDict = infoDict.CreateDict("NSAppTransportSecurity");elsebmDict = infoDict.values["NSAppTransportSecurity"].AsDict();if (bmDict.values.ContainsKey("NSAllowsArbitraryLoadsInWebContent"))bmDict.values.Remove("NSAllowsArbitraryLoadsInWebContent");if (AviaLogger.IsOpenLog){if (infoDict.values.ContainsKey("UIFileSharingEnabled"))infoDict.values.Remove("UIFileSharingEnabled");infoDict.SetBoolean("UIFileSharingEnabled", true);}infoDict.SetString("NSUserTrackingUsageDescription", "广告追踪权限");infoDict.SetString("NSLocationWhenInUseUsageDescription", "地理位置权限");infoDict.SetString("NSPhotoLibraryUsageDescription", "相册权限");infoDict.SetString("NSCameraUsageDescription", "相机权限");infoDict.SetBoolean("ITSAppUsesNonExemptEncryption", false);infoDict.CreateDict("NSLocationTemporaryUsageDescriptionDictionary").SetString("GetPreciseLocation", "此应用程序需要临时访问您的位置信息以提供更准确的服务。");if (!infoDict.values.ContainsKey("LSApplicationQueriesSchemes"))infoDict.CreateArray("LSApplicationQueriesSchemes").AddString("com.venmo.touch.v2");elseinfoDict.values["LSApplicationQueriesSchemes"].AsArray().AddString("com.venmo.touch.v2");if (!infoDict.values.ContainsKey("CFBundleURLTypes"))infoDict.CreateArray("CFBundleURLTypes").AddDict().CreateArray("CFBundleURLSchemes");elseinfoDict.values["CFBundleURLTypes"].AsArray().AddDict().CreateArray("CFBundleURLSchemes");PlistElementArray urlSchemes =infoDict["CFBundleURLTypes"].AsArray().values[1].AsDict()["CFBundleURLSchemes"].AsArray();urlSchemes.AddString("${PRODUCT_BUNDLE_IDENTIFIER}.payments");urlSchemes.AddString("${PRODUCT_BUNDLE_IDENTIFIER}.trustly");urlSchemes.AddString("${PRODUCT_BUNDLE_IDENTIFIER}.adyenCashApp");urlSchemes.AddString("${PRODUCT_BUNDLE_IDENTIFIER}.afLink");infoDict.SetString("AppIdentifierPrefix", "$(AppIdentifierPrefix)");//infoDict.SetString("CFBundleIdentifier", _bundleId);File.WriteAllText(plistPath, plist.WriteToString());#endregion#region 修改entitlementstring releaseEntitlementFilePath = pathToBuiltProject + "/Unity-iPhoneRelease.entitlements";string absoluteEntitlementFilePath = pathToBuiltProject + "/Unity-iPhoneDebug.entitlements";PlistDocument tempEntitlements = new PlistDocument();string keychainAccessGroups = "keychain-access-groups";var arr = new PlistElementArray();arr.values.Add(new PlistElementString($"$(AppIdentifierPrefix){Application.identifier}"));arr.values.Add(new PlistElementString("$(AppIdentifierPrefix)AviagamesUniqueDevice"));tempEntitlements.root[keychainAccessGroups] = arr;project.AddCapability(target, PBXCapabilityType.InAppPurchase);if (!string.IsNullOrEmpty(BtApplePayMerchantId)){string applePayments = "com.apple.developer.in-app-payments";var payArr = (tempEntitlements.root[applePayments] = new PlistElementArray()) as PlistElementArray;payArr?.values.Add(new PlistElementString(BtApplePayMerchantId));payArr?.values.Add(new PlistElementString(UtApplePayMerchantId));}else{AviaLogger.AMPLogWarn("merchant Id 为空");}string keyPushNotifications = "aps-environment";tempEntitlements.root[keyPushNotifications] = new PlistElementString("development");project.AddCapability(target, PBXCapabilityType.PushNotifications);project.AddCapability(target, PBXCapabilityType.KeychainSharing);project.AddCapability(target, PBXCapabilityType.AccessWiFiInformation);tempEntitlements.root["com.apple.developer.networking.wifi-info"] = new PlistElementBoolean(true);if (!string.IsNullOrEmpty(DeepLinkDomain)){project.AddCapability(target, PBXCapabilityType.AssociatedDomains);var associateDomains = new PlistElementArray();associateDomains.AddString(DeepLinkDomain);tempEntitlements.root["com.apple.developer.associated-domains"] = associateDomains;}else{AviaLogger.AMPLogWarn("deep link 为空");}if (!string.IsNullOrEmpty(AppGroup)){project.AddCapability(target, PBXCapabilityType.AppGroups);string appGroupKey = "com.apple.security.application-groups";var appGroupArr = new PlistElementArray();appGroupArr.values.Add(new PlistElementString(AppGroup));tempEntitlements.root[appGroupKey] = appGroupArr;}else{AviaLogger.AMPLogWarn("app group 为空");}tempEntitlements.WriteToFile(absoluteEntitlementFilePath);tempEntitlements.root[keyPushNotifications] = new PlistElementString("production");tempEntitlements.WriteToFile(releaseEntitlementFilePath);ModifyEntitlementFile(absoluteEntitlementFilePath);#endregion}private static void ModifyEntitlementFile(string absoluteEntitlementFilePath){if (!File.Exists(absoluteEntitlementFilePath)) return;try{StreamReader reader = new StreamReader(absoluteEntitlementFilePath);var content = reader.ReadToEnd().Trim();reader.Close();var needFindString = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";var changeString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" +"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";Debug.Log("entitlement更改之前: " + content);content = content.Replace(needFindString, changeString);Debug.Log("entitlement更改之后: " + content);StreamWriter writer = new StreamWriter(new FileStream(absoluteEntitlementFilePath, FileMode.Create));writer.WriteLine(content);writer.Flush();writer.Close();}catch (Exception e){Debug.Log("ModifyEntitlementFile - Failed: " + e.Message);}}#region 修改build phaseprivate static void Process(string path){string projectPath = PBXProject.GetPBXProjectPath(path);PBXProject project = new PBXProject();project.ReadFromFile(projectPath);string mainTargetGuild = project.GetUnityMainTargetGuid();//获取所有的build phase guidstring[] buildPhases = project.GetAllBuildPhasesForTarget(mainTargetGuild);//根据build phase name获取 guidstring crashlyticsShellScriptPhaseGuid =GetBuildPhaseGuid(project, buildPhases, CrashlyticsShellScriptPhaseName);if (string.IsNullOrEmpty(crashlyticsShellScriptPhaseGuid)){DebugLog($"\"{CrashlyticsShellScriptPhaseName}\" phase guid not found.");//return;}string embedAppExtensionsPhaseGuid = GetBuildPhaseGuid(project, buildPhases, EmbedAppExtensionsPhaseName);if (string.IsNullOrEmpty(embedAppExtensionsPhaseGuid)){DebugLog($"\"{EmbedAppExtensionsPhaseName}\" phase guid not found.");//return;}Type projectType = project.GetType();//获取nativeTargets属性PropertyInfo nativeTargetsProperty =projectType.GetProperty("nativeTargets", BindingFlags.NonPublic | BindingFlags.Instance);//获取nativeTargets属性值,是个数组object nativeTargets = nativeTargetsProperty?.GetValue(project);if (nativeTargets == null){DebugLog($"属性'nativeTargets'没找到");return;}DebugLog("nativeTargets 值为:" + nativeTargets);//获取nativeTargets的类Type nativeTargetsType = nativeTargets.GetType();DebugLog("nativeTargets 类名为:" + nativeTargetsType.FullName);//获取nativeTargets的类的索引器方法MethodInfo indexerMethod = nativeTargetsType.GetMethod("get_Item");if (indexerMethod == null){DebugLog($"Method 'get_Item' of {nativeTargetsType.FullName} type not found.");return;}//调用nativeTargets的类的索引器方法,参数为target guid,返回为PBXNativeTargetData,也就是target的数据,比如Unity-iPhone、UnityFrameworkobject pbxNativeTargetData = indexerMethod.Invoke(nativeTargets, new object[] { mainTargetGuild });//获取main target(PBXNativeTargetData)的phase 字段,它是GUIDList类型,也就是所有phases的所有GUIDFieldInfo phasesField = pbxNativeTargetData.GetType().GetField("phases");object phases = phasesField?.GetValue(pbxNativeTargetData);//获取GUIDList的m_List private字段FieldInfo listField = phases?.GetType().GetField("m_List", BindingFlags.NonPublic | BindingFlags.Instance);if (!(listField?.GetValue(phases) is List<string> guidList)){DebugLog($"Field 'm_List' not found.");return;}//------下面开始调整顺序,前面只是做校验多一点-------//build phase在xcode中的顺序,就是它在GUIDList中的顺序guidList.Remove(crashlyticsShellScriptPhaseGuid);guidList.Insert(guidList.IndexOf(embedAppExtensionsPhaseGuid) + 1, crashlyticsShellScriptPhaseGuid);DebugLog($"Insert {CrashlyticsShellScriptPhaseName} phase {crashlyticsShellScriptPhaseGuid} after {EmbedAppExtensionsPhaseName} phase {embedAppExtensionsPhaseGuid}");project.WriteToFile(projectPath);void DebugLog(string message) => Debug.Log($"[更改build phase 顺序] {message}");}/// <summary>/// 根据/// </summary>/// <param name="project"></param>/// <param name="buildPhases"></param>/// <param name="buildPhaseName"></param>/// <returns></returns>static string GetBuildPhaseGuid(PBXProject project, string[] buildPhases, string buildPhaseName){foreach (string buildPhaseGuid in buildPhases){if (project.GetBuildPhaseName(buildPhaseGuid) == buildPhaseName){return buildPhaseGuid;}}return null;}#endregion}
    }
    #endif
 打包命令行
def PROJECT_PATH = "${GIT_PRO_PATH}/${UNITY_PROJECT_NAME}"                                                               
def BUILD_IOS_PATH = "${PROJECT_PATH}/BuildTool/buildios.sh"                                   
def XCODE_ARCHIVE_NAME = 'unity_sdk.xcarchive'
def XCODE_ARCHIVE_PROJECT_PATH = "${IPA_PATH}/../archive_proj/${XCODE_ARCHIVE_NAME}"
def XCODE_BUILD_PROJECT_PATH = "${IPA_PATH}/../xcode_proj"
def PACKAGE_SHARE_PATH = "/opt/homebrew/var/www/unity_sdk_output"
def UNITY_LOG_FILE = "${PROJECT_PATH}/Logs/unity_sdk_log.txt"
def ARCHIVE_LOG_FILE = "${PROJECT_PATH}/Logs/archive.txt"
def SHARE_URL = "http://10.240.0.216:8090/unity_sdk_output"
def BUNDLE_NUM_FILE="${PROJECT_PATH}/Archive/Setting/BuildVersion.user"
def FAIRGUARD = "${PROJECT_PATH}/BuildTool/FairGuard_iOS_3.3.4/fairguardbuild"
def user
node {//需要安装插件 build var userwrap([$class: 'BuildUser']) {user = env.BUILD_USER_ID}
}
pipeline {agent anyoptions {//lock(label: 'DevLock', quantity: 1)            disableConcurrentBuilds()timeout(time: 45, unit: 'MINUTES')}environment {BUILD_TIMESTAMP = sh(script: 'echo $(date +"%Y_%m_%d-%H_%M_%S")', returnStdout: true).trim()TEST_VALUE = "${Test}" }stages {stage('git拉取代码更新') {steps {sh """cd ${GIT_PRO_PATH}git clean -fdgit stash push ${BUNDLE_NUM_FILE}git reset --hard HEAD git stash popgit checkout ${BRANCH}git clean -fdgit pull --force git submodule foreach --recursive 'git reset HEAD . || :'git submodule foreach --recursive 'git checkout -- . || :'git submodule update --init --recursivegit submodule foreach --recursive git clean -d -f -f -x"""}}stage('生成共享地址') {steps{sh """rm -rf ${PACKAGE_SHARE_PATH}/${BUILD_TIMESTAMP}mkdir ${PACKAGE_SHARE_PATH}/${BUILD_TIMESTAMP}echo ${PACKAGE_SHARE_PATH}/${BUILD_TIMESTAMP}"""}}stage('Unity打包') {when{expression{return IS_BUILD_IPA.toBoolean()}//expression{return false}}steps {sh """set -e${UNITY_2020_3_33} -projectPath $PROJECT_PATH -executeMethod BuildTools.BuildIOS  xcodeProjectPath:${XCODE_BUILD_PROJECT_PATH} env:${ENV} isUploadIpa:${IS_UPLOAD_IPA}  -quit -batchmode -logFile ${UNITY_LOG_FILE} 2>&1 | tee ${UNITY_LOG_FILE} -buildTarget iOScp ${UNITY_LOG_FILE} ${PACKAGE_SHARE_PATH}/${BUILD_TIMESTAMP}/unity_sdk_log.txt"""}}stage('Xcode工程 Clean') {when{expression{return IS_BUILD_IPA.toBoolean()}}steps {sh """cd ${XCODE_BUILD_PROJECT_PATH}xcodebuild -workspace Unity-iPhone.xcworkspace -scheme "Unity-iPhone" clean"""                    }}stage('XCODE加固') {when{expression{return false}}steps {script {if("${jiagu}" == 'true'){XCODE_BUILD_PATH = "${XCODE_DIR_PATH}/BuildSuccess"sh """ ${FAIRGUARD} -p ${XCODE_DIR_PATH}/Unity-iPhone.xcworkspace -s Unity-iPhonemv ${XCODE_BUILD_PATH}/RTB-* ${XCODE_BUILD_PATH}/rtb.xcarchive"""}}}}stage('Xcode工程 Archive') {when{expression{return IS_BUILD_IPA.toBoolean()}//expression{return false}}steps {sh """set -ecd ${XCODE_BUILD_PROJECT_PATH}  rm -f ${ARCHIVE_LOG_FILE}rm -rf ${XCODE_ARCHIVE_PROJECT_PATH}xcodebuild archive -workspace Unity-iPhone.xcworkspace -scheme "Unity-iPhone" -configuration "Release" -archivePath "${XCODE_ARCHIVE_PROJECT_PATH}" -destination "generic/platform=iOS" -allowProvisioningUpdates -allowProvisioningDeviceRegistration | tee ${ARCHIVE_LOG_FILE}  2>&1 cp ${ARCHIVE_LOG_FILE} ${PACKAGE_SHARE_PATH}/${BUILD_TIMESTAMP}/Archive.txtcat ${PACKAGE_SHARE_PATH}/${BUILD_TIMESTAMP}/Archive.txt"""}}stage('Xcode工程 Export') {when{expression{return IS_BUILD_IPA.toBoolean()}//expression{return false}}steps {script{def exportionPlistif (IS_UPLOAD_IPA.toBoolean()) {exportionPlist = "${PROJECT_PATH}/BuildTool/ExportOptions_Upload.plist"} else {exportionPlist = "${PROJECT_PATH}/BuildTool/ExportOptions_Dev.plist"}sh """set -ecd ${XCODE_BUILD_PROJECT_PATH} rm -rf "${IPA_PATH}/*"xcodebuild -exportArchive -archivePath  "${XCODE_ARCHIVE_PROJECT_PATH}" -exportPath ${IPA_PATH} -exportOptionsPlist ${exportionPlist} -allowProvisioningUpdates -allowProvisioningDeviceRegistration""" }}}stage('IPA 拷贝') {when{expression{return IS_BUILD_IPA.toBoolean()}//expression{return false}}steps {script{def ipa = sh(script: 'find ${IPA_PATH} -name "*.ipa" -print -quit', returnStdout: true).trim()sh """echo "${ipa}"cp ${ipa} "${PACKAGE_SHARE_PATH}/${BUILD_TIMESTAMP}/""""}}}stage('IPA 上传TestFlight') {when{//expression{return IS_UPLOAD_IPA.toBoolean()}expression{return false}}steps {script{def sharePath= "${PACKAGE_SHARE_PATH}/${BUILD_TIMESTAMP}"echo "${sharePath}"def ipa = sh(script: "find '${sharePath}' -name '*.ipa' -print -quit", returnStdout: true).trim()sh """ set -excrun altool --validate-app --type ios -f ${ipa} -u zhangruiguo@aviagames.com -p faoy-vcit-xyub-wqmr --verbose | tee "${PACKAGE_SHARE_PATH}/${BUILD_TIMESTAMP}/validate_log.txt"if !xcrun altool --upload-app --type ios -f ${ipa} -u zhangruiguo@aviagames.com -p faoy-vcit-xyub-wqmr --verbose | tee "${PACKAGE_SHARE_PATH}/${BUILD_TIMESTAMP}/upload_log.txt"; thenecho "上传TestFlight失败"exit 1fi""" }}}}post {always {echo "用户信息:${user}"}success{echo "构建成功"script{def ipa = sh(script: "find '${PACKAGE_SHARE_PATH}/${BUILD_TIMESTAMP}' -name '*.ipa' -print -quit", returnStdout: true).trim()def ipaUrl = sh(script: "echo '${ipa}' | sed 's|^${PACKAGE_SHARE_PATH}|${SHARE_URL}|'", returnStdout: true).trim()def BUNDLE_NUM=sh(script:"cat ${BUNDLE_NUM_FILE}", returnStdout: true).trim()sh """curl -X POST -H "Content-Type: application/json" \-d '{"msg_type": "post","content": {"post": {"zh_cn": {"title": "构建成功","content": [[{"tag":"a", "text":"包体地址","href":"${ipaUrl}"}],[{"tag":"text", "text":"构建环境:${ENV}   版本号[1.2(${BUNDLE_NUM})]"}],[{"tag":"text", "text":"构建人:${user}"}]]}}}}' \https地址"""}   }failure {echo "构建失败"script{sh """curl -X POST -H "Content-Type: application/json" \-d '{"msg_type": "post","content": {"post": {"zh_cn": {"title": "构建失败","content": [[{"tag":"a", "text":"失败详情","href":"${env.BUILD_URL}/console"}],[{"tag":"text", "text":"构建环境:${ENV}   版本号[1.2(${BUNDLE_NUM})]"}],[{"tag":"text", "text":"构建人:${user}"}]]}}}}' \https地址"""}   }}
}
xcode

ExportOptions.plist文件的作用,就是在export包时的配置,这里面可以配置成导出后,并上传到TestFlight,就不用再单独上传了

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict><!-- 如果不上传,设为export --><key>destination</key><string>upload</string><key>generateAppStoreInformation</key><false/><key>manageAppVersionAndBuildNumber</key><true/><key>method</key><!-- 如果不上传,设为app-store/ad-hoc/enterprise --><string>app-store-connect</string><key>provisioningProfiles</key><dict><key>包的bundle id</key><string>provision名字</string><key>内嵌包的bundle id</key><string>provision名字</string></dict><key>signingStyle</key><string>manual</string><key>stripSwiftSymbols</key><true/><key>teamID</key><string></string><key>testFlightInternalTestingOnly</key><false/><!-- 如果不上传,设为false --><key>uploadSymbols</key><true/>
</dict>
</plist>
 Groovy语法


jenkins的bool类型参数,在groovy里面是字符串,如果要判断,使用BoolParam.toBoolean()

✅ when{expression{return BoolParam.toBoolean()}}表示该阶段执不执行
✅def 变量赋值需要双引号"",比如def ttt="${test}"
✅sh"""  ""","""  """表示可写多行shell,且shell中不能定义变量,需要在script{}里面通过def定义变量,然后在sh里面通过${}引用
✅script里面的脚本,通过双引号包裹命令,单引号引用变量方式
比如 def ipa = sh(script: "find '${sharePath}' -name '*.ipa' -print -quit", returnStdout: true).trim()
unity_sdk.xcarchive 是个文件夹,删除用rm -rf
✅git update-index --assume-unchanged <file> 对本地文件忽略跟踪,比如分支上有这个文件,但是忽略本地的跟踪,但是git reset --hard HEAD 之后,还是会更改,所以先stash 再pop


http://www.ppmy.cn/embedded/114598.html

相关文章

Android 增加宏开关控制android.bp

android 全局定义的宏开关控制不同的feature。android 包含c 和 java&#xff0c; java只能通过全局属性作为判断&#xff0c; c&#xff0c;在android.bp中需要通过go语言定义协助&#xff0c;可以参考 Android.bp正确姿势添加宏控制编译指南_android.bp如何实现控制逻辑-C…

机器学习-点击率预估-论文速读-20240916

1. [经典文章] 特征交叉: Factorization Machines, ICDM, 2010 分解机&#xff08;Factorization Machines&#xff09; 摘要 本文介绍了一种新的模型类——分解机&#xff08;FM&#xff09;&#xff0c;它结合了支持向量机&#xff08;SVM&#xff09;和分解模型的优点。与…

网络协议全景:Linux环境下的TCP/IP、UDP

目录 1.UDP协议解析1.1.定义1.2.UDP报头1.3.特点1.4.缓冲区 2.TCP协议解析2.1.定义2.2.报头解析2.2.1.首部长度&#xff08;4位&#xff09;2.2.2.窗口大小2.2.3.确认应答机制2.2.4.6个标志位 2.3.超时重传机制2.4.三次握手四次挥手2.4.1.全/半连接队列2.4.2.listen2.4.3.TIME_…

设计模式 组合模式(Composite Pattern)

组合模式简绍 组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许你将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户端可以用一致的方式处理单个对象和组合对象。这样&#xff0c;可以在不知道对象具体类型的条…

Redis——常用数据类型set

目录 set普通命令saddsmembers keysismemberspopsrandmemberscardsmovesrem 集合间操作sintersinterstoresunionsunionstoresdiffsdiffstore set的编码方式set的应用 set 谈到set这个术语&#xff0c;可能会有多种含义 集合设置&#xff08;get对应&#xff09; 普通命令 s…

283. 移动零

283. 移动零 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: n…

[ IDE ] SEGGER Embedded Studio for RISC-V

一、FILE 二、Edit 三、View 四、Search 五、Navigate 六、Project 七、Build 7.1 编译 先选择一个目标类型&#xff0c;再选择编译。 八、Debug 九、Target 十、Tools 10.1 自定义快捷键 点击菜单项&#xff0c;通过Tools –> Options –> Keyboard&#xff0c;实现自…

卸载完mathtype后,删除word加载项中的mathtype

请参考博客“卸载完mathtype后&#xff0c;word加载项中还是有mathtype的解决方法_怎么删除word加载项里的mathtype-CSDN博客”以及 “安装卸载MathType经验解决MathType DLL找不到的问题——超实用_mathtype dll cannot-CSDN博客” 如果在删除.dotm文件时&#xff0c;删不掉…