├── .gitignore ├── Editor.meta ├── Editor ├── AssetBundleBrowser.meta ├── AssetBundleBrowser │ ├── AssetBundleBrowserWrapper.cs │ ├── AssetBundleBrowserWrapper.cs.meta │ ├── AssetBundleBuilder.cs │ └── AssetBundleBuilder.cs.meta ├── BuildConfig.cs ├── BuildConfig.cs.meta ├── JenkinsBuilder.cs ├── JenkinsBuilder.cs.meta ├── JenkinsBuilderWindow.cs ├── JenkinsBuilderWindow.cs.meta ├── JenkinsBuilder_Android.cs ├── JenkinsBuilder_Android.cs.meta ├── JenkinsBuilder_IOS.cs ├── JenkinsBuilder_IOS.cs.meta ├── KorStrix.JenkinsBuilder.Editor.asmdef └── KorStrix.JenkinsBuilder.Editor.asmdef.meta ├── GithubImage.meta ├── GithubImage ├── Jenkins_BuildConfig.png ├── Jenkins_BuildConfig.png.meta ├── Jenkins_BuildConfig_Android.png ├── Jenkins_BuildConfig_Android.png.meta ├── Jenkins_BuildConfig_iOS.png ├── Jenkins_BuildConfig_iOS.png.meta ├── Jenkins_EditorWindow.png └── Jenkins_EditorWindow.png.meta ├── IOS_Shell.meta ├── IOS_Shell ├── ios_export_ipa.sh ├── ios_export_ipa.sh.meta ├── ipa_send_appstore.sh └── ipa_send_appstore.sh.meta ├── LICENSE ├── LICENSE.meta ├── README.md ├── README.md.meta ├── Shell.meta ├── Shell ├── UploadFTP.sh ├── UploadFTP.sh.meta ├── VersionHandler.sh └── VersionHandler.sh.meta ├── package.json └── package.json.meta /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Asset meta data should only be ignored when the corresponding asset is also ignored 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | *.mdb 43 | *.opendb 44 | *.VC.db 45 | 46 | # Unity3D generated meta files 47 | *.pidb.meta 48 | *.pdb.meta 49 | *.mdb.meta 50 | 51 | # Unity3D generated file on crash reports 52 | sysinfo.txt 53 | 54 | # Builds 55 | *.apk 56 | *.unitypackage 57 | 58 | # Crashlytics generated file 59 | crashlytics-build.properties 60 | 61 | .UnityProject/Library/ 62 | .UnityProject/Temp/ 63 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 82c4633b1244f764bb2ec85d819cadd1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/AssetBundleBrowser.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f3ff2370f04644c43ad192da5b08deb7 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/AssetBundleBrowser/AssetBundleBrowserWrapper.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | /* ============================================ 3 | * Author : Strix 4 | * Initial Creation Date : 2020-04-10 5 | * Summary : 6 | * Template : For Unity Editor V1 7 | ============================================ */ 8 | #endregion Header 9 | 10 | using UnityEngine; 11 | using System.Reflection; 12 | using UnityEditor; 13 | 14 | #if ASSET_BUNDLE_BROWSER 15 | using AssetBundleBrowser; 16 | #endif 17 | 18 | 19 | /// 20 | /// 21 | /// 22 | public class AssetBundleBrowserWrapper 23 | { 24 | /* const & readonly declaration */ 25 | 26 | /* enum & struct declaration */ 27 | 28 | /* public - Field declaration */ 29 | 30 | 31 | /* protected & private - Field declaration */ 32 | 33 | #if ASSET_BUNDLE_BROWSER 34 | AssetBundleBrowserMain _pBrowser; 35 | #endif 36 | 37 | System.Type _pBrowserType; 38 | 39 | FieldInfo _pField_BuildTab; 40 | FieldInfo _pField_BuildTab_UserData; 41 | FieldInfo _pField_BuildTab_UserData_BuildTarget; 42 | 43 | private object _pInstance_BuildTab; 44 | private object _pInstance_UserData; 45 | 46 | MethodInfo _pMethod_Build; 47 | 48 | // ========================================================================== // 49 | 50 | /* public - [Do~Something] Function */ 51 | 52 | public AssetBundleBrowserWrapper() 53 | { 54 | #if ASSET_BUNDLE_BROWSER 55 | _pBrowser = AssetBundleBrowserMain.GetWindow(); 56 | _pBrowserType = _pBrowser.GetType(); 57 | 58 | _pField_BuildTab = _pBrowserType.GetField("m_BuildTab", BindingFlags.NonPublic | BindingFlags.Instance); 59 | _pInstance_BuildTab = _pField_BuildTab.GetValue(_pBrowser); 60 | 61 | _pField_BuildTab_UserData = _pField_BuildTab.FieldType.GetField("m_UserData", BindingFlags.NonPublic | BindingFlags.Instance); 62 | _pInstance_UserData = _pField_BuildTab_UserData.GetValue(_pInstance_BuildTab); 63 | 64 | _pField_BuildTab_UserData_BuildTarget = _pField_BuildTab_UserData.FieldType.GetField("m_BuildTarget", BindingFlags.NonPublic | BindingFlags.Instance); 65 | 66 | _pMethod_Build = _pField_BuildTab.FieldType.GetMethod("ExecuteBuild", BindingFlags.NonPublic | BindingFlags.Instance); 67 | #endif 68 | } 69 | 70 | public void DoBuildBundle(BuildTarget eBuildTarget) 71 | { 72 | _pField_BuildTab_UserData_BuildTarget.SetValue(_pInstance_UserData, (int)eBuildTarget); 73 | 74 | UnityEngine.Debug.Log($"!@#$ Start Build Bundle \n" + 75 | $"Current Platform : {Application.platform} Target : {_pField_BuildTab_UserData_BuildTarget.GetValue(_pInstance_UserData)} \n" + 76 | $"Symbol : {PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup)} \n"); 77 | 78 | #if ASSET_BUNDLE_BROWSER 79 | _pMethod_Build?.Invoke(_pField_BuildTab.GetValue(_pBrowser), null); 80 | _pBrowser.Close(); 81 | #else 82 | UnityEngine.Debug.Log("!@#$ Use Define Symbol ASSET_BUNDLE_BROWSER"); 83 | #endif 84 | UnityEngine.Debug.Log("!@#$ Finish Build"); 85 | } 86 | 87 | // ========================================================================== // 88 | 89 | /* protected - [Override & Unity API] */ 90 | 91 | 92 | /* protected - [abstract & virtual] */ 93 | 94 | 95 | // ========================================================================== // 96 | 97 | #region Private 98 | 99 | #endregion Private 100 | } 101 | -------------------------------------------------------------------------------- /Editor/AssetBundleBrowser/AssetBundleBrowserWrapper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 477ed728cf2cdf847acde74422cfbac1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/AssetBundleBrowser/AssetBundleBuilder.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | /* ============================================ 3 | * Author : Strix 4 | * Initial Creation Date : 2020-04-10 5 | * Summary : 6 | * Template : For Unity Editor V1 7 | ============================================ */ 8 | #endregion Header 9 | 10 | 11 | using UnityEditor; 12 | 13 | namespace Jenkins 14 | { 15 | /// 16 | /// 17 | /// 18 | public class AssetBundleBuilder 19 | { 20 | /* const & readonly declaration */ 21 | 22 | const string const_strPrefix_ForDebugLog = "!@#$"; 23 | 24 | /* enum & struct declaration */ 25 | 26 | /* public - Field declaration */ 27 | 28 | 29 | /* protected & private - Field declaration */ 30 | 31 | 32 | // ========================================================================== // 33 | 34 | /* public - [Do~Something] Function */ 35 | 36 | 37 | [MenuItem("Tools/Build/BundleBuild Test - Android", priority = 10000)] 38 | public static void Build_Android() 39 | { 40 | AssetBundleBrowserWrapper pWrapper = new AssetBundleBrowserWrapper(); 41 | pWrapper.DoBuildBundle(BuildTarget.Android); 42 | } 43 | 44 | 45 | [MenuItem("Tools/Build/BundleBuild Test - IOS", priority = 10000)] 46 | public static void Build_IOS() 47 | { 48 | AssetBundleBrowserWrapper pWrapper = new AssetBundleBrowserWrapper(); 49 | pWrapper.DoBuildBundle(BuildTarget.iOS); 50 | } 51 | 52 | // ========================================================================== // 53 | 54 | /* protected - [Override & Unity API] */ 55 | 56 | 57 | /* protected - [abstract & virtual] */ 58 | 59 | 60 | // ========================================================================== // 61 | 62 | #region Private 63 | 64 | #endregion Private 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Editor/AssetBundleBrowser/AssetBundleBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b60429b7bf2e9f74cbb4a7438c29bb18 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/BuildConfig.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | /* ============================================ 3 | * Author : Require PlayerPref Key : "Author" 4 | * Initial Creation Date : 2020-05-08 5 | * Summary : 6 | * Template : New Behaviour For Unity Editor V2 7 | ============================================ */ 8 | #endregion Header 9 | 10 | using System; 11 | using UnityEngine; 12 | using UnityEditor; 13 | 14 | namespace Jenkins 15 | { 16 | [Serializable] 17 | public partial class BuildConfig : ScriptableObject 18 | { 19 | /// 20 | /// 출력할 파일 명, 젠킨스에서 -filename (filename:string) 로 설정가능 21 | /// 22 | public string strFileName = "Build"; 23 | 24 | public string strDefineSymbol; 25 | 26 | /// 27 | /// 설치한 디바이스에 표기될 이름 28 | /// 29 | public string strProductName; 30 | 31 | /// 32 | /// 빌드에 포함할 씬들, 확장자는 안쓰셔도 됩니다. 33 | /// 예시) ["Assets/SomethingScene_1", "Assets/SomethingScene_1"] 34 | /// 35 | public string[] arrBuildSceneNames; 36 | 37 | 38 | // 출력할 폴더 및 파일은 Jenkins에서 처리할 예정이였으나, 39 | // IL2CPP의 경우 같은 장소에 빌드해놓으면 더 빠르다는 메뉴얼로 인해 일단 보류 40 | // https://docs.unity3d.com/kr/2020.2/Manual/IL2CPP-OptimizingBuildTimes.html 41 | public string strAbsolute_BuildOutputFolderPath; 42 | 43 | /// 44 | /// 빌드파일 끝에 DateTime을 붙일지 45 | /// 46 | public bool bUse_DateTime_Suffix; 47 | 48 | /// 49 | /// 50 | /// ScriptableObject.CreateInstance 51 | /// 52 | /// Wrapper 53 | /// ScriptableObject 생성시 생성자에 PlayerSettings에서 Get할경우 Unity Exception이 남 54 | /// 55 | public static BuildConfig CreateConfig() 56 | { 57 | BuildConfig pConfig = ScriptableObject.CreateInstance(); 58 | 59 | pConfig.strProductName = PlayerSettings.productName; 60 | pConfig.arrBuildSceneNames = Builder.GetEnabled_EditorScenes(); 61 | 62 | pConfig.strAbsolute_BuildOutputFolderPath = Application.dataPath.Replace("/Assets", "") + "/Build"; 63 | pConfig.bUse_DateTime_Suffix = true; 64 | 65 | pConfig.pAndroidSetting = AndroidSetting.CreateSetting(); 66 | pConfig.pIOSSetting = IOSSetting.CreateSetting(); 67 | 68 | return pConfig; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Editor/BuildConfig.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 83dc1534323151445a0f8c8be8326bb1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/JenkinsBuilder.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | 3 | /* ============================================ 4 | * 작성자 : Strix 5 | * 작성일 : 2019-10-21 오후 6:42:02 6 | * 개요 : 7 | * 8 | * 에디터 폴더에 있어야 정상 동작합니다. 9 | * 10 | * 참고한 원본 코드 링크 11 | * https://slway000.tistory.com/74 12 | * https://smilejsu.tistory.com/1528 13 | ============================================ */ 14 | 15 | #endregion Header 16 | 17 | using UnityEngine; 18 | using System; 19 | using System.IO; 20 | using System.Linq; 21 | 22 | #if UNITY_EDITOR 23 | using System.Collections.Generic; 24 | using UnityEditor; 25 | using UnityEditor.Build.Reporting; 26 | 27 | namespace Jenkins 28 | { 29 | /// 30 | /// 에디터 플레이어 빌드 전 세팅 (빌드 후 되돌리기용) 31 | /// 32 | public class PlayerSetting_Backup 33 | { 34 | public string strDefineSymbol { get; private set; } 35 | public string strProductName { get; private set; } 36 | 37 | public BuildTargetGroup eBuildTargetGroup { get; private set; } 38 | 39 | public PlayerSetting_Backup(BuildTargetGroup eBuildTargetGroup, string strDefineSymbol, string strProductName) 40 | { 41 | this.eBuildTargetGroup = eBuildTargetGroup; 42 | this.strDefineSymbol = strDefineSymbol; 43 | this.strProductName = strProductName; 44 | } 45 | 46 | public void Back_To_Origin() 47 | { 48 | PlayerSettings.SetScriptingDefineSymbolsForGroup(eBuildTargetGroup, strDefineSymbol); 49 | PlayerSettings.productName = strProductName; 50 | } 51 | } 52 | 53 | /// 54 | /// 젠킨스 빌드를 위한 스크립트입니다. 55 | /// 56 | public partial class Builder 57 | { 58 | public const string const_strPrefix_EditorContextMenu = "Tools/Strix/Jenkins Build/"; 59 | const string const_strPrefix_ForDebugLog = "!@#$"; 60 | 61 | public enum ECommandLineList 62 | { 63 | /// 64 | /// 결과물이 나오는 파일 명 65 | /// 66 | filename, 67 | 68 | /// 69 | /// 컨피그 파일이 있는 절대 경로 70 | /// 71 | config_path, 72 | 73 | /// 74 | /// 결과물이 나오는 절대 경로 75 | /// 76 | output_path, 77 | 78 | /// 79 | /// PlayerSetting.android.BundleVersionCode 80 | /// 81 | android_bundle_versioncode, 82 | 83 | /// 84 | /// PlayerSetting.android.Version 85 | /// 86 | android_version, 87 | 88 | /// 89 | /// 스토어에 올라가는 빌드 번호 90 | /// 91 | ios_buildnumber, 92 | 93 | /// 94 | /// 스토어에 올라가는 버전 95 | /// 96 | ios_version, 97 | } 98 | 99 | static readonly IReadOnlyDictionary mapCommandLine = 100 | new Dictionary() 101 | { 102 | {ECommandLineList.filename, "-filename"}, 103 | {ECommandLineList.config_path, "-config_path"}, 104 | {ECommandLineList.output_path, "-output_path"}, 105 | {ECommandLineList.android_bundle_versioncode, "-android_versioncode"}, 106 | {ECommandLineList.android_version, "-android_version"}, 107 | {ECommandLineList.ios_buildnumber, "-ios_buildnumber"}, 108 | {ECommandLineList.ios_version, "-ios_version"} 109 | }; 110 | 111 | public static string GetCommandLineString(ECommandLineList eCommandLine) => mapCommandLine[eCommandLine]; 112 | 113 | private static BuildConfig g_pLastConfig; 114 | 115 | 116 | [MenuItem(const_strPrefix_EditorContextMenu + "Create BuildConfig Example Json File")] 117 | public static void Create_BuildConfig_Dummy_Json() 118 | { 119 | string strContent = JsonUtility.ToJson(BuildConfig.CreateConfig(), true); 120 | string strFilePath = nameof(BuildConfig) + "_Example.json"; 121 | File.WriteAllText(Application.dataPath + "/" + strFilePath, strContent); 122 | 123 | AssetDatabase.Refresh(); 124 | 125 | UnityEngine.Object pJsonFile = AssetDatabase.LoadMainAssetAtPath($"Assets/{strFilePath}"); 126 | 127 | Selection.activeObject = pJsonFile; 128 | Debug.Log("Create BuildConfig Done", pJsonFile); 129 | } 130 | 131 | // SO는 아직 고려중 132 | //[MenuItem(const_strPrefix_EditorContextMenu + "Create BuildConfig Example SO File")] 133 | //public static void Create_BuildConfig_Dummy_SO() 134 | //{ 135 | // BuildConfig pConfig = BuildConfig.CreateConfig(); 136 | // AssetDatabase.CreateAsset(pConfig, $"Assets/{nameof(BuildConfig)} _Example.asset"); 137 | // AssetDatabase.SaveAssets(); 138 | // AssetDatabase.Refresh(); 139 | 140 | // Selection.activeObject = pConfig; 141 | // Debug.Log("Create BuildConfig Done", pConfig); 142 | //} 143 | 144 | #region public 145 | 146 | public static string GetCommandLineArg(string strName) 147 | { 148 | string[] arrArgument = Environment.GetCommandLineArgs(); 149 | for (int i = 0; i < arrArgument.Length; ++i) 150 | { 151 | if (arrArgument[i] == strName && arrArgument.Length > i + 1) 152 | { 153 | return arrArgument[i + 1]; 154 | } 155 | } 156 | 157 | return null; 158 | } 159 | 160 | public static bool GetFile_From_CommandLine(string strCommandLine, out T pOutFile) 161 | where T : new() 162 | { 163 | string strPath = GetCommandLineArg(strCommandLine); 164 | Exception pException = DoTryParsing_JsonFile(strPath, out pOutFile); 165 | if (pException != null) 166 | { 167 | Debug.LogErrorFormat(const_strPrefix_ForDebugLog + " Error - FilePath : {0}, FilePath : {1}\n" + 168 | " Error : {2}", strCommandLine, strPath, pException); 169 | return false; 170 | } 171 | 172 | return true; 173 | } 174 | 175 | public static bool GetFile_From_CommandLine_SO(string strCommandLine, out T pOutFile) 176 | where T : ScriptableObject 177 | { 178 | string strPath = GetCommandLineArg(strCommandLine); 179 | Exception pException = DoTryParsing_JsonFile_SO(strPath, out pOutFile); 180 | if (pException != null) 181 | { 182 | Debug.LogErrorFormat(const_strPrefix_ForDebugLog + " Error - FilePath : {0}, FilePath : {1}\n" + 183 | " Error : {2}", strCommandLine, strPath, pException); 184 | return false; 185 | } 186 | 187 | return true; 188 | } 189 | 190 | public static void GetAppFilePath_FromConfig(BuildConfig pConfig, out string strBuildOutputFolderPath, 191 | out string strFileName) 192 | { 193 | string strBuildOutputFolderPath_CommandLine = GetCommandLineArg(mapCommandLine[ECommandLineList.output_path]); 194 | string strFileName_CommandLine = GetCommandLineArg(mapCommandLine[ECommandLineList.filename]); 195 | 196 | strBuildOutputFolderPath = string.IsNullOrEmpty(strBuildOutputFolderPath_CommandLine) 197 | ? pConfig.strAbsolute_BuildOutputFolderPath 198 | : strBuildOutputFolderPath_CommandLine; 199 | 200 | if (string.IsNullOrEmpty(strFileName_CommandLine)) 201 | { 202 | strFileName = pConfig.strFileName; 203 | } 204 | else 205 | { 206 | strFileName = strFileName_CommandLine; 207 | pConfig.bUse_DateTime_Suffix = false; 208 | } 209 | } 210 | 211 | 212 | public static Exception DoTryParsing_JsonFile(string strJsonFilePath, out T pOutFile) 213 | where T : new() 214 | { 215 | pOutFile = default(T); 216 | 217 | try 218 | { 219 | string strConfigJson = File.ReadAllText(strJsonFilePath); 220 | pOutFile = JsonUtility.FromJson(strConfigJson); 221 | } 222 | catch (Exception pException) 223 | { 224 | return pException; 225 | } 226 | 227 | return null; 228 | } 229 | 230 | public static Exception DoTryParsing_JsonFile_SO(string strJsonFilePath, out T pOutFile) 231 | where T : ScriptableObject 232 | { 233 | pOutFile = ScriptableObject.CreateInstance(); 234 | 235 | try 236 | { 237 | string strConfigJson = File.ReadAllText(strJsonFilePath); 238 | JsonUtility.FromJsonOverwrite(strConfigJson, pOutFile); 239 | } 240 | catch (Exception pException) 241 | { 242 | pOutFile = null; 243 | return pException; 244 | } 245 | 246 | return null; 247 | } 248 | 249 | public static string[] GetEnabled_EditorScenes() 250 | { 251 | return EditorBuildSettings.scenes. 252 | Where(p => p.enabled). 253 | Select(p => p.path.Replace(".unity", "")). 254 | ToArray(); 255 | } 256 | 257 | 258 | public static void DoBuild(BuildConfig pBuildConfig, string strAbsolute_BuildOutputFolderPath, 259 | string strFileName, BuildTarget eBuildTarget) 260 | { 261 | g_pLastConfig = pBuildConfig; 262 | 263 | Process_PreBuild(pBuildConfig, strAbsolute_BuildOutputFolderPath, strFileName, eBuildTarget, out var eBuildTargetGroup, out var strBuildPath); 264 | 265 | BuildPlayerOptions sBuildPlayerOptions = Generate_BuildPlayerOption(pBuildConfig, eBuildTarget, strBuildPath); 266 | PlayerSetting_Backup pEditorSetting_Backup = SettingBuildConfig_To_EditorSetting(pBuildConfig, eBuildTargetGroup); 267 | 268 | Debug.LogFormat(const_strPrefix_ForDebugLog + " Before Build DefineSymbol TargetGroup : {0}\n" + 269 | "Origin Symbol : {1}\n " + 270 | "Config : {2} \n" + 271 | "Current : {3} \n" + 272 | "strBuildPath : {4}", 273 | eBuildTargetGroup, 274 | pEditorSetting_Backup.strDefineSymbol, 275 | pBuildConfig.strDefineSymbol, 276 | PlayerSettings.GetScriptingDefineSymbolsForGroup(eBuildTargetGroup), 277 | strBuildPath); 278 | 279 | try 280 | { 281 | BuildReport pReport = BuildPipeline.BuildPlayer(sBuildPlayerOptions); 282 | PrintBuildResult(strBuildPath, pReport, pReport.summary); 283 | } 284 | catch (Exception e) 285 | { 286 | Debug.Log(const_strPrefix_ForDebugLog + " Error - " + e); 287 | throw; 288 | } 289 | 290 | pEditorSetting_Backup.Back_To_Origin(); 291 | Process_PostBuild(eBuildTarget, strAbsolute_BuildOutputFolderPath); 292 | 293 | Debug.LogFormat(const_strPrefix_ForDebugLog + " After Build DefineSymbol Current {0}", 294 | PlayerSettings.GetScriptingDefineSymbolsForGroup(eBuildTargetGroup)); 295 | 296 | // 2018.4 에서 프로젝트 전체 리임포팅 하는 이슈 대응 297 | // https://issuetracker.unity3d.com/issues/osx-batchmode-build-hangs-at-refresh-detecting-if-any-assets-need-to-be-imported-or-removed 298 | #if UNITY_EDITOR 299 | AssetDatabase.Refresh(); 300 | #endif 301 | } 302 | 303 | /// 304 | /// Android를 빌드합니다. CommandLine - ConfigPath 필요 305 | /// Command Line으로 실행할 때 partial class file에 있으면 못찾음.. 306 | /// 307 | public static void Build_Android() 308 | { 309 | if (GetFile_From_CommandLine_SO(mapCommandLine[ECommandLineList.config_path], out BuildConfig pConfig)) 310 | { 311 | GetAppFilePath_FromConfig(pConfig, out string strBuildOutputFolderPath, out string strFileName); 312 | DoBuild(pConfig, strBuildOutputFolderPath, strFileName, BuildTarget.Android); 313 | } 314 | } 315 | 316 | /// 317 | /// IOS를 빌드합니다. CommandLine - ConfigPath 필요 318 | /// Command Line으로 실행할 때 partial class file에 있으면 못찾음.. 319 | /// 320 | public static void Build_IOS() 321 | { 322 | if (GetFile_From_CommandLine_SO(mapCommandLine[ECommandLineList.config_path], out BuildConfig pConfig)) 323 | { 324 | GetAppFilePath_FromConfig(pConfig, out string strBuildOutputFolderPath, out string strFileName); 325 | DoBuild(pConfig, strBuildOutputFolderPath, strFileName, BuildTarget.iOS); 326 | } 327 | } 328 | 329 | #endregion public 330 | 331 | // ============================================================================================== 332 | 333 | 334 | #region private 335 | private static BuildPlayerOptions Generate_BuildPlayerOption(BuildConfig pBuildConfig, BuildTarget eBuildTarget, 336 | string strBuildPath) 337 | { 338 | BuildPlayerOptions sBuildPlayerOptions = new BuildPlayerOptions 339 | { 340 | scenes = pBuildConfig.arrBuildSceneNames.Select(p => p += ".unity").ToArray(), 341 | locationPathName = strBuildPath, 342 | target = eBuildTarget, 343 | options = BuildOptions.None 344 | }; 345 | 346 | return sBuildPlayerOptions; 347 | } 348 | 349 | 350 | private static PlayerSetting_Backup SettingBuildConfig_To_EditorSetting(BuildConfig pBuildConfig, 351 | BuildTargetGroup eBuildTargetGroup) 352 | { 353 | string strDefineSymbol_Backup = PlayerSettings.GetScriptingDefineSymbolsForGroup(eBuildTargetGroup); 354 | PlayerSettings.SetScriptingDefineSymbolsForGroup(eBuildTargetGroup, pBuildConfig.strDefineSymbol); 355 | 356 | string strProductName_Backup = PlayerSettings.productName; 357 | PlayerSettings.productName = pBuildConfig.strProductName; 358 | 359 | return new PlayerSetting_Backup(eBuildTargetGroup, strDefineSymbol_Backup, strProductName_Backup); 360 | } 361 | 362 | private static void Process_PreBuild(BuildConfig pBuildConfig, string strAbsolute_BuildOutputFolderPath, 363 | string strFileName, BuildTarget eBuildTarget, out BuildTargetGroup eBuildTargetGroup, 364 | out string strBuildPath) 365 | { 366 | eBuildTargetGroup = GetBuildTargetGroup(eBuildTarget); 367 | strBuildPath = Create_BuildPath(pBuildConfig.bUse_DateTime_Suffix, strAbsolute_BuildOutputFolderPath, 368 | strFileName); 369 | 370 | switch (eBuildTarget) 371 | { 372 | case BuildTarget.Android: 373 | BuildSetting_Android(pBuildConfig.pAndroidSetting); 374 | strBuildPath += ".apk"; 375 | break; 376 | 377 | case BuildTarget.iOS: 378 | BuildSetting_IOS(pBuildConfig.pIOSSetting); 379 | break; 380 | } 381 | } 382 | 383 | private static string Create_BuildPath(bool bUse_DateTime_Suffix, string strFolderName, string strFileName) 384 | { 385 | Debug.LogFormat(const_strPrefix_ForDebugLog + " FolderName : {0}, FileName : {1}", strFolderName, 386 | strFileName); 387 | 388 | try 389 | { 390 | if (Directory.Exists(strFolderName) == false) 391 | Directory.CreateDirectory(strFolderName); 392 | } 393 | catch (Exception e) 394 | { 395 | Debug.Log(const_strPrefix_ForDebugLog + " Error - Create Directory - " + e); 396 | } 397 | 398 | string strBuildPath = strFolderName + "/" + strFileName; 399 | if (bUse_DateTime_Suffix) 400 | { 401 | string strDateTime = DateTime.Now.ToString("MMdd_HHmm"); 402 | strBuildPath = strBuildPath + "_" + strDateTime; 403 | } 404 | 405 | return strBuildPath; 406 | } 407 | 408 | 409 | private static void Process_PostBuild(BuildTarget eBuildTarget, 410 | string strAbsolute_BuildOutputFolderPath) 411 | { 412 | switch (eBuildTarget) 413 | { 414 | case BuildTarget.Android: 415 | 416 | try 417 | { 418 | // Mac OS에서 구동 시 Directory.GetFiles함수는 Error가 나기 때문에 419 | // DirectoryInfo.GetFiles를 통해 체크 420 | DirectoryInfo pDirectory = new DirectoryInfo(strAbsolute_BuildOutputFolderPath); 421 | foreach (var pFile in pDirectory.GetFiles()) 422 | { 423 | // IL2CPP 파일로 빌드 시 자동으로 생inf기는 파일, 삭제해도 무방 424 | if (pFile.Extension == ".zip" && pFile.Name.Contains("symbols")) 425 | { 426 | Debug.Log(const_strPrefix_ForDebugLog + " Delete : " + pFile.Name); 427 | pFile.Delete(); 428 | } 429 | } 430 | } 431 | catch (Exception e) 432 | { 433 | Debug.Log(const_strPrefix_ForDebugLog + " Error - " + e); 434 | } 435 | 436 | break; 437 | } 438 | } 439 | 440 | 441 | private static void PrintBuildResult(string strPath, BuildReport pReport, BuildSummary pSummary) 442 | { 443 | Debug.LogFormat(const_strPrefix_ForDebugLog + " Path : {0}, Build Result : {1}", strPath, pSummary.result); 444 | 445 | if (pSummary.result == BuildResult.Succeeded) 446 | { 447 | Debug.Log(const_strPrefix_ForDebugLog + " Build Succeeded!"); 448 | } 449 | else if (pSummary.result == BuildResult.Failed) 450 | { 451 | int iErrorIndex = 1; 452 | foreach (var pStep in pReport.steps) 453 | { 454 | foreach (var pMessage in pStep.messages) 455 | { 456 | if (pMessage.type == LogType.Error || pMessage.type == LogType.Exception) 457 | { 458 | Debug.LogFormat(const_strPrefix_ForDebugLog + " Build Fail Log[{0}] : type : {1}\n" + 459 | " content : {2}", ++iErrorIndex, pMessage.type, pMessage.content); 460 | } 461 | } 462 | } 463 | } 464 | } 465 | 466 | private static BuildTargetGroup GetBuildTargetGroup(BuildTarget eBuildTarget) 467 | { 468 | switch (eBuildTarget) 469 | { 470 | case BuildTarget.Android: return BuildTargetGroup.Android; 471 | case BuildTarget.iOS: return BuildTargetGroup.iOS; 472 | } 473 | 474 | return BuildTargetGroup.Standalone; 475 | } 476 | 477 | #endregion private 478 | } 479 | } 480 | 481 | #endif 482 | -------------------------------------------------------------------------------- /Editor/JenkinsBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 524e7afbd5eb4070a54244e149dc5149 3 | timeCreated: 1588752966 -------------------------------------------------------------------------------- /Editor/JenkinsBuilderWindow.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | 3 | /* ============================================ 4 | * 작성자 : Strix 5 | * 작성일 : 2019-10-21 오후 6:42:02 6 | * 개요 : 7 | * 8 | * 에디터 폴더에 있어야 정상 동작합니다. 9 | * 10 | * 참고한 원본 코드 링크 11 | * https://slway000.tistory.com/74 12 | * https://smilejsu.tistory.com/1528 13 | ============================================ */ 14 | 15 | #endregion Header 16 | 17 | using UnityEngine; 18 | using System; 19 | using System.IO; 20 | using System.Linq; 21 | using UnityEditor.Callbacks; 22 | 23 | #if UNITY_EDITOR 24 | using UnityEditor; 25 | 26 | namespace Jenkins 27 | { 28 | /// 29 | /// 젠킨스 빌더를 유니티 에디터에서 제어하하는 스크립트입니다. 30 | /// 31 | public class JenkinsBuilderWindow : EditorWindow 32 | { 33 | BuildConfig _pBuildConfig; 34 | 35 | string _strConfigPath; 36 | string _strBuildPath; 37 | 38 | [MenuItem(Builder.const_strPrefix_EditorContextMenu + "Show Builder Window", priority = -10000)] 39 | public static void DoShow_Jenkins_Builder_Window() 40 | { 41 | JenkinsBuilderWindow pWindow = (JenkinsBuilderWindow) GetWindow(typeof(JenkinsBuilderWindow), false); 42 | 43 | pWindow.minSize = new Vector2(600, 200); 44 | pWindow.Show(); 45 | } 46 | 47 | private void OnEnable() 48 | { 49 | _strConfigPath = EditorPrefs.GetString($"{nameof(JenkinsBuilderWindow)}_{nameof(_strConfigPath)}"); 50 | _strBuildPath = EditorPrefs.GetString($"{nameof(JenkinsBuilderWindow)}_{nameof(_strBuildPath)}"); 51 | 52 | CheckConfigPath(); 53 | } 54 | 55 | private void OnGUI() 56 | { 57 | GUILayout.Space(10f); 58 | 59 | EditorGUILayout.HelpBox("이 툴은 BuildConfig를 통해 빌드하는 툴입니다.\n\n" + 60 | "사용방법\n" + 61 | "1. Edit Config Json File을 클릭하여 세팅합니다.\n" + 62 | "2. Edit Build Output Path를 눌러 빌드파일 출력 경로를 세팅합니다.\n" + 63 | "3. 플랫폼(Android or iOS) 빌드를 누릅니다.\n" + 64 | "4. 빌드가 되는지 확인 후, 빌드가 완료되면 Open BuildFolder를 눌러 빌드 파일을 확인합니다." 65 | ,MessageType.Info); 66 | 67 | 68 | if (GUILayout.Button("Github")) 69 | { 70 | System.Diagnostics.Process.Start("https://github.com/KorStrix/Unity_JenkinsBuilder"); 71 | } 72 | GUILayout.Space(30f); 73 | 74 | 75 | EditorGUI.BeginChangeCheck(); 76 | DrawPath_File("Config Json File", ref _strConfigPath, 77 | (strPath) => EditorPrefs.SetString($"{nameof(JenkinsBuilderWindow)}_{nameof(_strConfigPath)}", strPath)); 78 | if (EditorGUI.EndChangeCheck()) 79 | { 80 | CheckConfigPath(); 81 | } 82 | 83 | DrawPath_Folder("Build", ref _strBuildPath, 84 | (strPath) => EditorPrefs.SetString($"{nameof(JenkinsBuilderWindow)}_{nameof(_strBuildPath)}", strPath)); 85 | GUILayout.Space(10f); 86 | 87 | bool bConfigIsNotNull = _pBuildConfig != null; 88 | 89 | GUI.enabled = bConfigIsNotNull; 90 | GUILayout.BeginHorizontal(); 91 | { 92 | if (GUILayout.Button("Android Build !", GUILayout.Height(40f))) 93 | { 94 | Builder.DoBuild(_pBuildConfig, _strBuildPath, _pBuildConfig.strFileName, BuildTarget.Android); 95 | } 96 | 97 | if (GUILayout.Button("iOS Build !", GUILayout.Height(40f))) 98 | { 99 | Builder.DoBuild(_pBuildConfig, _strBuildPath, _pBuildConfig.strFileName, BuildTarget.iOS); 100 | } 101 | } 102 | GUILayout.EndHorizontal(); 103 | GUI.enabled = true; 104 | 105 | if (GUILayout.Button("Open BuildFolder Path !")) 106 | { 107 | System.Diagnostics.Process.Start(_strBuildPath); 108 | } 109 | } 110 | 111 | private string DrawPath_Folder(string strExplainName, ref string strFolderPath, Action OnChangePath) 112 | { 113 | return DrawPath(strExplainName, ref strFolderPath, OnChangePath, true); 114 | } 115 | 116 | private string DrawPath_File(string strExplainName, ref string strFilePath, Action OnChangePath) 117 | { 118 | return DrawPath(strExplainName, ref strFilePath, OnChangePath, false); 119 | } 120 | 121 | private string DrawPath(string strExplainName, ref string strEditPath, Action OnChangePath, bool bIsFolder) 122 | { 123 | GUILayout.BeginHorizontal(); 124 | 125 | if (bIsFolder) 126 | GUILayout.Label($"{strExplainName} Path : ", GUILayout.Width(150f)); 127 | else 128 | GUILayout.Label($"{strExplainName} Path : ", GUILayout.Width(150f)); 129 | 130 | GUI.enabled = false; 131 | GUILayout.TextArea(strEditPath, GUILayout.ExpandWidth(true), GUILayout.Height(40f)); 132 | GUI.enabled = true; 133 | 134 | if (GUILayout.Button($"Edit {strExplainName}", GUILayout.Width(150f))) 135 | { 136 | string strPath = ""; 137 | if (bIsFolder) 138 | strPath = EditorUtility.OpenFolderPanel("Root Folder", "", ""); 139 | else 140 | strPath = EditorUtility.OpenFilePanel("File Path", "", ""); 141 | 142 | strEditPath = strPath; 143 | OnChangePath?.Invoke(strPath); 144 | } 145 | 146 | GUILayout.EndHorizontal(); 147 | 148 | return strEditPath; 149 | } 150 | 151 | private void CheckConfigPath() 152 | { 153 | if (string.IsNullOrEmpty(_strConfigPath)) 154 | return; 155 | 156 | Exception pException = Builder.DoTryParsing_JsonFile_SO(_strConfigPath, out _pBuildConfig); 157 | if (pException != null) 158 | { 159 | _strConfigPath = "!! Error !!" + _strConfigPath; 160 | Debug.LogError($"Json Parsing Fail Path : {_strConfigPath}\n {pException}", this); 161 | } 162 | } 163 | 164 | } 165 | } 166 | 167 | #endif -------------------------------------------------------------------------------- /Editor/JenkinsBuilderWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62ce867b31e61764a84f95b91b51a7d8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/JenkinsBuilder_Android.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | 3 | /* ============================================ 4 | * 작성자 : Strix 5 | * 작성일 : 2019-10-21 오후 6:42:02 6 | * 개요 : 7 | * 8 | * 에디터 폴더에 있어야 정상 동작합니다. 9 | * 10 | * 참고한 원본 코드 링크 11 | * https://slway000.tistory.com/74 12 | * https://smilejsu.tistory.com/1528 13 | ============================================ */ 14 | 15 | #endregion Header 16 | 17 | using UnityEngine; 18 | using System; 19 | 20 | #if UNITY_EDITOR 21 | using UnityEditor; 22 | 23 | namespace Jenkins 24 | { 25 | public partial class BuildConfig 26 | { 27 | [Serializable] 28 | public class AndroidSetting 29 | { 30 | /// 31 | /// 예시) com.CompanyName.ProductName 32 | /// 33 | public string strFullPackageName; 34 | 35 | public string strKeyalias_Name; 36 | public string strKeyalias_Password; 37 | 38 | /// 39 | /// Keystore 파일의 경로입니다. `파일경로/파일명.keystore` 까지 쓰셔야 합니다. 40 | /// UnityProject/Asset/ 기준의 상대 경로입니다. 41 | /// 예를들어 UnityProject/Asset 폴더 밑에 example.keystore를 넣으셨으면 "/example.keystore" 입니다. 42 | /// 43 | public string strKeystore_RelativePath; 44 | public string strKeystore_Password; 45 | 46 | /// 47 | /// CPP 빌드를 할지 체크, CPP빌드는 오래 걸리므로 Test빌드가 아닌 Alpha 빌드부터 하는걸 권장 48 | /// 아직 미지원 49 | /// 50 | public bool bUse_IL_TO_CPP_Build; 51 | 52 | public int iBundleVersionCode; 53 | 54 | public string strVersion; 55 | 56 | 57 | /// 58 | /// ScriptableObject 생성시 생성자에 PlayerSettings에서 Get할경우 Unity Exception이 남 59 | /// 60 | /// 61 | public static AndroidSetting CreateSetting() 62 | { 63 | AndroidSetting pNewSetting = new AndroidSetting(); 64 | 65 | pNewSetting.strFullPackageName = PlayerSettings.applicationIdentifier; 66 | pNewSetting.iBundleVersionCode = PlayerSettings.Android.bundleVersionCode; 67 | pNewSetting.strVersion = PlayerSettings.bundleVersion; 68 | 69 | return pNewSetting; 70 | } 71 | } 72 | 73 | public AndroidSetting pAndroidSetting; 74 | } 75 | 76 | public partial class Builder 77 | { 78 | [MenuItem(const_strPrefix_EditorContextMenu + "Build Test - Android")] 79 | public static void Build_Test_Android() 80 | { 81 | BuildConfig pConfig = BuildConfig.CreateConfig(); 82 | BuildTargetGroup eBuildTargetGroup = GetBuildTargetGroup(BuildTarget.Android); 83 | pConfig.strDefineSymbol = PlayerSettings.GetScriptingDefineSymbolsForGroup(eBuildTargetGroup); 84 | 85 | DoBuild(pConfig, pConfig.strAbsolute_BuildOutputFolderPath, pConfig.strFileName, BuildTarget.Android); 86 | } 87 | 88 | // ============================================================================================== 89 | 90 | 91 | /// 92 | /// 안드로이드 세팅 93 | /// 94 | private static void BuildSetting_Android(BuildConfig.AndroidSetting pSetting) 95 | { 96 | if (string.IsNullOrEmpty(pSetting.strFullPackageName) == false) 97 | PlayerSettings.applicationIdentifier = pSetting.strFullPackageName; 98 | 99 | PlayerSettings.Android.keyaliasName = pSetting.strKeyalias_Name; 100 | PlayerSettings.Android.keyaliasPass = pSetting.strKeyalias_Password; 101 | 102 | PlayerSettings.Android.keystoreName = Application.dataPath + pSetting.strKeystore_RelativePath; 103 | PlayerSettings.Android.keystorePass = pSetting.strKeystore_Password; 104 | 105 | string strBundleVersionCode_FromCommandLine = GetCommandLineArg(mapCommandLine[ECommandLineList.android_bundle_versioncode]); 106 | if(int.TryParse(strBundleVersionCode_FromCommandLine, out int iBundleVersionCode)) 107 | PlayerSettings.Android.bundleVersionCode = iBundleVersionCode; 108 | else 109 | PlayerSettings.Android.bundleVersionCode = pSetting.iBundleVersionCode; 110 | 111 | string strVersionCode_FromCommandLine = GetCommandLineArg(mapCommandLine[ECommandLineList.android_version]); 112 | if (string.IsNullOrEmpty(strVersionCode_FromCommandLine) == false) 113 | PlayerSettings.bundleVersion = strVersionCode_FromCommandLine; 114 | else 115 | PlayerSettings.bundleVersion = pSetting.strVersion; 116 | 117 | // if (pAndroidSetting.bUse_IL_TO_CPP_Build) 118 | // PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, ScriptingImplementation.IL2CPP); 119 | // else 120 | // PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, ScriptingImplementation.Mono2x); 121 | 122 | Debug.LogFormat(const_strPrefix_ForDebugLog + " Build Setting [Android]\n" + 123 | "strPackageName : {0}\n" + 124 | "keyaliasName : {1}, keyaliasPass : {2}\n" + 125 | "keystoreName : {3}, keystorePass : {4}\n" + 126 | "bUse_IL_TO_CPP_Build : {5}", 127 | PlayerSettings.applicationIdentifier, 128 | PlayerSettings.Android.keyaliasName, PlayerSettings.Android.keyaliasPass, 129 | PlayerSettings.Android.keystoreName, PlayerSettings.Android.keystorePass, 130 | pSetting.bUse_IL_TO_CPP_Build); 131 | ; 132 | } 133 | } 134 | } 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /Editor/JenkinsBuilder_Android.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cba2fab4324b48a1879d081f12cfd2ff 3 | timeCreated: 1588752631 -------------------------------------------------------------------------------- /Editor/JenkinsBuilder_IOS.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | 3 | /* ============================================ 4 | * 작성자 : Strix 5 | * 작성일 : 2019-10-21 오후 6:42:02 6 | * 개요 : 7 | * 8 | * 에디터 폴더에 있어야 정상 동작합니다. 9 | * 10 | * 참고한 원본 코드 링크 11 | * https://slway000.tistory.com/74 12 | * https://smilejsu.tistory.com/1528 13 | ============================================ */ 14 | 15 | #endregion Header 16 | 17 | // #define UNITY_IOS // IOS Code Compile Test 18 | 19 | using UnityEngine; 20 | using System; 21 | 22 | #if UNITY_EDITOR 23 | using UnityEditor; 24 | using UnityEditor.Callbacks; 25 | 26 | 27 | 28 | #if UNITY_IOS 29 | using System.Collections.Generic; 30 | using System.IO; 31 | using UnityEditor.iOS.Xcode; 32 | #endif 33 | 34 | namespace Jenkins 35 | { 36 | public partial class BuildConfig 37 | { 38 | /// 39 | /// 유니티 -> XCode Export -> XCode ArchiveBuildConfig -> .ipa 에 필요한 모든 설정 40 | /// 41 | [Serializable] 42 | public class IOSSetting 43 | { 44 | /// 45 | /// 애플 개발자 사이트에서 조회 가능, 숫자랑 영어로 된거 46 | /// 47 | public string strAppleTeamID; 48 | 49 | /// 50 | /// Apple에서 세팅된 net.Company.Product 형식의 string 51 | /// 52 | public string strBundle_Identifier; 53 | public string strEntitlementsFileName_Without_ExtensionName; 54 | 55 | /// 56 | /// 유니티 Asset 경로에서 XCode Project로 카피할 파일 목록, 확장자까지 작성해야 합니다 57 | /// UnityProject/Assets/ 기준 58 | /// 59 | public string[] arrCopy_AssetFilePath_To_XCodeProjectPath; 60 | 61 | /// 62 | /// XCode 프로젝트에 추가할 Framework, 확장자까지 작성해야 합니다 63 | /// 64 | public string[] arrXCode_Framework_Add; 65 | 66 | /// 67 | /// XCode 프로젝트에 제거할 Framework, 확장자까지 작성해야 합니다 68 | /// 69 | public string[] arrXCode_Framework_Remove; 70 | 71 | public string[] arrXCode_OTHER_LDFLAGS_Add; 72 | public string[] arrXCode_OTHER_LDFLAGS_Remove; 73 | 74 | /// 75 | /// HTTP 주소 IOS는 기본적으로 HTTP를 허용 안하기 때문에 예외에 추가해야 합니다. http://는 제외할것 76 | /// 예시) http://www.naver.com = www.naver.com 77 | /// 78 | public string[] arrHTTPAddress; 79 | 80 | /// 81 | /// 출시할 빌드 버전 82 | /// 이미 앱스토어에 올렸으면 그 다음 항상 숫자를 올려야 합니다. 안그럼 앱스토어에서 안받음 83 | /// 84 | public string strBuildVersion; 85 | 86 | /// 87 | /// 빌드 번호 88 | /// 이미 앱스토어에 올렸으면 그 다음 항상 1씩 올려야 합니다. 안그럼 앱스토어에서 안받음 89 | /// 90 | public string strBuildNumber; 91 | 92 | [Serializable] 93 | public class PLIST_ADD 94 | { 95 | public string strKey; 96 | public string strValue; 97 | 98 | public PLIST_ADD(string strKey, string strValue) 99 | { 100 | this.strKey = strKey; 101 | this.strValue = strValue; 102 | } 103 | } 104 | 105 | public PLIST_ADD[] arrAddPlist = new PLIST_ADD[] {new PLIST_ADD("ExampleKey", "ExampleValue")}; 106 | public string[] arrRemovePlistKey = new string[] { "ExampleKey", "ExampleValue" }; 107 | 108 | /// 109 | /// ScriptableObject 생성시 생성자에 PlayerSettings에서 Get할경우 Unity Exception이 남 110 | /// 111 | /// 112 | public static IOSSetting CreateSetting() 113 | { 114 | IOSSetting pNewSetting = new IOSSetting(); 115 | 116 | return pNewSetting; 117 | } 118 | } 119 | 120 | public IOSSetting pIOSSetting; 121 | } 122 | 123 | public partial class Builder 124 | { 125 | public const int const_iPostBuildCallbackOrder = 777; 126 | 127 | [MenuItem(const_strPrefix_EditorContextMenu + "Build Test - IOS")] 128 | // ReSharper disable once UnusedMember.Global 129 | public static void Build_Test_IOS() 130 | { 131 | BuildConfig pConfig = new BuildConfig(); 132 | BuildTargetGroup eBuildTargetGroup = GetBuildTargetGroup(BuildTarget.iOS); 133 | pConfig.strDefineSymbol = PlayerSettings.GetScriptingDefineSymbolsForGroup(eBuildTargetGroup); 134 | 135 | DoBuild(pConfig, pConfig.strAbsolute_BuildOutputFolderPath, pConfig.strFileName, BuildTarget.iOS); 136 | } 137 | 138 | [PostProcessBuild(const_iPostBuildCallbackOrder)] 139 | public static void OnPostProcessBuild(BuildTarget eBuildTarget, string strPath) 140 | { 141 | Debug.Log($"{const_strPrefix_ForDebugLog} {nameof(OnPostProcessBuild)} - BuildTarget : {eBuildTarget} strPath : {strPath}"); 142 | if (eBuildTarget != BuildTarget.iOS) 143 | return; 144 | 145 | Init_XCodeProject(strPath); 146 | Setup_XCodePlist(strPath); 147 | } 148 | 149 | // ============================================================================================== 150 | 151 | /// 152 | /// IOS용 XCode Initialize 153 | /// 154 | // ReSharper disable once UnusedParameter.Local 155 | private static void Init_XCodeProject(string strXCodeProjectPath) 156 | { 157 | #if UNITY_IOS 158 | BuildConfig.IOSSetting pIOSSetting = g_pLastConfig.pIOSSetting; 159 | var projectPath = strXCodeProjectPath + "/Unity-iPhone.xcodeproj/project.pbxproj"; 160 | 161 | Debug.Log($"{const_strPrefix_ForDebugLog} {nameof(Init_XCodeProject)} Start - {nameof(strXCodeProjectPath)} : {strXCodeProjectPath}\n" + 162 | $"projectPath : {projectPath}"); 163 | 164 | PBXProject pPBXProject = new PBXProject(); 165 | pPBXProject.ReadFromFile(projectPath); 166 | 167 | string strTargetGuid = pPBXProject.TargetGuidByName("Unity-iPhone"); 168 | 169 | 170 | // Set Apple Team ID 171 | pPBXProject.SetTeamId(strTargetGuid, pIOSSetting.strAppleTeamID); 172 | 173 | // Copy File Asset To XCode Project 174 | foreach(var strFilePath in pIOSSetting.arrCopy_AssetFilePath_To_XCodeProjectPath) 175 | CopyFile_Asset_To_XCode(strXCodeProjectPath, strFilePath); 176 | 177 | 178 | // Add XCode Framework 179 | foreach (string strFramework in pIOSSetting.arrXCode_Framework_Add) 180 | { 181 | pPBXProject.AddFrameworkToProject(strTargetGuid, strFramework, false); 182 | Debug.Log($"{const_strPrefix_ForDebugLog} Add Framework \"{strFramework}\" to XCode Project"); 183 | } 184 | 185 | 186 | // Remove XCode Framework 187 | foreach (string strFramework in pIOSSetting.arrXCode_Framework_Remove) 188 | { 189 | pPBXProject.RemoveFrameworkFromProject(strTargetGuid, strFramework); 190 | Debug.Log($"{const_strPrefix_ForDebugLog} Remove Framework \"{strFramework}\" to XCode Project"); 191 | } 192 | 193 | 194 | // Set XCode OTHER_LDFLAGS 195 | pPBXProject.UpdateBuildProperty(strTargetGuid, "OTHER_LDFLAGS", pIOSSetting.arrXCode_OTHER_LDFLAGS_Add, pIOSSetting.arrXCode_OTHER_LDFLAGS_Remove); 196 | 197 | #region Sample 198 | // // Sample of setting build property 199 | // project.SetBuildProperty(targetGuid, "ENABLE_BITCODE", "NO"); 200 | 201 | // Sample of setting compile flags 202 | // var guid = pbxProject.FindFileGuidByProjectPath("Classes/UI/Keyboard.mm"); 203 | // var flags = pbxProject.GetCompileFlagsForFile(targetGuid, guid); 204 | // flags.Add("-fno-objc-arc"); 205 | // pbxProject.SetCompileFlagsForFile(targetGuid, guid, flags); 206 | #endregion Sample 207 | 208 | string strTargetEntitlementsFilePath = strXCodeProjectPath + "/" + pIOSSetting.strEntitlementsFileName_Without_ExtensionName + ".entitlements"; 209 | pPBXProject.AddCapability(strTargetGuid, PBXCapabilityType.PushNotifications, strTargetEntitlementsFilePath, true); 210 | pPBXProject.AddCapability(strTargetGuid, PBXCapabilityType.InAppPurchase, null, true); 211 | pPBXProject.AddCapability(strTargetGuid, PBXCapabilityType.GameCenter, null, true); 212 | 213 | pPBXProject.AddBuildProperty(strTargetGuid, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)"); 214 | 215 | SetIOS_AuthToken(pPBXProject, strTargetGuid); 216 | 217 | // Apply settings 218 | File.WriteAllText(projectPath, pPBXProject.WriteToString()); 219 | #else 220 | Debug.Log($"{const_strPrefix_ForDebugLog} {nameof(Init_XCodeProject)} - Define Symbol is Not IOS"); 221 | #endif 222 | } 223 | 224 | #if UNITY_IOS 225 | private static void SetIOS_AuthToken(PBXProject project, string strTargetGuid) 226 | { 227 | var token = project.GetBuildPropertyForAnyConfig(strTargetGuid, "USYM_UPLOAD_AUTH_TOKEN"); 228 | if (string.IsNullOrEmpty(token)) 229 | { 230 | token = "FakeToken"; 231 | } 232 | 233 | project.SetBuildProperty(strTargetGuid, "USYM_UPLOAD_AUTH_TOKEN", token); 234 | } 235 | #endif 236 | 237 | private static void CopyFile_Asset_To_XCode(string strXCodeProjectPath, string strFilePath) 238 | { 239 | string strFileName = strFilePath; 240 | int iLastIndex = strFilePath.LastIndexOf("/"); 241 | if(iLastIndex != -1) 242 | strFileName = strFilePath.Substring(iLastIndex + 1); 243 | 244 | string strFilePath_Origin = Application.dataPath + "/" + strFilePath; 245 | string strFilePath_Dest = strXCodeProjectPath + "/" + strFileName; 246 | 247 | try 248 | { 249 | FileUtil.DeleteFileOrDirectory(strFilePath_Dest); 250 | FileUtil.CopyFileOrDirectory(strFilePath_Origin, strFilePath_Dest); 251 | } 252 | catch (Exception e) 253 | { 254 | Debug.Log($"{const_strPrefix_ForDebugLog} Copy File Error FileName : \"{strFileName}\" // \"{strFilePath_Origin}\" to \"{strFilePath_Dest}\"" + e); 255 | } 256 | 257 | Debug.Log($"{const_strPrefix_ForDebugLog} Copy File FileName : \"{strFileName}\" // \"{strFilePath_Origin}\" to \"{strFilePath_Dest}\""); 258 | } 259 | 260 | // ReSharper disable once UnusedParameter.Local 261 | private static void Setup_XCodePlist(string strXCodeProjectPath) 262 | { 263 | #if UNITY_IOS 264 | Debug.Log($"{const_strPrefix_ForDebugLog} {nameof(Setup_XCodePlist)} Start - {nameof(strXCodeProjectPath)} : {strXCodeProjectPath}"); 265 | BuildConfig.IOSSetting pIOSSetting = g_pLastConfig.pIOSSetting; 266 | 267 | // Property List(.plist) Default Name 268 | const string strInfoPlistName = "Info.plist"; 269 | 270 | var str_plistPath = Path.Combine(strXCodeProjectPath, strInfoPlistName); 271 | var p_plistDocument = new PlistDocument(); 272 | p_plistDocument.ReadFromFile(str_plistPath); 273 | 274 | 275 | 276 | // 해당 키는 IOS 업로드 시 해당 키는 지원하지 않는다는 에러 발생으로 인해 제거 277 | const string strExitsOnSuspendKey = "UIApplicationExitsOnSuspend"; 278 | var arrRootValues = p_plistDocument.root.values; 279 | if(arrRootValues.ContainsKey(strExitsOnSuspendKey)) 280 | arrRootValues.Remove(strExitsOnSuspendKey); 281 | 282 | foreach (var pProperty in pIOSSetting.arrAddPlist) 283 | { 284 | Debug.Log($"{const_strPrefix_ForDebugLog} Add Property - Key : \"{pProperty.strKey}\" Value : {pProperty.strValue}"); 285 | 286 | if (arrRootValues.ContainsKey(pProperty.strKey)) 287 | arrRootValues[pProperty.strKey] = new PlistElementString(pProperty.strValue); 288 | else 289 | arrRootValues.Add(pProperty.strKey, new PlistElementString(pProperty.strValue)); 290 | } 291 | 292 | foreach (string strRemovePropertyKey in pIOSSetting.arrRemovePlistKey) 293 | { 294 | if (arrRootValues.ContainsKey(strRemovePropertyKey)) 295 | { 296 | arrRootValues.Remove(strRemovePropertyKey); 297 | Debug.Log($"{const_strPrefix_ForDebugLog} Contains & Removed Key.Length : {strRemovePropertyKey}"); 298 | } 299 | } 300 | 301 | Debug.Log($"{const_strPrefix_ForDebugLog} pIOSSetting.arrHTTPAddress.Length : \"{pIOSSetting.arrHTTPAddress.Length}\""); 302 | 303 | // HTTP 주소는 Plist에 추가해야 접근 가능.. 304 | if (pIOSSetting.arrHTTPAddress.Length != 0) 305 | { 306 | PlistElementDict pTransportDict = Get_Or_Add_PlistDict(arrRootValues, "NSAppTransportSecurity"); 307 | PlistElementDict pExceptionDomainsDict = Get_Or_Add_PlistDict(pTransportDict.values, "NSExceptionDomains"); 308 | 309 | foreach (string strAddress in pIOSSetting.arrHTTPAddress) 310 | { 311 | Debug.Log($"{const_strPrefix_ForDebugLog} Add HTTPAddress : \"{strAddress}\""); 312 | 313 | PlistElementDict pTransportDomain = Get_Or_Add_PlistDict(pExceptionDomainsDict.values, strAddress); 314 | const string strNSAllowInsecureHTTPLoadsKey = "NSExceptionAllowsInsecureHTTPLoads"; 315 | const string strNSIncludesSubdomains = "NSIncludesSubdomains"; 316 | 317 | 318 | if (pTransportDomain.values.ContainsKey(strNSAllowInsecureHTTPLoadsKey) == false) 319 | pTransportDomain.values.Add(strNSAllowInsecureHTTPLoadsKey, new PlistElementBoolean(true)); 320 | 321 | if (pTransportDomain.values.ContainsKey(strNSIncludesSubdomains) == false) 322 | pTransportDomain.values.Add(strNSIncludesSubdomains, new PlistElementBoolean(true)); 323 | } 324 | } 325 | 326 | // Apply editing settings to Info.plist 327 | p_plistDocument.WriteToFile(str_plistPath); 328 | Debug.Log($"{const_strPrefix_ForDebugLog} {nameof(Setup_XCodePlist)} - WriteToFile {str_plistPath}"); 329 | #else 330 | Debug.Log($"{const_strPrefix_ForDebugLog} {nameof(Setup_XCodePlist)} - Not Define Symbol is Not IOS"); 331 | #endif 332 | } 333 | 334 | #if UNITY_IOS 335 | private static PlistElementDict Get_Or_Add_PlistDict(IDictionary arrRootValues, string strKey) 336 | { 337 | if (arrRootValues.ContainsKey(strKey) == false) 338 | arrRootValues.Add(strKey, new PlistElementDict()); 339 | 340 | return arrRootValues[strKey].AsDict(); 341 | } 342 | #endif 343 | 344 | private static void BuildSetting_IOS(BuildConfig.IOSSetting pSetting) 345 | { 346 | if (string.IsNullOrEmpty(pSetting.strBundle_Identifier) == false) 347 | PlayerSettings.applicationIdentifier = pSetting.strBundle_Identifier; 348 | 349 | string strVersion_FromCommandLine = GetCommandLineArg(mapCommandLine[ECommandLineList.ios_version]); 350 | if (string.IsNullOrEmpty(strVersion_FromCommandLine) == false) 351 | PlayerSettings.bundleVersion = strVersion_FromCommandLine; 352 | else if(string.IsNullOrEmpty(pSetting.strBuildVersion) == false) 353 | PlayerSettings.bundleVersion = pSetting.strBuildVersion; 354 | 355 | 356 | string strBuildNumber_FromCommandLine = GetCommandLineArg(mapCommandLine[ECommandLineList.ios_buildnumber]); 357 | if(string.IsNullOrEmpty(strBuildNumber_FromCommandLine) == false) 358 | PlayerSettings.iOS.buildNumber = strBuildNumber_FromCommandLine; 359 | else if(string.IsNullOrEmpty(pSetting.strBuildNumber) == false) 360 | PlayerSettings.iOS.buildNumber = pSetting.strBuildNumber; 361 | 362 | 363 | Debug.Log(const_strPrefix_ForDebugLog + 364 | $" Build Setting [IOS]\n" + 365 | $"applicationIdentifier : {PlayerSettings.applicationIdentifier}\n" + 366 | $"PlayerSettings.bundleVersion : {PlayerSettings.bundleVersion}\n" + 367 | $"buildNumber : {PlayerSettings.iOS.buildNumber}" 368 | ); 369 | } 370 | 371 | } 372 | } 373 | 374 | #endif 375 | -------------------------------------------------------------------------------- /Editor/JenkinsBuilder_IOS.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 867ccb99b3bd4074a13329d4fffcd1d8 3 | timeCreated: 1588752768 -------------------------------------------------------------------------------- /Editor/KorStrix.JenkinsBuilder.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "KorStrix.JenkinsBuilder.Editor", 3 | "references": [], 4 | "optionalUnityReferences": [], 5 | "includePlatforms": [ 6 | "Editor" 7 | ], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false, 10 | "overrideReferences": false, 11 | "precompiledReferences": [], 12 | "autoReferenced": true, 13 | "defineConstraints": [] 14 | } -------------------------------------------------------------------------------- /Editor/KorStrix.JenkinsBuilder.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4bc58e642c93a1646a608a8ddedd04be 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /GithubImage.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 73ae918af23bcd7428bd2297cba057e6 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /GithubImage/Jenkins_BuildConfig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KorStrix/Unity_JenkinsBuilder/6a4782ae6f952e73d32477adc18d18d5ca8d5d19/GithubImage/Jenkins_BuildConfig.png -------------------------------------------------------------------------------- /GithubImage/Jenkins_BuildConfig.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 502efca67ed2cc543a589a61ca19a528 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | externalObjects: {} 6 | serializedVersion: 9 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: -1 36 | mipBias: -100 37 | wrapU: -1 38 | wrapV: -1 39 | wrapW: -1 40 | nPOTScale: 1 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 0 53 | spriteTessellationDetail: -1 54 | textureType: 0 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 2 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 2048 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | spriteSheet: 73 | serializedVersion: 2 74 | sprites: [] 75 | outline: [] 76 | physicsShape: [] 77 | bones: [] 78 | spriteID: 79 | vertices: [] 80 | indices: 81 | edges: [] 82 | weights: [] 83 | spritePackingTag: 84 | pSDRemoveMatte: 0 85 | pSDShowRemoveMatteOption: 0 86 | userData: 87 | assetBundleName: 88 | assetBundleVariant: 89 | -------------------------------------------------------------------------------- /GithubImage/Jenkins_BuildConfig_Android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KorStrix/Unity_JenkinsBuilder/6a4782ae6f952e73d32477adc18d18d5ca8d5d19/GithubImage/Jenkins_BuildConfig_Android.png -------------------------------------------------------------------------------- /GithubImage/Jenkins_BuildConfig_Android.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a094905a75b45a64c935e963cc4818d7 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | externalObjects: {} 6 | serializedVersion: 9 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: -1 36 | mipBias: -100 37 | wrapU: -1 38 | wrapV: -1 39 | wrapW: -1 40 | nPOTScale: 1 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 0 53 | spriteTessellationDetail: -1 54 | textureType: 0 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 2 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 2048 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | spriteSheet: 73 | serializedVersion: 2 74 | sprites: [] 75 | outline: [] 76 | physicsShape: [] 77 | bones: [] 78 | spriteID: 79 | vertices: [] 80 | indices: 81 | edges: [] 82 | weights: [] 83 | spritePackingTag: 84 | pSDRemoveMatte: 0 85 | pSDShowRemoveMatteOption: 0 86 | userData: 87 | assetBundleName: 88 | assetBundleVariant: 89 | -------------------------------------------------------------------------------- /GithubImage/Jenkins_BuildConfig_iOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KorStrix/Unity_JenkinsBuilder/6a4782ae6f952e73d32477adc18d18d5ca8d5d19/GithubImage/Jenkins_BuildConfig_iOS.png -------------------------------------------------------------------------------- /GithubImage/Jenkins_BuildConfig_iOS.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eab92f6b90cda2e4ab5442ac0a7b473b 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | externalObjects: {} 6 | serializedVersion: 9 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: -1 36 | mipBias: -100 37 | wrapU: -1 38 | wrapV: -1 39 | wrapW: -1 40 | nPOTScale: 1 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 0 53 | spriteTessellationDetail: -1 54 | textureType: 0 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 2 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 2048 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | spriteSheet: 73 | serializedVersion: 2 74 | sprites: [] 75 | outline: [] 76 | physicsShape: [] 77 | bones: [] 78 | spriteID: 79 | vertices: [] 80 | indices: 81 | edges: [] 82 | weights: [] 83 | spritePackingTag: 84 | pSDRemoveMatte: 0 85 | pSDShowRemoveMatteOption: 0 86 | userData: 87 | assetBundleName: 88 | assetBundleVariant: 89 | -------------------------------------------------------------------------------- /GithubImage/Jenkins_EditorWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KorStrix/Unity_JenkinsBuilder/6a4782ae6f952e73d32477adc18d18d5ca8d5d19/GithubImage/Jenkins_EditorWindow.png -------------------------------------------------------------------------------- /GithubImage/Jenkins_EditorWindow.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4d23144f54d90c044bc5da4dd1fb07a5 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | externalObjects: {} 6 | serializedVersion: 9 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: -1 36 | mipBias: -100 37 | wrapU: -1 38 | wrapV: -1 39 | wrapW: -1 40 | nPOTScale: 1 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 0 53 | spriteTessellationDetail: -1 54 | textureType: 0 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 2 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 2048 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | spriteSheet: 73 | serializedVersion: 2 74 | sprites: [] 75 | outline: [] 76 | physicsShape: [] 77 | bones: [] 78 | spriteID: 79 | vertices: [] 80 | indices: 81 | edges: [] 82 | weights: [] 83 | spritePackingTag: 84 | pSDRemoveMatte: 0 85 | pSDShowRemoveMatteOption: 0 86 | userData: 87 | assetBundleName: 88 | assetBundleVariant: 89 | -------------------------------------------------------------------------------- /IOS_Shell.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5fc10328f2e165743aa0c9dd36080c62 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /IOS_Shell/ios_export_ipa.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # IOS Uploader Bash입니다. 3 | # 주의사항 4 | # Window에서 파일 수정후 맥에서 실행시 줄바꿈 코드(EOL)를 Unix 형식으로 변경바랍니다. (Window/MAC은 안됨) 5 | 6 | WORKSPACE=$1 7 | AppleTeamID=$2 8 | ProjectName=$3 9 | 10 | cd "$WORKSPACE" 11 | 12 | XCODE_PROJECT_DIR="Build" 13 | IPA_EXPORT_PATH="${XCODE_PROJECT_DIR}/.." 14 | 15 | 16 | echo "XCODE_PROJECT_DIR=${XCODE_PROJECT_DIR}" 17 | cd "$XCODE_PROJECT_DIR" 18 | echo "Archive iOS BUILD" 19 | 20 | if test -d "${XCODE_PROJECT_DIR}/Unity-iPhone.xcworkspace" 21 | then 22 | echo "xcodebuild with xcode workspace" 23 | xcodebuild DEVELOPMENT_TEAM="${AppleTeamID}" \ 24 | -allowProvisioningUpdates \ 25 | -workspace Unity-iPhone.xcworkspace \ 26 | -scheme Unity-iPhone \ 27 | -configuration Release archive \ 28 | -archivePath "${XCODE_PROJECT_DIR}/../archive/${ProjectName}" 29 | else 30 | echo "xcodebuild with xcode project" 31 | xcodebuild DEVELOPMENT_TEAM="${AppleTeamID}" \ 32 | -allowProvisioningUpdates \ 33 | -scheme Unity-iPhone \ 34 | -configuration Release archive \ 35 | -archivePath "${XCODE_PROJECT_DIR}/../archive/${ProjectName}" 36 | fi 37 | 38 | echo "Export from ARCHIVE to IPA" 39 | 40 | xcodebuild -allowProvisioningUpdates \ 41 | -exportArchive \ 42 | -exportOptionsPlist "exportOptions.plist" \ 43 | -exportPath "${IPA_EXPORT_PATH}" \ 44 | -archivePath "${XCODE_PROJECT_DIR}/../archive/${ProjectName}.xcarchive" -------------------------------------------------------------------------------- /IOS_Shell/ios_export_ipa.sh.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 19f601fb8a08f7a46b8462742fd0a6d4 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /IOS_Shell/ipa_send_appstore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 주의사항 3 | # Window에서 파일 수정후 맥에서 실행시 줄바꿈 코드(EOL)를 Unix 형식으로 변경바랍니다. (Window/MAC은 안됨) 4 | 5 | APP_STORE_USERNAME=$1 6 | APP_STORE_PASSWORD=$2 7 | IPA_PATH=$3 8 | 9 | echo "Validate App IPA_PATH : $IPA_PATH" 10 | xcrun altool --validate-app --file "$IPA_PATH" --username "$APP_STORE_USERNAME" --password "$APP_STORE_PASSWORD" 11 | 12 | echo "Upload App IPA_PATH : $IPA_PATH" 13 | xcrun altool --upload-app --file "$IPA_PATH" --username "$APP_STORE_USERNAME" --password "$APP_STORE_PASSWORD" -------------------------------------------------------------------------------- /IOS_Shell/ipa_send_appstore.sh.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d481da08ad8063c4cb860317544be92b 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Strix 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6eaa6f2dbeb8aa34c85ad13773ace966 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 이 저장소는 관리되지 않습니다. 2 | https://github.com/unity-korea-community/unity-builder 3 | 4 | # 1. 젠킨스 빌더 프로젝트입니다. 5 | ![](https://github.com/KorStrix/Unity_JenkinsBuilder/blob/master/GithubImage/Jenkins_EditorWindow.png) 6 | 7 | `젠킨스`에서 실행하는 유니티 빌드 스크립트 패키지입니다. 8 | 9 | 기능 10 | - Unity Editor 내부/외부(`커맨드라인`)에서 `ConfigFile`을 통해 `Platform`별로 `빌드` 11 | 12 | # 2. 왜 만들었나요? 13 | `커맨드라인`을 통해 `Unity Build`를 할경우 이것저것 `세팅`할게 많습니다. 14 | 15 | 이 세팅들을 `파일`(=**Config File**)에 담은 후 `경로`만 넘겨주는 식으로 빌드하기 위해서 만들었습니다. 16 | 17 | ![](https://github.com/KorStrix/Unity_JenkinsBuilder/blob/master/GithubImage/Jenkins_BuildConfig.png) 18 | 19 | (Config 파일 [링크](https://github.com/KorStrix/Unity_JenkinsBuilder/blob/master/Editor/BuildConfig.cs)) 20 | 21 | 22 | # 3. 어떻게 설치하나요? 23 | [링크](https://github.com/KorStrix/Unity_DevelopmentDocs/blob/master/GitHub/UnityPackage.md)를 참고바랍니다. 24 | 25 | **Unity Editor 상단탭/Tools/Build에 메뉴가 뜨면 설치 성공!** 26 | 27 | --- 28 | # 4. 빌드 테스트 29 | 30 | ## 4-1. Build Config 생성 및 Editor에서 바로 빌드 테스트 31 | 1. 유니티 에디터의 상단 탭 - `Tools/Strix/Jenkins Build/Create Build Config Exmaple File`로 `ConfigFile`을 생성합니다. 32 | 2. `Config File`은 `Json 형식`으로 이루어져 있으며, 각 항목당 설명은 스크립트에 주석[(링크)](https://github.com/KorStrix/Unity_JenkinsBuilder/blob/master/Editor/BuildConfig.cs)으로 달았습니다. 33 | 이를 참고하며 `Config File`을 프로젝트에 맞게 수정합니다. 34 | 3. 수정 완료 후 `Tools/Strix/Jenkins Build/Show Jenkins Builder Window`를 통해 윈도우를 엽니다. 35 | 4. 아까 작성한 `Config File Path`를 설정 후 빌드 파일을 어디에 생성할지 세팅합니다. 36 | 5. Android or IOS `Build`를 합니다. 37 | * 빌드 하기 전 주의사항 ) 프로젝트의 `Platform`이 해당 Platform인지 확인합니다. 38 | * `AOS`는 APK를 `바로 빌드`할 수 있지만, `IOS`의 경우 유니티에선 `Xcode Project`로 Export밖에 못합니다. 39 | 40 | 6. **APK or XCode Project가 세팅한 Output path에 나오면 성공!** 41 | 42 | --- 43 | ## 4-2. 젠킨스 - 안드로이드 빌드 테스트 44 | 45 | ![](https://github.com/KorStrix/Unity_JenkinsBuilder/blob/master/GithubImage/Jenkins_BuildConfig_Android.png) 46 | 47 | 빌드하기 전 `BuildConfig/AndroidSetting`을 세팅하세요. 48 | 49 | 안드로이드는 크게 어렵지 않기 때문에 자세한 설명을 생략합니다. 50 | 51 | 52 | 53 | ### 빌드 방법 54 | 55 | 1. 젠킨스 프로젝트를 생성 합니다. 56 | * 젠킨스 프로젝트 생성 관련 내용은 여기서 다루지 않습니다. 57 | 2. 젠킨스 프로젝트 구성 - `Build` 항목에 `Invoke Unity3D Editor` 항목이 있습니다. 여기서 `Editor command line arguments`를 수정할 예정입니다. 58 | * 이 항목에는 Unity Default CommandLine과 이 프로젝트의 CommandLine을 같이 쓰며 CommandLine을 통해 **"어떻게"** 유니티를 실행시키고, 이 프로젝트의 빌드 스크립트를 **"어떻게"** 실행하는지를 세팅하는 곳입니다. 59 | * 유니티 에디터의 커맨드라인 중 -quit -batchmode -logFile log.txt를 넣습니다. 이에 대한 설명은 유니티 메뉴얼[(링크)](https://docs.unity3d.com/kr/530/Manual/CommandLineArguments.html)를 참고합니다. 60 | * 하단의 라인도 연달아 삽입합니다. 61 | ``` 62 | -executeMethod Jenkins.Builder.Build_Android -config_path YOUR_CONFIG_PATH.json -output_path ${JENKINS_HOME}/jobs/${JOB_NAME}/builds/${BUILD_NUMBER}/archive 63 | ``` 64 | 여기서 YOUR_CONFIG_PATH에 Build Config 파일의 경로를 세팅합니다. 65 | 다른 커맨드 라인을 보고싶으시면 스크립트[(링크)](https://github.com/KorStrix/Unity_JenkinsBuilder/blob/eb5f4c29fe026abfbbdf7977ca4295948cfb8106/Editor/JenkinsBuilder.cs#L60)를 참고바랍니다. 66 | 67 | - ${JENKINS_HOME}, ${JOB_NAME}, ${BUILD_NUMBER}의 경우 Jenkins 환경변수입니다. 68 | 69 | 70 | 3. **Build를 한 뒤 Archive에 APK파일이 있으면 성공!** 71 | 72 | --- 73 | ## 4-3. 젠킨스 - IOS 빌드 테스트 74 | 75 | ![](https://github.com/KorStrix/Unity_JenkinsBuilder/blob/master/GithubImage/Jenkins_BuildConfig_iOS.png) 76 | 77 | 빌드하기 전 `BuildConfig/iOSSetting`을 세팅하세요. 78 | 79 | ### 주의사항 80 | **IOS 빌드를 위해선 MAC OS의 PC와 Apple 개발자 계정이 필요합니다.** 81 | 82 | ### 개요 83 | 안드로이드의 경우 PC -> APK 추출 -> 선택에 따라 -> APK 스토어 업로드까지 크게 어렵지는 않으나, 84 | 85 | IOS의 경우 ipa를 공유하려면 86 | PC -> XCode Project -> ipa 추출 -> Appstore Connect 업로드까지 해아 하며, 87 | PC -> XCode Project 과정에서 ipa -> Appstore Connect 업로드에 필요한 `plist(property list)` 등을 함께 `Xcode Project`에 담아야 합니다. 이것은 `Config File`로 작업할 수 있습니다. 88 | 89 | 젠킨스에 IOS Build 플러그인이 있음에도 불구하고 배치파일로 뺀 이유는 세팅 간소화 및 범용성을 위해서입니다. 90 | (플러그인에 세팅해야 할 변수가 많음, 젠킨스가 아닌 환경에서도 쓸 수 있게끔) 91 | 92 | **여기서 IOS 빌드 테스트 항목은 PC -> XCode Project -> ipa 추출 및 Appstore Connect 업로드까지 테스트합니다.** 93 | 94 | **Appstore Connect 링크** 95 | https://appstoreconnect.apple.com/ 96 | 97 | ### 빌드 방법 98 | 1. 젠킨스 프로젝트 생성 후 `프로젝트 구성`으로 갑니다. 99 | 2. `Build`에 Execute Shell 작업을 추가하고 하단의 내용을 적습니다. 100 | ``` 101 | # 폴더 내 모든 걸 비우기 102 | rm -r ${WORKSPACE}/Build/ 103 | ``` 104 | 3. `Build`에 `Invoke Unity3D Editor/Editor command line arguments`에 하단의 내용을 적습니다. 105 | ``` 106 | -quit -batchmode -executeMethod Jenkins.Builder.Build_IOS -config_path YOUR_CONFIG_PATH.json -output_path ${WORKSPACE} -filename Build -ios_version 1 107 | ``` 108 | 109 | 4. `Build`에 `Execute Shell` 작업을 추가하고 하단의 내용을 적습니다. 110 | ``` 111 | # ipa Export 112 | sh "ios_export_ipa.sh이 들어있는 경로" "${WORKSPACE}" "AppleTeamID" 113 | ``` 114 | 여기서 `AppleTeamID`는 애플 계정에 있는 애플 `팀 ID`를 기입합니다. `팀 ID`는 숫자와 대문자 영어로 이루어진 10개의 단어입니다. (2020.08 기준) 115 | 116 | 5. Mac OS가 설치된 PC에서 XCode를 설치 후 `Preference - AppleTeamID`를 등록한 뒤 **빌드**를 합니다. 117 | 6. **Build를 한 뒤 AppleStore Connect 사이트에 세팅한 빌드번호의 빌드가 있으면 성공** 118 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 939cf69029667ec40a8df6b2207f283b 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Shell.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed20f3a8f790e4c4a9e72fd58850073e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Shell/UploadFTP.sh: -------------------------------------------------------------------------------- 1 | # ============================================ 2 | # 작성자 : Strix 3 | # 개요 : LFTP를 통해 FTP에 업로드하는 스크립트입니다. 4 | # LFTP는 병렬 전송 및 실패 시 어느정도 자동화를(경로가 없으면 경로생성 등) 지원하기 때문에 채택하였습니다. 5 | # 6 | # 설치 : LFTP를 설치해야 합니다. 7 | # - 공식 홈페이지 : https://lftp.yar.ru/ 8 | # 9 | # 주의사항 : Window에서 파일 수정후 맥에서 실행시 줄바꿈 코드(EOL)를 Unix 형식으로 변경바랍니다. (Window/MAC은 안됨) 10 | # ============================================ 11 | 12 | 13 | # 데이터 세팅 - FTP 14 | HOST=$1 15 | USER=$2 16 | PASS=$3 17 | 18 | CLEAR_TARGET_DIR_IF_EXIST=$4 19 | SOURCE_DIR=$5 20 | TARGET_DIR=$6 21 | 22 | 23 | # TARGETDIR이 이미 있으면 비우기 유무 24 | if [ $CLEAR_TARGET_DIR_IF_EXIST == "true" ] 25 | then 26 | echo "Clear Start // Target Dir : $TARGET_DIR" 27 | 28 | lftp -f " 29 | open $HOST 30 | user $USER $PASS 31 | set ftp:ssl-allow no; 32 | rm -r -f "$TARGET_DIR"; 33 | bye 34 | " 35 | fi 36 | 37 | 38 | echo "Upload Start // SourceDir : $SOURCE_DIR TargetDir : $TARGET_DIR" 39 | 40 | lftp -f " 41 | open $HOST 42 | user $USER $PASS 43 | set ftp:ssl-allow no; 44 | mirror -R --parallel=50 $SOURCE_DIR $TARGET_DIR 45 | bye 46 | " 47 | -------------------------------------------------------------------------------- /Shell/UploadFTP.sh.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f4c79528136decc4d993b788841c9e6a 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Shell/VersionHandler.sh: -------------------------------------------------------------------------------- 1 | # ============================================ 2 | # 작성자 : Strix 3 | # 개요 : 버전 파일(Json 형식만 지원)을 핸들링하는 Shell입니다. 4 | # 설치 : JJ(Json CLI Editor,https://github.com/tidwall/jj)를 설치해야 합니다. 5 | # 6 | # 주의사항 : Window에서 파일 수정후 맥에서 실행시 줄바꿈 코드(EOL)를 Unix 형식으로 변경바랍니다. (Window/MAC은 안됨) 7 | # ============================================ 8 | 9 | 10 | # 데이터 세팅 11 | FILE_NAME=$1 12 | EDIT_NAME=$2 13 | METHOD_NAME=$3 14 | ZERO_PADDING_COUNT=$4 15 | 16 | # JJ 플러그인을 통해 변수 추출 17 | VERSION=$(cat "$FILE_NAME" | jj "$EDIT_NAME") 18 | 19 | if [ "$METHOD_NAME" == "GET" ] || [ "$METHOD_NAME" == "get" ] 20 | then 21 | echo $VERSION 22 | 23 | else 24 | NEW_VERSION=$VERSION; 25 | 26 | echo "Current File : $(cat "$FILE_NAME") METHOD_NAME : $METHOD_NAME \nNEW_VERSION : $NEW_VERSION" 27 | 28 | if [ "$METHOD_NAME" == "ADD" ] || [ "$METHOD_NAME" == "add" ] 29 | then 30 | # 변수에 1을 더합니다. `10#`을 안붙일 경우 에러가 뜹니다. (shell은 기본적으로 8진수 계산이므로 9 이상 숫자가 나올 시 에러) 31 | NEW_VERSION=$((10#${VERSION} + 1)) 32 | elif [ "$METHOD_NAME" == "SUB" ] || [ "$METHOD_NAME" == "sub" ] 33 | then 34 | # 변수에 1을 더합니다. 35 | NEW_VERSION=$((10#${VERSION} - 1)) 36 | fi 37 | 38 | if [ "$ZERO_PADDING_COUNT" != "0" ] 39 | then 40 | OPERATOR="%0${ZERO_PADDING_COUNT}d" 41 | NEW_VERSION=$(printf \""$OPERATOR\"" $NEW_VERSION) 42 | 43 | echo "Zero Fill $ADD_PREFIX // $NEW_VERSION" 44 | fi 45 | 46 | echo "$EDIT_NAME : Current : $VERSION // New : $NEW_VERSION" 47 | 48 | # 1을 더한 값을 변수에 저장후 덮어쓰기 49 | # -v = 덮어쓰기 / -p = 보기좋은 출력 50 | FILE_TEXT=$(cat "$FILE_NAME" | jj -r -v "$NEW_VERSION" "$EDIT_NAME" | jj -p) 51 | 52 | # 변수를 파일에 덮어쓰며 확인합니다. 53 | echo "$FILE_TEXT" > "$FILE_NAME" 54 | echo "New File : $(cat "$FILE_NAME")" 55 | fi -------------------------------------------------------------------------------- /Shell/VersionHandler.sh.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8d6b16f68de22284895a5ed6038cb3d8 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.korstrix.jenkinsbuilder", 3 | "version": "1.0.0", 4 | "displayName": "ZZ.Jenkins Builder", 5 | "description": "\uc820\ud0a8\uc2a4\uc5d0\uc11c \uc2e4\ud589\ud558\ub294 \uc720\ub2c8\ud2f0 \ube4c\ub4dc \uc2a4\ud06c\ub9bd\ud2b8\uc785\ub2c8\ub2e4.", 6 | "unity": "2018.1", 7 | "keywords": [ 8 | "utility" 9 | ], 10 | "author": { 11 | "name": "KorStrix", 12 | "email": "korstrix@gmail.com", 13 | "url": "https://github.com/KorStrix/Unity_JenkinsBuilder" 14 | } 15 | } -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a415ffceec2ef544eb9fa3302910749c 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------