✍️ 개요


이번에 커스텀 패키지를 제작하면서 InitializeOnLoad 어트리뷰트를 사용하면서 시행착오를 많이 겪었죠.
InitializeOnLoad를 통해 호출되는 로직은... 매우 조심스럽게 다뤄야 한다는 사실을 뼈저리게 경험했답니다.
지금부터 InitializeOnLoad을 사용할 때 주의할 점을 정리하도록 하겠습니다.
📌 문제 분석
[Unity 이슈] 커스텀 패키지 Addressable 이슈
✍️ 개요 [ Custom Package 제작하기 ] [Unity 기능] 커스텀 패키지 제작하기✍️ 개요 유니티를 사용해온 프로그래머라면 사용자 패키지(Custom Package)을 만들고 싶다는 생각이 든 적 있지 않나요?
gus6615.tistory.com
이 이슈는 커스탬 패키지를 제작하는 과정에서 나타났습니다.
샘플을 설치하면 Addressable이 사라지는 문제가 있었는데,
이 문제를 해결하기 위해 InitializeOnLoad 어트리뷰트를 사용했습니다.
해결책은 프로젝트의 AddressableAssetGroups에 샘플의 AddressableAssetGroup을 추가하는 방법입니다.

먼저 AddressableSettings의 기본 경로를 가지고 옵니다.
이 값들을 folderPath와 settingsName으로 저장하겠습니다.
※ folderPath = Assets/AddressableAssetsData

위 코드를 분석해보면,
- folderPath 폴더가 없으면 생성하기
- AssetDatabase 갱신하기
입니다.
만약 새 프로젝트에 AddressableAssetSetting을 한 적이 없으면 새로운 폴더를 생성하는 코드입니다.
다음으로는 AddressableAssetSetting을 생성하는 방법에 대해 알아봅시다.

AddressableAssetSetting을 생성하는 방법은 사실 이미 있습니다.
위 버튼이 수행되는 코드를 살펴보면 되겠죠? (Addressable 패키지를 살펴보면 있어요!)

AddressableAssetsWindow.cs 안을 살펴보면 생성 방법을 알 수 있습니다.

이 코드를 사용하면 되겠네요!
[ 소스 코드 전체보기 ]
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEngine;
[InitializeOnLoad]
public class AddressableAssetAdder
{
private static string folderPath = AddressableAssetSettingsDefaultObject.kDefaultConfigFolder;
private static string settingsName = AddressableAssetSettingsDefaultObject.kDefaultConfigAssetName;
static AddressableAssetAdder()
{
EditorApplication.delayCall -= AddressableAssetAdderHandler;
EditorApplication.delayCall += AddressableAssetAdderHandler;
}
private static void AddressableAssetAdderHandler()
{
AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
Debug.Log($"New AddressableAssetSettings created.");
settings = CreateAddressableAssetSettings();
AddressableAssetSettingsDefaultObject.Settings = settings;
}
if (settings.FindGroup("DevelopKit_Basic_Template") == null)
{
string packageVersion = FindPackageVersion();
string assetPath = $"Assets/Samples/DevelopKit Basic Template/{packageVersion}/Basic Template Reference/AddressableAssetsData/AssetGroups/DevelopKit_Basic_Template.asset";
string groupName = "DevelopKit_Basic_Template";
AddressableAssetGroup group = AssetDatabase.LoadAssetAtPath<AddressableAssetGroup>(assetPath);
settings.groups.Add(group);
Debug.Log($"Asset '{assetPath}' added to Addressable Group '{groupName}'.");
}
}
private static AddressableAssetSettings CreateAddressableAssetSettings()
{
AddressableAssetSettings settings = AddressableAssetSettings.Create(folderPath, settingsName, true, true);
// 기본 그룹 생성
if (settings.DefaultGroup == null)
{
var defaultGroup = settings.CreateGroup(
"Default Local Group",
true,
false,
false,
null,
typeof(BundledAssetGroupSchema),
typeof(ContentUpdateGroupSchema)
);
settings.DefaultGroup = defaultGroup;
// 기본 경로 설정
BundledAssetGroupSchema bundleSchema = defaultGroup.GetSchema<BundledAssetGroupSchema>();
if (bundleSchema != null)
{
bundleSchema.BuildPath.SetVariableByName(settings, "LocalBuildPath");
bundleSchema.LoadPath.SetVariableByName(settings, "LocalLoadPath");
}
Debug.Log("Default Addressable Group created");
}
return settings;
}
private static string FindPackageVersion()
{
string packagePath = Application.dataPath.Replace("Assets", string.Empty) +
"/Library/PackageCache/com.developkit.basictemplate/package.json";
string packageText = System.IO.File.ReadAllText(packagePath);
string version = string.Empty;
string[] lines = packageText.Split('\n');
foreach (string line in lines)
{
if (line.Contains("\"version\""))
{
version = line.Split(':')[1].Trim().Replace("\"", string.Empty).Replace(",", string.Empty);
break;
}
}
return version;
}
}
자, 이제 실행해볼까요?

짜잔~ 바로 오류가 발생했네요.
AddressableAssetSetting을 생성하는 부분에서 오류가 날 줄 알았는데,
폴더를 생성하는 부분에서 오류가 발생했습니다.
그런데 이상한 점이 있습니다.
분명 Assets/AddressableAssetsData 폴더를 생성했는데 Invalid 하다고 뜹니다.

... ( 이때 엄청난 삽질을 통해 멘탈이 나갈 뻔 했습니다 )
문제 원인은 InitializeOnLoad 어트리뷰트였습니다.

저렇게 정적 생성자에서 로직을 처리하는데, 호출 시점이 AssetDatabase 갱신을 알지 못하더라구요.
심지어 Addressable 관련 함수 내부에서도 문제가 발생하더군요.

위 코드는 Addressable 패키지 소스 코드 중 일부로, AddressableAssetSettings을 생성하는 Create 함수입니다.
붉은 영역을 보시면 여기도 AssetDatabase을 사용하는 것을 볼 수 있습니다.
그래서 InitializeOnLoad 호출 시점에서 폴더를 생성해도 InValid 하다고 나오고, AddressableAssetSetting도 제대로 생성되지 않는 문제가 발생했었습니다.
📌 해결책

해결책 : EditorApplication.delayCall을 활용하여 호출 시점 미루기
호출 시점을 미뤄서 AssetDatabase가 정상적으로 작동될 때 로직이 처리되도록 했습니다.

다행히 폴더도 정상적으로 생성되고 AddressableAssetSetting도 잘 생성되어 문제를 해결할 수 있었습니다.
다들 InitializeOnLoad 어트리뷰트를 사용할 때 주의하시기 바랍니다!!
AssetDatabase나 Addressable 뿐만 아니라 다른 작업에서도 문제가 발생할 수 있어요.
이럴 경우에는 EditorApplication.delayCall을 활용해보도록 합시다.
'유니티(Unity) > 이슈 도감' 카테고리의 다른 글
[Unity 이슈] Editor에서는 잘 되지만 Build가 안되는 이슈 (1) | 2024.12.29 |
---|---|
[Unity 이슈] Package 파일 참조하는 방법 (0) | 2024.12.28 |
[Unity 이슈] 커스텀 패키지 Addressable 이슈 (1) | 2024.12.22 |
[Unity 이슈] 커스텀 패키지 종속성 문제 (1) | 2024.12.21 |
[Unity] 직렬화가 되지 않는 문제 (1) | 2024.12.06 |