Jenkins 와 Unity3D 의 headless build 를 이용한 build 자동화

이 번 글에서는 Unity 로 만들어진 프로젝트를 Jenkins 를 통해 빌드 자동화 하는 것을 알아보도록 하겠다.
이 예제에서는 Mac 에 설치된 Unity 를 호출해서 빌드하는 것을 가정한다. 전체 흐름은 다음과 같다.

1. Jenkins 의 빌드 번호 등 빌드 환경 정보를 JSON 파일로 저장한다
2. Jenkins 가 Unity 의 editor script 를 batch mode 로 실행하고, editor script 는 앞의 JSON 형태의 정보를 넘겨 받아 빌드 결과물을 생성한다.
3. Jenkins 에서 Google drive 나 windows 공유 폴더 등에 결과물을 복사한다.
4. 팀원들이 다 같이 즐겁게 새 빌드를 플레이한다.

아래에 각 단계별로 좀 더 자세한 설명을 하도록 하겠다. 설명 중에 인용되는 코드는 좀 더 쉽게 읽히게 하기 위해서 에러 처리 등을 제외하고 단순화시켰다.

Step 1. 빌드 정보를 JSON 파일로 넘겨주기

빌드 자동화를 하게 되면 여러 빌드 파일이 생성되는데 이를 구분하기 위해서는 각 결과물에 빌드 번호를 포함하는 것이 편리할 것이다. 빌드 번호는 Jenkins 가 자동으로 생성해주는데, 이 정보를 활용하기 위해서는 Jenkins 의 빌드 번호 정보를 뒤에서 설명하는 Unity script 에 넘겨줄 필요가 있다. 여기서는 간단하게 JSON 파일 안에 빌드 정보를 포함하게 하고 Unity script 에서 이를 읽어서 빌드 번호를 추출하는 것으로 하겠다.

먼저 Jenkins 상에서 새로 아이템을 만들어준다.
Jenkins 설정에 따라 소스 저장소를 모니터링 하다가 새로 소스 저장소에 커밋되는 내용이 있으면 자동으로 빌드 아이템이 실행되게 할 수도 있고, 아니면 몇시간에 한 번씩 주기적으로 빌드를 만들어내게 설정할 수도 있다. 이 부분은 Jenkins 의 표준적인 설정 환경이니 Jenkins 매뉴얼을 참고하길 바란다.

해당 아이템에서 shell command 설정 부분이 핵심적인 부분인데, 다음과 같은 내용을 포함시킨다.

cat > convert.py <<EOF2
import json

conf = {}
conf[‘build_number’] = $BUILD_NUMBER
conf[‘apk’] = {
 “sdk_relative_path” : “NVPACK/android-sdk-macosx”   # android sdk 의 주소를 기입한다.
}

print json.dumps(conf, indent=2)
EOF2

python ./convert.py > build_config.json2
mv build_config.json2 build_config.json

그리고 나서는 별도의 shell command 로 아래에 설명되는 Unity editor script 를 호출해준다.

<code>
/Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -logFile build.log -projectPath \$PWD -quit -nographics -executeMethod iFunFactoryEditorScript.BuildApk
</code>

Step 2. Unity editor script 에서 빌드 번호 받아서 실제 APK 파일 생성하기

Unity 의 Assets/Editor 디렉토리 아래 ScriptableObject 를 상속받은 C# class 를 포함하는 C# 스크립트를 추가함으로써 editor script 를 포함시킬 수 있다.

아래는 아이펀팩토리에서 사용되는 ifunfactory.cs 내용이다. 앞 단계에서 호출한 BuildApk 라는 함수가 static 으로 선언된 것을 확인할 수 있을 것이다.

1

우리는 이 스크립트에서 앞서 JSON 으로 넘겨준 build 번호를 넘겨 받아서 PlayerSettings 에 세팅함으로써, 최종 생성될 APK 에 포함될 version 번호를 지정할 수 있다.
아래는 이 코드의 예시이다.

<code>
JSONClass conf = JSON.Parse(System.IO.File.ReadAllText(“build_config.json”)).AsObject;
JSONClass backup = new JSONClass();

int build_number = conf[“build_number”].AsInt;
PlayerSettings.bundleVersion = “1.0.0.” + build_number;

JSONClass apk_conf = conf[“apk”].AsObject;
PlayerSettings.Android.bundleVersionCode = conf[“build_number”].AsInt;

string product_name = PlayerSettings.productName;
string output1 = product_name + “-” + conf[“build_number”].AsInt + “-unaligned.apk”;
string apk_name = product_name + “-” + conf[“build_number”].AsInt + “.apk”;
</code>

이제 기본적인 준비가 끝났으니 실제 APK 를 생성한다. 이 과정은 다음과 같이 BuildPipeline.BuildPlayer() 를 호출하는 것만으로 가능하다. 이 때 첫번째 인자로 빌드할 scene 의 리스트를 문자열 배열로 넘겨준다.

<code>
string[] scenes = [“scene1”, “scene2”];
BuildPipeline.BuildPlayer(scenes, output1, BuildTarget.Android, BuildOptions.None);
</code>

그런데 생성되는 APK 는 jarsigner 와 zipalign 을 거쳐야된다. 그렇기 때문에 다음과 같은 코드를 추가한다.

<code>
// Runs jarsigner on the generated apk file.
UnityEngine.Debug.Log(“Running jarsinger”);
Process jarsigner = new Process{StartInfo = new ProcessStartInfo{FileName = “jarsigner”, Arguments = “-verify -verbose ” + output1, UseShellExecute = false, RedirectStandardOutput = true}};
jarsigner.Start();
jarsigner.WaitForExit();

// Makes the generated apk file aligned.
UnityEngine.Debug.Log(“Running zipalign”);
string android_sdk_path = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + “/” + apk_conf[“sdk_relative_path”].Value;
Process zipalign = new Process{StartInfo = new ProcessStartInfo{FileName = android_sdk_path + “/tools/zipalign”, Arguments = “-f -v 4 ” + output1 + ” ” + apk_name, UseShellExecute = false, RedirectStandardOutput = true}};
zipalign.Start();
zipalign.WaitForExit();
</code>

이렇게 생성된 APK 파일은 빌드 번호가 파일 이름에도 포함되고, 실제 apk 를 설치했을 때도 제대로 된 build 번호가 표시될 것이다.

끝으로 Jenkins 의 post-build action 으로 apk 파일을 archive 하게 해서 Jenkins 상에 저장할 수 있다. 여기까지로 작업을 완료할 수도 있지만, 만일 공유 폴더로 파일을 복사하고 싶은 경우 Jenkins 상에서 별도의 shell command 로 cp 명령을 추가해주면 된다.

단순한 Jenkins script 와 Unity editor script 로 손쉽게 unity project 의 빌드 자동화를 완성했다. 유사한 방식으로 APK 뿐만 아니라 iOS 용 IPA 를 생성하는 것도 가능한데, 이 부분은 여러분이 직접 시도해보면 좋을 것 같다.

아이펀팩토리 문대경 CEO

답글 남기기

댓글을 게시하려면 다음의 방법 중 하나를 사용하여 로그인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중