使用jenkins打包unity工程

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.mzph.cn/web/53293.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux 基础(一)mkdir、ls、vi、ifconfig

1、linux简介 linux是一个操作系统&#xff08;os: operating system&#xff09; 中国有没有自己的操作系统&#xff08;华为鸿蒙HarmonyOS&#xff0c;阿里龙蜥(Anolis) OS 8、百度DuerOS都有&#xff09; 计算机组的组成&#xff1a;硬件软件 硬件&#xff1a;运算器&am…

数据结构和算法之树形结构(1)

文章出处: 数据结构和算法之树形结构(1) 关注码农爱刷题&#xff0c;看更多技术文章&#xff01;&#xff01; 树形结构是数据结构四种逻辑结构之一&#xff0c;也是被广泛使用的一种逻辑结构&#xff0c;它描述的是数据元素之间一对多的逻辑关系。树是一种非线性的数据结构&a…

初识模版!!

初识模版 1.泛型编程1.1 如何实现一个交换函数呢&#xff08;使得所有数据都可以交换&#xff09;&#xff1f;1.2 那可以不可以让编译器根据不同的类型利用该模子来生成代码呢&#xff1f; 2.模版类型2.1 模版概念2.2 函数模版的原理2.3 函数模板的实例化2.4 模板参数的匹配原…

如何优化前端页面的 AJAX 请求性能并避免冲突

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119@qq.com] 📱个人微信:15279484656 🌐个人导航网站:www.forff.top 💡座右铭:总有人要赢。为什么不能是我呢? 专栏导…

开源 AI 智能名片 S2B2C 商城小程序与正能量融入对社群归属感的影响

摘要&#xff1a;本文探讨了开源 AI 智能名片 S2B2C 商城小程序在社群运营中的作用&#xff0c;以及融入正能量对提高社群归属感的关键意义。通过分析正能量的精神感染力和对社群氛围的积极影响&#xff0c;阐述了在开源 AI 智能名片 S2B2C 商城小程序的各类活动中融入正能量的…

flask项目初始化

1、初始环境 python3.8 2、flask文档地址&#xff1a;https://flask.palletsprojects.com/en/latest/installation/#install-flask 3、初始化项目 $ mkdir myproject $ cd myproject $ python3 -m venv .venv $ . .venv/bin/activate $ pip install Flask4、打开项目mypr…

Ansible——Playbook基本功能???

文章目录 一、Ansible Playbook介绍1、Playbook的简单组成1&#xff09;“play”2&#xff09;“task”3&#xff09;“playbook” 2、Playbook与ad-hoc简单对比区别联系 3、YAML文件语法&#xff1a;---以及多个---&#xff1f;&#xff1f;使用 include 指令 1. 基本结构2. 数…

java后端字节一面

1. 我现在和你进行视频通话&#xff0c;这个是怎么做的&#xff1f; 视频通话通常基于实时通信技术&#xff08;RTC&#xff09;&#xff0c;如WebRTC。它利用现代浏览器的API来实现视频、音频和数据的直接P2P&#xff08;点对点&#xff09;通信&#xff0c;或通过服务器中转。…

【JavaEE】IP协议 应用层协议

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【Java】登神长阶 史诗般的Java成神之路 &#x1f576;️一.IP地址 IP协议&#xff08;Internet Protocol&#xff09;是TCP/IP协议族中最核心的协议之一&#xff0c;它定义了数据包在网络中传输的标准…

应用层协议HTTP介绍

一、HTTP协议介绍 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一个至关重要的协议。它定义了客户端&#xff08;如浏览器&#xff09;与服务器之间如何通信&#xff0c;以交换或传输超文本。 超文本&#xff1a;视频&#xff0c;音…

24年蓝桥杯及攻防世界赛题-MISC-1

2 What-is-this AZADI TOWER 3 Avatar 题目 一个恐怖份子上传了这张照片到社交网络。里面藏了什么信息?隐藏内容即flag 解题 ┌──(holyeyes㉿kali2023)-[~/Misc/tool-misc/outguess] └─$ outguess -r 035bfaa85410429495786d8ea6ecd296.jpg flag1.txt Reading 035bf…

如何使用命令行快速下载Google Drive/OneDrive大文件

OneDrive OneDrive使用wget下载会出现403 forbidden&#xff0c;可通过下面方法下载。 浏览器右键进入检查界面&#xff0c;选择netowork&#xff0c;搜索download.aspx&#xff0c;然后在待下载文件处点击下载&#xff0c;即可出现下载链接&#xff0c;复制为cURL即可下载。…

日志收集工具 Fluentd vs Fluent Bit 的区别

参考链接&#xff1a; FluentdFluentd BitFluentd & Fluent Bit | Fluent Bit: Official Manual Fluentd 与 Fluent Bit 两者都是生产级遥测生态系统&#xff01; 遥测数据处理可能很复杂&#xff0c;尤其是在大规模处理时。这就是创建 Fluentd 的原因。 Fluentd 不仅仅是…

jenkins声明式流水线语法详解

最基本的语法包含 pipeline&#xff1a;所有有效的声明式流水线必须包含在一个 pipeline 块中stages&#xff1a;包含一系列一个或多个stage指令stage&#xff1a;stage包含在stages中进行&#xff0c;比如某个阶段steps&#xff1a;在阶段中具体得执行操作&#xff0c;一个或…

React js Router 路由 2, (把写过的几个 app 组合起来)

完整的项目&#xff0c;我已经上传了&#xff0c;资源链接. 起因&#xff0c; 目的: 每次都是新建一个 react 项目&#xff0c;有点繁琐。 刚刚学了路由&#xff0c;不如写一个 大一点的 app &#xff0c;把前面写过的几个 app, 都包含进去。 这部分感觉就像是&#xff0c; …

[ 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;实现自…

Java | Leetcode Java题解之第413题等差数列划分

题目&#xff1a; 题解&#xff1a; class Solution {public int numberOfArithmeticSlices(int[] nums) {int n nums.length;if (n 1) {return 0;}int d nums[0] - nums[1], t 0;int ans 0;// 因为等差数列的长度至少为 3&#xff0c;所以可以从 i2 开始枚举for (int i …

安卓13设置动态显示隐藏第一页的某一项 动态显示隐藏无障碍 android13设置动态显示隐藏第一页的某一项

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改4.1修改方法14.2修改方法25.编译6.彩蛋1.前言 有时候,我们的设置里面显示的信息,需要根据不同的情况显示不同的信息,例如,动态的显示或者隐藏 “无障碍” 这一项。 2.问题分析 像这个问题…

英集芯IP5902:集成电压可调异步升压转换充电管理功能的8位MCU芯片

英集芯IP5902是一款集成了9V异步升压转换、锂电池充电管理及负端NMOS管的8-bit MCU芯片&#xff0c;外壳采用了SOP16封装形式&#xff0c;高集成度和丰富的功能使其在应用时只需很少的外围器件&#xff0c;就能有效减小整体方案的尺寸&#xff0c;降低BOM成本&#xff0c;为小型…

Day69补 前后端分离思想

ajax前后端分离 前后端分离处理&#xff1a;前端------&#xff08;数据&#xff09;-----服务端----&#xff08;数据&#xff09;-----前端-----动态改变页面的内容 1.json 1、JSON&#xff1a;由于JSON易读以及纯文本格式的特性&#xff0c;可以非常容易地与其他程序进行沟通…