[unity] Build Script class
Unity에서 프로젝트 세팅으로 하는 빌드가 아닌, 빌드를 스크립트를 통해서 빌드할 수 있는 Build Script Class를 제작해보자.
1. Build Script를 사용해야 되는 이유
- Unity에서 빌드는 File Build Settting -> Build or Build And Run을 통한 빌드를 하는 것이 일반적이다.
하지만 프로젝트를 열때마다 입력해야 하는 keystore 비밀번호나, apk 경로, apk 이름 등을 간소화하고자 빌드 스크립트를 이용하는 경우도 많아지고 있다.
- 게임이나 앱 제작 시 빌드 스크립트만 잘 구축해 놓아도 상당히 시간 비용을 줄일 수 있다.
2. Build Script 제작 방법
1. 우선 프로젝트를 열고 Asset/Scripts/Editor 폴더를 만들어 준다.
2. 해당 폴더에 BuildScript.cs 스크립트를 하나 생성 후 아래와 같이 코딩해보자!
using UnityEditor;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
namespace Container.Build
{
public class BuildScript
{
/* App Info */
private const string APP_NAME = "APPNAME"; //APK 명칭
protected const string KEYSTORE_PASSWORD = "********";
private const string BUILD_BASIC_PATH = "../../build/";
private const string BUILD_ANDROID_PATH = BUILD_BASIC_PATH + "Android/";
private const string BUILD_IOS_PATH = BUILD_BASIC_PATH + "Ios/";
/* IOS 권한 메세지 정보 */
private const string PHOTO_LIBRARY_USAGE_DESCRIPTION = "앱과 상호 작용하려면 사진 액세스 권한이 필요합니다.";
private const string PHOTO_LIBRARY_ADDITIONS_USAGE_DESCRIPTION = "이 앱에 미디어를 저장하려면 사진에 액세스할 수 있어야 합니다.";
private const string MICROPHONE_USAGE_DESCRIPTION = "앱 내 음성 확인 콘텐츠를 활용하려면 마이크 권한이 필요합니다.";
private const bool DONT_ASK_LIMITED_PHOTOS_PERMISSION_AUTOMATICALLY_ON_IOS14 = true;
[MenuItem("Builder/Build/BuildForAndroid")]
public static void BuildForAndroid()
{
string fileName = SetPlayerSettingsForAndroid();
BuildPlayerOptions buildOption = new BuildPlayerOptions();
buildOption.locationPathName = BUILD_ANDROID_PATH + fileName;
buildOption.scenes = GetBuildSceneList();
buildOption.target = BuildTarget.Android;
buildOption.options = BuildOptions.AutoRunPlayer;
BuildPipeline.BuildPlayer(buildOption);
}
[MenuItem("Builder/Build/BuildForIOS")]
public static void BuildForIOS()
{
BuildPlayerOptions buildOption = new BuildPlayerOptions();
buildOption.target = BuildTarget.iOS;
buildOption.scenes = GetBuildSceneList();
buildOption.locationPathName = BUILD_IOS_PATH;
BuildPipeline.BuildPlayer(buildOption);
}
[MenuItem("Builder/OpenBuildDirectory")]
public static void OpenBuildDirectory()
{
OpenFileBrowser(Path.GetFullPath(BUILD_BASIC_PATH));
}
public static void OpenFileBrowser(string path)
{
bool openInsidesOfFolder = false;
if (Directory.Exists(path))
{
openInsidesOfFolder = true;
}
string arguments = (openInsidesOfFolder ? "" : "-R ") + path;
try
{
System.Diagnostics.Process.Start("open", arguments);
}
catch (Exception e)
{
Debug.Log("Failed to open path : " + e.ToString());
}
}
/// <summary>
/// 현재 빌드세팅의 Scene리스트를 받아옴.
/// Enable이 True인 것만 받아옴.
/// </summary>
/// <returns></returns>
protected static string[] GetBuildSceneList()
{
EditorBuildSettingsScene[] scenes = UnityEditor.EditorBuildSettings.scenes;
List<string> listScenePath = new List<string>();
for (int i = 0; i < scenes.Length; i++)
{
if (scenes[i].enabled)
listScenePath.Add(scenes[i].path);
}
return listScenePath.ToArray();
}
protected static string SetPlayerSettingsForAndroid()
{
PlayerSettings.Android.keystorePass = KEYSTORE_PASSWORD;
PlayerSettings.Android.keyaliasPass = KEYSTORE_PASSWORD;
PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64 | AndroidArchitecture.ARMv7;
string fileName = string.Format("{0}_{1}.apk", APP_NAME, PlayerSettings.bundleVersion);
return fileName;
}
#if UNITY_IOS
#pragma warning disable 0162
[PostProcessBuild]
public static void OnPostprocessBuild(BuildTarget target, string buildPath)
{
if (target == BuildTarget.iOS)
{
string pbxProjectPath = PBXProject.GetPBXProjectPath(buildPath);
string plistPath = Path.Combine(buildPath, "Info.plist");
PBXProject pbxProject = new PBXProject();
pbxProject.ReadFromFile(pbxProjectPath);
#if UNITY_2019_3_OR_NEWER
string targetGUID = pbxProject.GetUnityFrameworkTargetGuid();
#else
string targetGUID = pbxProject.TargetGuidByName(PBXProject.GetUnityTargetName());
#endif
//필요한 라이브러리 추가//
//pbxProject.AddBuildProperty(targetGUID, "OTHER_LDFLAGS", "-weak_framework PhotosUI");
//pbxProject.AddBuildProperty(targetGUID, "OTHER_LDFLAGS", "-framework Photos");
//pbxProject.AddBuildProperty(targetGUID, "OTHER_LDFLAGS", "-framework MobileCoreServices");
//pbxProject.AddBuildProperty(targetGUID, "OTHER_LDFLAGS", "-framework ImageIO");
//pbxProject.RemoveFrameworkFromProject(targetGUID, "Photos.framework");
//File.WriteAllText(pbxProjectPath, pbxProject.WriteToString());
PlistDocument plist = new PlistDocument();
plist.ReadFromString(File.ReadAllText(plistPath));
PlistElementDict rootDict = plist.root;
//수출 규정 물어보지 않게 하기 위한 옵션.
rootDict.SetBoolean("ITSAppUsesNonExemptEncryption", false);
//사진첩 사용권한 설명.
rootDict.SetString("NSPhotoLibraryUsageDescription", PHOTO_LIBRARY_USAGE_DESCRIPTION);
//사진추가 사용권한 설명.
rootDict.SetString("NSPhotoLibraryAddUsageDescription", PHOTO_LIBRARY_ADDITIONS_USAGE_DESCRIPTION);
//마이크 사용권한 설명.
rootDict.SetString("NSMicrophoneUsageDescription", MICROPHONE_USAGE_DESCRIPTION);
//if (DONT_ASK_LIMITED_PHOTOS_PERMISSION_AUTOMATICALLY_ON_IOS14)
// rootDict.SetBoolean("PHPhotoLibraryPreventAutomaticLimitedAccessAlert", true);
File.WriteAllText(plistPath, plist.WriteToString());
}
}
#pragma warning restore 0162
#endif
}
}
3. 컴파일 후 Unity 상단의 에디터 메뉴에 보면 빌드 메뉴가 생성된걸 확인할 수 있다.
4. Build And Run 항목이 싫다면 아래 코드 처럼 AutoRunPlayer를 주석처리해주면 된다.
[MenuItem("Builder/Build/BuildForAndroid")]
public static void BuildForAndroid()
{
string fileName = SetPlayerSettingsForAndroid();
BuildPlayerOptions buildOption = new BuildPlayerOptions();
buildOption.locationPathName = BUILD_ANDROID_PATH + fileName;
buildOption.scenes = GetBuildSceneList();
buildOption.target = BuildTarget.Android;
//buildOption.options = BuildOptions.AutoRunPlayer;
BuildPipeline.BuildPlayer(buildOption);
}
5. BuildForAndroid 를 눌러서 빌드를 해보면 APK가 추출된 걸 볼 수 있다.
App 이름과 키스토어 비밀번호는 각자 앱 환경에 맞게 코드를 바꿔줘야 한다.
private const string APP_NAME = "APPNAME"; //APK 명칭
protected const string KEYSTORE_PASSWORD = "********";
6. IOS의 경우는 빌드 후 OnPostprocessBuild 함수를 통해. 빌드 후에 xcode 에서 해야 될 사항들을 자동화할 수 있다.
위 샘플 코드에서는 빌드 후 xcode의 Info.plist 파일을 편집해주는 코드 및 라이브러리 추가하는 방법이 들어 있다.
개인 앱에 맞게 적절히 활용하면 된다.
댓글