You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
10 KiB
C#

// Build Maker
// For making iOS and Android builds automatically at default paths outside project folder
// Default Path for iOS build is /Users/${UserName}/Documents/_Builds/${Product Name}/iOS Build
// Default Path for Android build is ${UserName}/Documents/_Builds/${Product Name}/Android Build
// Only active scenes in build settings are included in build
// No need to create any folders all folders will be created automatically
// If build already exists no need to delete, it will Append existing build for iOS
// If APK already exists with the same version it will be deleted and new build will be generated
// If build is completed succesfully respective folders are automatically opened
// Shortcut key for Generating iOS Build => Cmd + Shift + i
// Shortcut key opening Build Path => Cmd + Shift + o
using System;
using System.IO;
using UnityEngine;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Build.Reporting;
#endif
namespace HGR.Utils
{
public static class BuildMaker
{
#if UNITY_EDITOR
//===================================================
// FIELDS
//===================================================
private static string _version = $"{PlayerSettings.bundleVersion}";
//===================================================
// METHODS
//===================================================
/// <summary>
/// Method return the Build path according to the OS.
/// </summary>
/// <param name="target">The Build Target type passed.</param>
/// <returns>A string of the whole path</returns>
private static string GetBuildPath(BuildTarget target, bool server)
{
string path = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
//One check only for MacOSX because on MAC the Documents folder is inside the path returned by the above statement
if(SystemInfo.operatingSystemFamily.Equals(OperatingSystemFamily.MacOSX))
path += "/Documents";
if(!Directory.Exists(path + "/_Builds"))
Directory.CreateDirectory(path + "/_Builds");
if(!Directory.Exists(path + "/_Builds/" + PlayerSettings.productName))
Directory.CreateDirectory(path + "/_Builds/" + PlayerSettings.productName);
path += "/_Builds/" + PlayerSettings.productName;
switch(target)
{
case BuildTarget.StandaloneWindows64:
if(server)
{
if(!Directory.Exists(path + "/Server Build"))
Directory.CreateDirectory(path + "/Server Build");
else
{
Directory.Delete(path + "/Server Build", true);
Directory.CreateDirectory(path + "/Server Build");
}//else end
path += "/Server Build";
}//if end
else
{
if(!Directory.Exists(path + "/Standalone Build"))
Directory.CreateDirectory(path + "/Standalone Build");
else
{
Directory.Delete(path + "/Standalone Build", true);
Directory.CreateDirectory(path + "/Standalone Build");
}//else end
path += "/Standalone Build";
}//else end
break;
case BuildTarget.Android:
if(!Directory.Exists(path + "/Android Build"))
Directory.CreateDirectory(path + "/Android Build");
path += "/Android Build";
break;
}//switch end
return path;
}//GetBuildPath() end
/// <summary>
/// Method finds and returns the active scenes in build settings.
/// </summary>
/// <returns>Return an array of the currently active scenes.</returns>
private static string[] GetActiveScenes()
{
List<string> scenes = new();
foreach(EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
{
if(scene.enabled)
scenes.Add(scene.path);
}//loop end
return scenes.ToArray();
}//GetBuildScenes() end
/// <summary>
/// Method opens the OS explorer according to the path passed.
/// </summary>
/// <param name="path">The path to open.</param>
private static void OpenInExplorer(string path) => EditorUtility.RevealInFinder(path);
[MenuItem("Build/Generate Standalone Build")]
private static void GenerateStandaloneBuild()
{
if(EditorUtility.DisplayDialog("BUILD MAKER", "Do you want to Generate Standalone Build?.", "Yes", "No"))
MakeStandaloneBuild();
}//GenerateAndroidBuild() end
private static void MakeStandaloneBuild()
{
string path = GetBuildPath(BuildTarget.StandaloneWindows64, false);
string name = path + $"/{PlayerSettings.productName}.exe";
BuildPlayerOptions buildPlayerOptions = new()
{
scenes = GetActiveScenes(),
locationPathName = name,
target = BuildTarget.StandaloneWindows64,
subtarget = (int)StandaloneBuildSubtarget.Player,
options = BuildOptions.None
};
BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
BuildSummary summary = report.summary;
if(summary.result == BuildResult.Succeeded)
{
OpenInExplorer(path);
Debug.Log("Standalone Build Generated Successfully to path\n" + path);
}//if end
}//MakeStandaloneBuild() end
[MenuItem("Build/Generate Server Build %#s")]
private static void GenerateServerBuild()
{
if(EditorUtility.DisplayDialog("BUILD MAKER", "Do you want to Generate Server Build?.", "Yes", "No"))
MakeServerBuild();
}//GenerateAndroidBuild() end
private static void MakeServerBuild()
{
string path = GetBuildPath(BuildTarget.StandaloneWindows64, true);
string name = path + $"/{PlayerSettings.productName}.exe";
BuildPlayerOptions buildPlayerOptions = new()
{
scenes = GetActiveScenes(),
locationPathName = name,
target = BuildTarget.StandaloneWindows64,
subtarget = (int)StandaloneBuildSubtarget.Server,
options = BuildOptions.None
};
BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
BuildSummary summary = report.summary;
if(summary.result == BuildResult.Succeeded)
{
CreateLaunchFile(path);
Debug.Log("Server Build Generated Successfully to path\n" + path);
// MakeAndroidBuild();
}//if end
}//MakeAndroidBuild() end
private static void CreateLaunchFile(string path)
{
path += "/Launch.bat";
string dq = "\"";
string bs = @"\";
string command = $"start cmd /k {dq}.{bs}{PlayerSettings.productName}.exe -batchmode -nographics -logFile output.log{dq}";
if (!File.Exists(path))
File.WriteAllText(path, command);
OpenInExplorer(path);
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android);
}//CreateLaunchFile() end
[MenuItem("Build/Generate Android Build %#a")]
private static void GenerateAndroidBuild()
{
if(EditorUtility.DisplayDialog("BUILD MAKER", "Do you want to Generate Android Build?.", "Yes", "No"))
MakeAndroidBuild();
}//GenerateAndroidBuild() end
/// <summary>
/// Method Generates an Android Platform Build.
/// </summary>
private static void MakeAndroidBuild()
{
string BuildPath = GetBuildPath(BuildTarget.Android, false);
string BuildName = BuildPath + "/" + PlayerSettings.productName + " v" + _version + ".apk";
//if same version apk exists then delete it
if(File.Exists(BuildName))
File.Delete(BuildName);
BuildPlayerOptions buildPlayerOptions = new()
{
scenes = GetActiveScenes(),
locationPathName = BuildName,
target = BuildTarget.Android,
options = BuildOptions.None
};
BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
BuildSummary summary = report.summary;
if(summary.result == BuildResult.Succeeded)
{
OpenInExplorer(BuildName);
Debug.Log("Build Generated Successfully for Android Platform to path\n" + BuildPath);
}//if end
}//MakeAndroidBuild() end
/// <summary>
/// Method open the path at which the build has been generated.
/// </summary>
[MenuItem("Build/Open Build Path %#o")]
private static void OpenBuildPath()
{
string BuildPath = string.Empty;
switch(EditorUserBuildSettings.activeBuildTarget)
{
case BuildTarget.Android:
BuildPath = GetBuildPath(BuildTarget.Android, false);
if(File.Exists(BuildPath + "/" + PlayerSettings.productName + " v" + _version+ ".apk"))
{
OpenInExplorer(BuildPath + "/" + PlayerSettings.productName + " v" + _version + ".apk");
return;
}//if end
break;
}//switch end
OpenInExplorer(BuildPath);
}//OpenBuildPath() end
#endif
}//class end
}//namespace end