WinCNT

유니티에서 안드로이드 기기에 연결되어 있으면 Build And Run, 그렇지 않으면 Build만 하는 스크립트 만들어보기 본문

Unity/Unity 관련

유니티에서 안드로이드 기기에 연결되어 있으면 Build And Run, 그렇지 않으면 Build만 하는 스크립트 만들어보기

WinCNT_SSS 2023. 9. 21. 18:12

서론

CI와 빌드 자동화를 위한 무언가(?)를 작업 중이었다

유니티에서는 빌드하는 스크립트를 간편하게 짤 수 있고, 참고 자료도 많아서 문제는 없었다

 

그런데 빌드 옵션에 BuildOptions.AutoRunPlayer를 지정했을 경우, 빌드 시에 연결된 디바이스가 없으면 빌드 파일 자체가 안 만들어진다는 것을 알게 되었다

안드로이드 기기에 연결되어 있으면 Build And Run, 그렇지 않으면 Build만 하고 싶었기에 그 방법을 찾아봤다


방법 1) UnityException: No Android devices connected 체크

우선 처음으로 성공한 것은 BuildPipeline.BuildPlayer의 리턴 값인 BuildReport를 체크하는 방법이었다

빌드 시에 디바이스가 연결되어 있지 않으면 예외가 발생하며, 그 내용은 Prepare For Build라는 스텝에 나와있었기에 그것을 체크해봤다

public static void Build()
{
    BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();
    buildPlayerOptions.scenes = new[] { RenderingTestScenePath };
    buildPlayerOptions.locationPathName = "Build/Application.apk";
    buildPlayerOptions.target = BuildTarget.Android;
    buildPlayerOptions.options = BuildOptions.CompressWithLz4HC | BuildOptions.AutoRunPlayer | BuildOptions.Development | BuildOptions.ShowBuiltPlayer;
    
    BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
    BuildSummary summary = report.summary;

    // No Android devices connected로 인한 예외 발생 체크
    bool isRebuildNotRun = false;
    foreach (var step in report.steps)
    {
        if (step.name == "Prepare For Build")
        {
            foreach (var message in step.messages)
            {
                if (message.type == LogType.Exception &&
                    message.content.Contains("UnityException: No Android devices connected"))
                {
                    isRebuildNotRun = true; 
                    break;
                }
            }
        }
    }

    if (isRebuildNotRun)
    {
        buildPlayerOptions.options = BuildOptions.CompressWithLz4HC | BuildOptions.Development | BuildOptions.ShowBuiltPlayer;
        report = BuildPipeline.BuildPlayer(buildPlayerOptions);
        summary = report.summary;
    }
    
    if (summary.result == BuildResult.Succeeded)
        Debug.Log("Build succeeded: " + summary.totalSize + " bytes");
    if (summary.result == BuildResult.Failed)
        Debug.Log("Build failed");
}

문제 없이 작동은 했지만, 사실 그다지 마음에 들지 않은 방법이었다

마음과 같아서는 디바이스가 연결되어 있는지를 먼저 체크하고 싶었는데……


방법 2) adb.exe로 연결된 디바이스 체크하기

그런데 짜잔~!! 챗GPT에 물어보니 그 방법을 알려주네요~

그냥 물어보니 이상한 코드만 만들길래, 위의 코드의 타당성을 묻는 방식으로 바꾸니 도움이 되는 코드를 알려줬다

물론 중간에 몇 번 틀리기도 했다

 

아무튼 이 방법은 adb.exe를 스크립트에서 실행시켜서, 연결된 디바이스가 있는지 확인하는 방식이다

public static void Build()
{
    BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();
    buildPlayerOptions.scenes = new[] { RenderingTestScenePath };
    buildPlayerOptions.locationPathName = "Build/Application.apk";
    buildPlayerOptions.target = BuildTarget.Android;
    buildPlayerOptions.options = BuildOptions.CompressWithLz4HC | BuildOptions.AutoRunPlayer | BuildOptions.Development | BuildOptions.ShowBuiltPlayer;
    
    Process process = new Process();
    // adb 실행 파일의 경로를 설정
    process.StartInfo.FileName = @"C:\\Program Files\\Unity\\Hub\\Editor\\...생략...\\platform-tools\\adb.exe";
    // adb.exe의 인수로 devices를 지정
    process.StartInfo.Arguments = "devices";
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.CreateNoWindow = true;

    process.Start();
    string output = process.StandardOutput.ReadToEnd();
    process.WaitForExit();
    
    List<string> connectedDevices = new List<string>();
    string[] lines = output.Split(new char[] { '\\n', '\\r' }, System.StringSplitOptions.RemoveEmptyEntries);
    for (int i = 1; i < lines.Length; i++) // 첫 번째 라인은 헤더이므로 스킵
    {
        string[] tokens = lines[i].Split('\\t');
        if (tokens.Length >= 2 && tokens[1] == "device")
        {
            connectedDevices.Add(tokens[0]);
        }
    }

    // 연결된 디바이스의 개수 체크
    bool isDeviceConnected = connectedDevices.Count > 0;
    // 연결된 디바이스가 없으면 빌드 옵션 재설정
    if (isDeviceConnected == false)
    {
        buildPlayerOptions.options = BuildOptions.CompressWithLz4HC | BuildOptions.Development | BuildOptions.ShowBuiltPlayer;
    }
    
    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");
}

굳이 BuildPipeline.BuildPlayer를 2번 호출할 필요가 없어지므로 이 방법이 더 나은 것 같다


마무리

여담이지만 BuildOptions.AutoRunPlayer를 지정하지 않으면 딱히 필요 없는 방식이긴 하다

그래도 adb.exe로 연결된 디바이스 체크하는 방법 자체는 여러 응용이 가능할 것 같으니 조사하길 잘 했다고 믿고 싶다


참고 사이트

Unity - Scripting API: BuildPipeline.BuildPlayer

 

Unity - Scripting API: BuildPipeline.BuildPlayer

Use this function to programatically create a build of your project. Calling this method will invalidate any variables in the editor script that reference GameObjects, so they will need to be reacquired after the call. Note: Be aware that changes to script

docs.unity3d.com