Jenkins에서 Unity 빌드하기
목적 : CI를 통해 Unity빌드를 자동화 한다.
필요한 것
Unity pro
SVN
Jenkins
JDK(jenkins설치시 필요)
Jenkins의 unity build plugin
진행 과정
0. 젠킨스 설치
0-1. jenkins를 다운로드 후, 설치를 하면 Applications(응용 프로그램)/Jenkins/jenkins.war가 생성된다.
0-2. terminal에서 jenkins.war의 디렉터리로 이동 후, $java -jar jenkins.war 명령을 실행한다.
0-3. 사파리에서 localhost:8080으로 접속한다.
- Default port번호는 8080 변경하고 싶으면 --httpPort=번호 로 바꿔준다.
1. 시스템 설정을 한다.
1-1. JDK Installations
- mac에서 JAVA_HOME은 JDK설치 후 /usr/libexec/java_home을 실행하면 알 수 있음
1-2 ANT Installations(있으니까 했음, Maven연동은 안한)
1-3 unity build plugin을 설치하면 Maven아래쪽에 Unity3d탭이 생김 Untiy installations를 등록
- mac에서 발생하는 Not Unity3d home directory /Applications/Unity 에러가 뭔지 모르겠음.
=> 발견 : Installation directory를 /Applications/Unity/Unity.app으로 해야됨
2. Configure Global Security
2-1. Enable security 활성화
2.2. Security Realm의 Access Control에서 Jenkins'own user database 활성화 및 사용자의 가입 허용 활성화
2.3 Autorization에서 Project-based Matrix Authorization Stratgy 활성화
=> 젠킨스 세팅 완료
3. 새로운 Item(Job 등록)
3-1. 새로운 Item클릭 후, Freestyle project 생성
3-2. 소스 코드 관리에서 Subversion선택
- Unable to access svn://blah.blah.blah.blah/svn/what/what : svn:E200015:No credential to try. Authentication failed(show details) (Mabe you need to enter credential?) 에러 발생시에는 enter credential을 클릭 후, subversion Authentication을 등록하면 된다.
3-3. Build탭에서 Invoke Unity3d Editor에서 Unity3d installation name을 아까 시스템 설정창에서 등록한 유니티로 설정.
3-4. Editor command line arguments을 채움
- -quit -batchmode -project Path "/Path/path/Path/path/path" -executeMethod className.methodName -output "%WORKSPACE%\output" -Define PREDEFINES로 했음
- http://docs.unity3d.com/Manual/CommandLineArguments.html 참조
이제 실행시키면 됨.
빌드 시, 문제 발생
해당 빌드 콘솔에서 FAILED TO establish the default connection to the WindowServer가 뜨고 아무것도 안되는 경우,
sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
sudo mv /Library/LaunchDaemons/org.jenkins-ci.plist /Library/LaunchAgents/
를 입력하면 젠킨스가 종료됩니다. 이후, 젠킨스를 실행해주면 잘 됩니다.
using UnityEngine;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
public class CommandBuild
{
static Dictionary<string, string> arguments = new Dictionary<string, string>();
static void InitCommandLineArgs()
{
string[] commandArgs;
if (editorBuild != null)
commandArgs = editorBuild.Split(' ');
else
commandArgs = Environment.GetCommandLineArgs();
for (int i = 0; i < commandArgs.Length; i++)
{
if (commandArgs[i].Length > 1 && commandArgs[i].StartsWith("-"))
{
string key = commandArgs[i].Substring(1);
if (arguments.ContainsKey(key) == false)
{
string value = null;
if (i + 1 < commandArgs.Length)
value = commandArgs[i + 1];
arguments.Add(key, value);
}
}
}
}
public static void BuildAndroid()
{
InitCommandLineArgs();
string define = GetValue("Define");
if (define != null)
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, define);
string outputFileName = GetValue("outputFileName");
string savepath = string.Format("{0}/../{1}.apk", Application.dataPath, outputFileName);
PlayerSettings.Android.keystoreName = "keystoreName.keystore";
PlayerSettings.Android.keyaliasName = "keyaliasName";
PlayerSettings.Android.keystorePass = "keystorePass";
PlayerSettings.Android.keyaliasPass = "keyaliasPass";
Build(savepath, BuildTarget.Android);
}
public static void BuildiOS()
{
InitCommandLineArgs();
string define = GetValue("Define");
if (define != null)
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iPhone, define);
string outputFileName = GetValue("outputFileName");
string savepath = string.Format("{0}/../"+outputFileName, Application.dataPath);
Build(savepath, BuildTarget.iPhone);
}
이후 발견된 버그
1. 플랫폼 변경이 안된채로 빌드되는 경우
=> 플랫폼 변경하는 코드를 삽입하여도 실질적으로 코드와 연결된 라이브러리들이 변경전 라이브러리들을 보고 있어서 컴파일 에러 발생
해결 : 빌드 과정을 하나 상단에 추가하여 플랫폼 변경을 미리 해준 후, 다음 빌드 과정에서 빌드를 해준다.
2. Definition이 변경 안되는 경우
=> preprocess defininition들을 위의 소스와 같이 변경을 해도 적용이 안되는 버그 발생
해결 : 1번과 같이 prebuild를 만들어 그 안에서 빌드전에 세팅해야할 것들을 미리 세팅한다.