GitLab で Unity の Android アプリを自動ビルドするようにしてみた

# GitLab で Unity の Android アプリを自動ビルドするようにしてみた

GitLab で Unity の Androidアプリを自動ビルドするようにしてみました。
最初は、Windows10 で試行錯誤していましたが、GitLab Runner の実行ユーザーがシステムアカウントになるためか、エラーが解消されませんでした。
Mac で試したところ問題なく動いたので、Mac を使うほうがよさそうです。

## 環境

- macOS Catalina 10.15.4
- GitLab CE 12.8.6（Windows10上の仮想サーバーで動かしています）
- GitLab Runner 12.9.0（Mac上で動かしています）
- Unity 2018.4.20f1

## フォルダ構成

| ファイル/フォルダ | 内容 |
|:--|:--|
| TestProject_Unity/  |  Unityプロジェクトフォルダ |
| TestProject_Unity/.gitignore  |  Git無視リストファイル |
| TestAutoTest/TestProject_Unity/Assets/Editor/AppBuild.cs | ビルド実行メソッドC#ファイル |
| .gitlab-ci.yml  |  GitLab CI 設定ファイル |
|  build.sh |  ビルド用シェルスクリプトファイル |
|  README.md |  説明ファイル |

## 注意点

Android SDK をインストールしたフォルダに toolsフォルダが入っていないことがあるようです。

![Image Pasted at 2020-4-5 09-43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30731/66f26264-5aa5-188b-8a88-7f896dbad85f.png)

toolsフォルダが見当たらないときは、Android Studio から SDKManager を起動して、Android SDK Platform-Tools をインストールしてみてください。

![Image Pasted at 2020-4-5 09-43_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30731/8afb7d32-0d7f-8e2c-0c91-cba8d3249f1f.png)

## ファイルの内容

### TestProject_Unity/.gitignore

```
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/Assets/AssetStoreTools*

# Autogenerated VS/MD solution and project files
ExportedObj/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd

# Unity3D generated meta files
*.pidb.meta

# Unity3D Generated File On Crash Reports
sysinfo.txt

# Builds
*.apk
*.unitypackage

# Visual Studio
.vs
Release/
Debug/
```

### .gitlab-ci.yml

```yml
stages:
  - build

job_build01:
  stage: build
  script:
    - echo "Start build"
    - chmod a+x ./build.sh
    - ./build.sh Android 1.2.3.4
    - echo "Finish build"
  tags:
    - mac
  artifacts:
    paths:
      - build_*.log
      - TestProject_Unity/Build/
    expire_in: 1 week
```

### TestAutoTest/TestProject_Unity/Assets/Editor/AppBuild.cs

```csharp
using UnityEditor;
using UnityEngine;
using UnityEditor.Build.Reporting;
using System;
using System.Collections.Generic;

public class AppBuild : MonoBehaviour
{
    static string[] GetSceneList()
    {
        List<string> sceneList = new List<string>();
        EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes;
        foreach (EditorBuildSettingsScene scene in scenes)
        {
            if (scene.enabled)
            {
                sceneList.Add(scene.path);
            }
        }
        return sceneList.ToArray();
    }

    static string GetArgument(string name)
    {
        string[] arguments = Environment.GetCommandLineArgs();
        for (int i = 0; i < arguments.Length; i++)
        {
            if (arguments[i].Contains(name))
            {
                return arguments[i + 1];
            }
        }
        return null;
    }

    public static void Build()
    {
        string locationPathName = "";
        BuildTarget target = BuildTarget.NoTarget;
        string bundleVersion = GetArgument("/version");;
        string platformName = GetArgument("/platform");
        switch (platformName.ToLower())
        {
            case "android":
                {
                    locationPathName = "Build/" + platformName + "_" + bundleVersion + ".apk";
                }
                break;
            default:
                {
                    locationPathName = "Build/" + platformName + "_" + bundleVersion;
                }
                break;
        }
        target = (BuildTarget)Enum.Parse(typeof(BuildTarget), platformName);

        BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();
        buildPlayerOptions.scenes = GetSceneList();
        buildPlayerOptions.locationPathName = locationPathName;
        buildPlayerOptions.target = target;
        buildPlayerOptions.options = BuildOptions.Development;

        PlayerSettings.bundleVersion = bundleVersion;

        BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
        BuildSummary summary = report.summary;

        if (summary.result == BuildResult.Succeeded)
        {
            Debug.Log("Build succeeded: " + summary.totalSize + " bytes");
        }

        if (summary.result == BuildResult.Failed)
        {
            Debug.Log("Build failed");
        }
    }
}
```

### build.sh

```sh
#!/bin/bash

SHELL_PATH=`pwd`
PLATFORM=$1
VERSION=$2

UNITY=/Applications/Unity/Hub/Editor/2018.4.20f1/Unity.app/Contents/MacOS/Unity
LOGFILE=build_${PLATFORM}.log
PROJECT_PATH=TestProject_Unity
EXECUTE_METHOD=AppBuild.Build

${UNITY} -batchmode -quit -logFile ${LOGFILE} -projectPath "${SHELL_PATH}/${PROJECT_PATH}" -executeMethod ${EXECUTE_METHOD} /platform ${PLATFORM} /version ${VERSION}
```

## まとめ

Unity のビルドはけっこう時間がかかりますね。
開発に専念できるように、自動ビルドする環境を用意してはいかがでしょうか？