앱인토스 개발자센터 로고
Skip to content

시작 시간 최적화

앱인토스 Unity 게임의 시작 시간을 최적화하여 사용자 경험을 크게 향상시키는 방법을 제공해요.
토스 앱 사용자들은 빠른 응답성을 기대하므로 5초 이내 시작을 목표로 해요.


1. 시작 시간 개요

목표 시간 기준

🎯 앱인토스 시작 시간 목표
├── Critical (즉시 개선 필요): > 5초
├── Good (권장): 2-3초  
└── Excellent (최적): < 2초

시작 과정 분석

tsx
// 앱인토스 Unity 시작 과정
interface StartupPhases {
  tossAppLaunch: number;        // 토스 앱 내 게임 시작: ~0.5초
  appsInTossInit: number;       // 앱인토스 프레임워크 초기화: ~0.3초
  unityEngineInit: number;      // Unity 엔진 초기화: ~1.0초
  gameAssetLoading: number;     // 게임 에셋 로딩: ~1-3초
  firstSceneReady: number;      // 첫 씬 준비 완료: ~0.5초
}

// 각 단계별 최적화 포인트 식별

2. Unity 엔진 최적화

PlayerSettings 최적화

c#
// Unity 프로젝트 설정 최적화
public class AppsInTossStartupOptimizer : MonoBehaviour
{
    [Header("시작 최적화 설정")]
    public bool enableFastStartup = true;
    public bool preloadCriticalAssets = true;
    public int maxConcurrentLoads = 3;
    
    [Header("앱인토스 연동")]
    public bool enableTossLogin = true;
    public bool preloadTossServices = false;
    
    void Awake()
    {
        if (enableFastStartup)
        {
            OptimizeStartupSettings();
        }
    }
    
    void OptimizeStartupSettings()
    {
        // 프레임률 제한 설정 (초기 로딩 시)
        Application.targetFrameRate = 30; // 배터리 절약
        
        // Unity 서비스 지연 초기화
        StartCoroutine(DelayedUnityServicesInit());
        
        // 메모리 관리 최적화
        System.GC.Collect();
        Resources.UnloadUnusedAssets();
        
        if (enableTossLogin)
        {
            InitializeTossServices();
        }
    }
    
    IEnumerator DelayedUnityServicesInit()
    {
        // 첫 프레임 렌더링 후 Unity 서비스 초기화
        yield return new WaitForEndOfFrame();
        
        // Analytics, Cloud Build 등 지연 초기화
        InitializeUnityServices();
    }
    
    void InitializeTossServices()
    {
        // 토스 로그인 서비스 사전 초기화
        StartCoroutine(PreloadTossAuthentication());
    }
    
    IEnumerator PreloadTossAuthentication()
    {
        // 토스페이 SDK 사전 로딩
        yield return new WaitForSeconds(0.1f);
        
        // AppsInToss 인증 토큰 검증
        AppsInToss.GetCurrentUserToken((token) => {
            if (!string.IsNullOrEmpty(token))
            {
                Debug.Log("토스 인증 토큰 사전 로딩 완료");
                // 사용자 프로필 캐시 로딩
                StartCoroutine(CacheUserProfile(token));
            }
        });
    }
    
    IEnumerator CacheUserProfile(string token)
    {
        // 사용자 프로필 정보 미리 캐시
        // 게임 플레이 중 빠른 접근을 위함
        yield return null; // 구현 필요
    }
}

스크립트 실행 순서 최적화

c#
// 스크립트 실행 순서 정의
[DefaultExecutionOrder(-100)] // 가장 먼저 실행
public class StartupManager : MonoBehaviour
{
    public static StartupManager Instance { get; private set; }
    
    [Header("시작 단계 설정")]
    public StartupPhase[] phases;
    
    [System.Serializable]
    public class StartupPhase
    {
        public string name;
        public UnityEngine.Events.UnityEvent onPhaseStart;
        public UnityEngine.Events.UnityEvent onPhaseComplete;
        public float maxDuration = 5f; // 타임아웃
    }
    
    private int currentPhaseIndex = 0;
    private float phaseStartTime;
    
    void Awake()
    {
        // 싱글톤 패턴
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
            StartStartupSequence();
        }
        else
        {
            Destroy(gameObject);
        }
    }
    
    void StartStartupSequence()
    {
        Debug.Log("앱인토스 게임 시작 시퀀스 시작");
        ExecuteNextPhase();
    }
    
    void ExecuteNextPhase()
    {
        if (currentPhaseIndex >= phases.Length)
        {
            OnStartupComplete();
            return;
        }
        
        var phase = phases[currentPhaseIndex];
        Debug.Log($"시작 단계 실행: {phase.name}");
        
        phaseStartTime = Time.realtimeSinceStartup;
        phase.onPhaseStart?.Invoke();
        
        // 타임아웃 설정
        StartCoroutine(PhaseTimeout(phase));
    }
    
    IEnumerator PhaseTimeout(StartupPhase phase)
    {
        yield return new WaitForSeconds(phase.maxDuration);
        
        // 단계가 완료되지 않았다면 강제 진행
        if (currentPhaseIndex < phases.Length)
        {
            Debug.LogWarning($"시작 단계 타임아웃: {phase.name}");
            CompleteCurrentPhase();
        }
    }
    
    public void CompleteCurrentPhase()
    {
        if (currentPhaseIndex >= phases.Length) return;
        
        var phase = phases[currentPhaseIndex];
        float duration = Time.realtimeSinceStartup - phaseStartTime;
        
        Debug.Log($"시작 단계 완료: {phase.name} ({duration:F2}초)");
        
        phase.onPhaseComplete?.Invoke();
        
        // 앱인토스 분석 시스템에 전송
        SendPhaseMetric(phase.name, duration);
        
        currentPhaseIndex++;
        ExecuteNextPhase();
    }
    
    void OnStartupComplete()
    {
        float totalTime = Time.realtimeSinceStartup;
        Debug.Log($"게임 시작 완료! 총 시간: {totalTime:F2}초");
        
        // 앱인토스에 시작 완료 알림
        AppsInToss.ReportGameReady(totalTime);
        
        // 성능 목표 체크
        if (totalTime > 5f)
        {
            Debug.LogWarning($"시작 시간이 목표를 초과했습니다: {totalTime:F2}s > 5s");
            AppsInToss.ReportPerformanceIssue("startup_slow", totalTime);
        }
    }
    
    void SendPhaseMetric(string phaseName, float duration)
    {
        var metric = new Dictionary<string, object>
        {
            {"phase", phaseName},
            {"duration", duration},
            {"timestamp", System.DateTime.UtcNow.ToString("o")}
        };
        
        AppsInToss.SendAnalytics("startup_phase", metric);
    }
}

3. 에셋 로딩 최적화

핵심 에셋 사전 로딩

c#
public class CriticalAssetLoader : MonoBehaviour
{
    [Header("필수 에셋 목록")]
    public UnityEngine.Object[] criticalAssets;
    public string[] criticalAddressables;
    
    [Header("앱인토스 특화 에셋")]
    public Texture2D tossPayIcon;
    public AudioClip tossNotificationSound;
    public Font tossFont; // 앱인토스 권장 폰트
    
    private int loadedAssetCount = 0;
    private int totalAssetCount = 0;
    
    public System.Action<float> OnLoadProgress;
    public System.Action OnLoadComplete;
    
    public IEnumerator LoadCriticalAssets()
    {
        totalAssetCount = criticalAssets.Length + criticalAddressables.Length + 3; // 앱인토스 에셋
        loadedAssetCount = 0;
        
        // 1. Unity Resources 에셋 로딩
        foreach (var asset in criticalAssets)
        {
            if (asset != null)
            {
                // 이미 로딩된 에셋은 스킵
                yield return null; // 프레임 분산
                loadedAssetCount++;
                ReportProgress();
            }
        }
        
        // 2. Addressables 에셋 로딩
        foreach (var address in criticalAddressables)
        {
            yield return StartCoroutine(LoadAddressableAsset(address));
        }
        
        // 3. 앱인토스 특화 에셋 로딩
        yield return StartCoroutine(LoadAppsInTossAssets());
        
        OnLoadComplete?.Invoke();
    }
    
    IEnumerator LoadAddressableAsset(string address)
    {
        var handle = Addressables.LoadAssetAsync<UnityEngine.Object>(address);
        
        while (!handle.IsDone)
        {
            yield return null;
        }
        
        if (handle.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded)
        {
            Debug.Log($"Addressable 에셋 로딩 완료: {address}");
        }
        else
        {
            Debug.LogError($"Addressable 에셋 로딩 실패: {address}");
        }
        
        loadedAssetCount++;
        ReportProgress();
    }
    
    IEnumerator LoadAppsInTossAssets()
    {
        // 토스페이 아이콘 로딩
        if (tossPayIcon == null)
        {
            var iconLoad = Resources.LoadAsync<Texture2D>("AppsInToss/TossPayIcon");
            yield return iconLoad;
            tossPayIcon = iconLoad.asset as Texture2D;
        }
        loadedAssetCount++;
        ReportProgress();
        
        // 토스 알림음 로딩
        if (tossNotificationSound == null)
        {
            var soundLoad = Resources.LoadAsync<AudioClip>("AppsInToss/NotificationSound");
            yield return soundLoad;
            tossNotificationSound = soundLoad.asset as AudioClip;
        }
        loadedAssetCount++;
        ReportProgress();
        
        // 앱인토스 권장 폰트 로딩
        if (tossFont == null)
        {
            var fontLoad = Resources.LoadAsync<Font>("AppsInToss/NotoSansKR");
            yield return fontLoad;
            tossFont = fontLoad.asset as Font;
        }
        loadedAssetCount++;
        ReportProgress();
    }
    
    void ReportProgress()
    {
        float progress = (float)loadedAssetCount / totalAssetCount;
        OnLoadProgress?.Invoke(progress);
        
        // 앱인토스 로딩 진행률 UI 업데이트
        AppsInToss.UpdateLoadingProgress(progress);
    }
}

점진적 로딩 시스템

c#
public class ProgressiveLoader : MonoBehaviour
{
    [System.Serializable]
    public class LoadingTier
    {
        public string name;
        public UnityEngine.Object[] assets;
        public int priority; // 낮을수록 우선순위 높음
        public bool loadInBackground = true;
    }
    
    [Header("로딩 단계 설정")]
    public LoadingTier[] loadingTiers;
    
    [Header("앱인토스 연동 설정")]
    public bool showTossLoadingScreen = true;
    public bool enableBackgroundLoading = true;
    
    void Start()
    {
        StartCoroutine(ProgressiveLoadingSequence());
    }
    
    IEnumerator ProgressiveLoadingSequence()
    {
        // 우선순위별로 정렬
        var sortedTiers = loadingTiers.OrderBy(t => t.priority).ToArray();
        
        foreach (var tier in sortedTiers)
        {
            if (tier.priority == 0) // 최우선 에셋은 동기 로딩
            {
                yield return StartCoroutine(LoadTierSync(tier));
            }
            else if (enableBackgroundLoading) // 나머지는 백그라운드 로딩
            {
                StartCoroutine(LoadTierAsync(tier));
            }
        }
    }
    
    IEnumerator LoadTierSync(LoadingTier tier)
    {
        Debug.Log($"동기 로딩 시작: {tier.name}");
        
        foreach (var asset in tier.assets)
        {
            if (asset != null)
            {
                // 에셋 사전 로딩
                yield return null; // 프레임 분산
            }
        }
        
        Debug.Log($"동기 로딩 완료: {tier.name}");
    }
    
    IEnumerator LoadTierAsync(LoadingTier tier)
    {
        Debug.Log($"백그라운드 로딩 시작: {tier.name}");
        
        // 백그라운드 로딩 (게임 플레이에 영향 없음)
        foreach (var asset in tier.assets)
        {
            if (asset != null)
            {
                yield return new WaitForSeconds(0.1f); // 부하 분산
            }
        }
        
        Debug.Log($"백그라운드 로딩 완료: {tier.name}");
    }
}

4. 네트워크 최적화

앱인토스 API 사전 초기화

tsx
// TypeScript - 앱인토스 서비스 사전 초기화
interface AppsInTossPreloadConfig {
    enableUserAuth: boolean;
    enableTossPay: boolean;
    enableAnalytics: boolean;
    cacheUserData: boolean;
}

class AppsInTossPreloader {
    private config: AppsInTossPreloadConfig;
    private preloadPromises: Promise<any>[] = [];
    
    constructor(config: AppsInTossPreloadConfig) {
        this.config = config;
    }
    
    async preloadServices(): Promise<void> {
        console.log('앱인토스 서비스 사전 로딩 시작');
        
        if (this.config.enableUserAuth) {
            this.preloadPromises.push(this.preloadAuthentication());
        }
        
        if (this.config.enableTossPay) {
            this.preloadPromises.push(this.preloadTossPayServices());
        }
        
        if (this.config.enableAnalytics) {
            this.preloadPromises.push(this.preloadAnalyticsServices());
        }
        
        if (this.config.cacheUserData) {
            this.preloadPromises.push(this.preloadUserData());
        }
        
        // 병렬로 모든 서비스 사전 로딩
        await Promise.all(this.preloadPromises);
        console.log('앱인토스 서비스 사전 로딩 완료');
    }
    
    private async preloadAuthentication(): Promise<void> {
        try {
            // 토스 인증 토큰 검증
            const token = await AppsInToss.getCurrentUserToken();
            if (token) {
                console.log('사용자 인증 정보 캐시 완료');
                localStorage.setItem('ait_user_token_cache', token);
            }
        } catch (error) {
            console.warn('인증 정보 사전 로딩 실패:', error);
        }
    }
    
    private async preloadTossPayServices(): Promise<void> {
        try {
            // 토스페이 결제 수단 목록 캐시
            const paymentMethods = await AppsInToss.getAvailablePaymentMethods();
            localStorage.setItem('ait_payment_methods_cache', JSON.stringify(paymentMethods));
            console.log('토스페이 서비스 캐시 완료');
        } catch (error) {
            console.warn('토스페이 서비스 사전 로딩 실패:', error);
        }
    }
    
    private async preloadAnalyticsServices(): Promise<void> {
        try {
            // 분석 서비스 초기화
            await AppsInToss.initializeAnalytics();
            console.log('분석 서비스 초기화 완료');
        } catch (error) {
            console.warn('분석 서비스 초기화 실패:', error);
        }
    }
    
    private async preloadUserData(): Promise<void> {
        try {
            // 사용자 프로필 및 게임 데이터 캐시
            const userProfile = await AppsInToss.getUserProfile();
            const gameData = await AppsInToss.getCloudSaveData();
            
            localStorage.setItem('ait_user_profile_cache', JSON.stringify(userProfile));
            localStorage.setItem('ait_game_data_cache', JSON.stringify(gameData));
            
            console.log('사용자 데이터 캐시 완료');
        } catch (error) {
            console.warn('사용자 데이터 캐시 실패:', error);
        }
    }
}

// Unity WebGL에서 호출할 전역 함수
(window as any).initializeAppsInTossServices = async (configJson: string) => {
    const config = JSON.parse(configJson) as AppsInTossPreloadConfig;
    const preloader = new AppsInTossPreloader(config);
    
    try {
        await preloader.preloadServices();
        // Unity에 완료 알림
        (window as any).unityInstance.SendMessage('StartupManager', 'OnAppsInTossServicesReady', '');
    } catch (error) {
        console.error('앱인토스 서비스 초기화 실패:', error);
        (window as any).unityInstance.SendMessage('StartupManager', 'OnAppsInTossServicesError', error.message);
    }
};

5. 메모리 관리 최적화

시작 시 메모리 정리

c#
public class StartupMemoryManager : MonoBehaviour
{
    [Header("메모리 최적화 설정")]
    public bool enableStartupGC = true;
    public bool unloadUnusedAssets = true;
    public bool optimizeTextureMemory = true;
    
    [Header("앱인토스 메모리 제한")]
    public long maxMemoryUsageMB = 200; // 앱인토스 권장 제한
    
    void Awake()
    {
        if (enableStartupGC)
        {
            StartCoroutine(OptimizeStartupMemory());
        }
    }
    
    IEnumerator OptimizeStartupMemory()
    {
        Debug.Log("시작 시 메모리 최적화 시작");
        
        // 1. 가비지 컬렉션 실행
        if (enableStartupGC)
        {
            System.GC.Collect();
            System.GC.WaitForPendingFinalizers();
            yield return new WaitForSeconds(0.1f);
        }
        
        // 2. 사용하지 않는 에셋 언로드
        if (unloadUnusedAssets)
        {
            var unloadOp = Resources.UnloadUnusedAssets();
            yield return unloadOp;
        }
        
        // 3. 텍스처 메모리 최적화
        if (optimizeTextureMemory)
        {
            OptimizeTextureSettings();
        }
        
        // 4. 메모리 사용량 체크
        CheckMemoryUsage();
        
        Debug.Log("시작 시 메모리 최적화 완료");
    }
    
    void OptimizeTextureSettings()
    {
        // 모바일 환경에 맞는 텍스처 설정 적용
        QualitySettings.masterTextureLimit = 1; // 절반 해상도
        QualitySettings.anisotropicFiltering = AnisotropicFiltering.Disable;
        
        Debug.Log("텍스처 메모리 최적화 적용");
    }
    
    void CheckMemoryUsage()
    {
        long currentMemoryMB = UnityEngine.Profiling.Profiler.GetTotalAllocatedMemory(false) / (1024 * 1024);
        
        Debug.Log($"현재 메모리 사용량: {currentMemoryMB}MB");
        
        if (currentMemoryMB > maxMemoryUsageMB)
        {
            Debug.LogWarning($"메모리 사용량이 권장 제한을 초과: {currentMemoryMB}MB > {maxMemoryUsageMB}MB");
            
            // 앱인토스에 메모리 경고 리포트
            AppsInToss.ReportPerformanceIssue("high_memory_startup", currentMemoryMB);
            
            // 추가 메모리 정리 시도
            StartCoroutine(AdditionalMemoryCleanup());
        }
    }
    
    IEnumerator AdditionalMemoryCleanup()
    {
        // 더 적극적인 메모리 정리
        Resources.UnloadUnusedAssets();
        System.GC.Collect();
        
        yield return new WaitForSeconds(0.5f);
        
        // 정리 후 재측정
        long newMemoryMB = UnityEngine.Profiling.Profiler.GetTotalAllocatedMemory(false) / (1024 * 1024);
        Debug.Log($"메모리 정리 후 사용량: {newMemoryMB}MB");
    }
}

6. 시작 화면 최적화

앱인토스 로딩 화면 커스터마이징

c#
public class AppsInTossLoadingScreen : MonoBehaviour
{
    [Header("로딩 화면 설정")]
    public CanvasGroup loadingCanvas;
    public Image progressBar;
    public TextMeshProUGUI loadingText;
    public Image tossLogo;
    
    [Header("앱인토스 브랜딩")]
    public Color tossBlue = new Color(0.196f, 0.510f, 0.965f); // #3182F6
    public Sprite tossIcon;
    public string[] loadingMessages = {
        "토스와 함께하는 게임을 준비하고 있어요",
        "곧 시작됩니다!",
        "로딩 중..."
    };
    
    private int currentMessageIndex = 0;
    
    void Start()
    {
        InitializeLoadingScreen();
        StartCoroutine(AnimateLoadingScreen());
    }
    
    void InitializeLoadingScreen()
    {
        // 앱인토스 브랜드 컬러 적용
        progressBar.color = tossBlue;
        
        if (tossIcon != null)
        {
            tossLogo.sprite = tossIcon;
        }
        
        // 초기 메시지 설정
        if (loadingText != null)
        {
            loadingText.text = loadingMessages[0];
            loadingText.color = tossBlue;
        }
    }
    
    IEnumerator AnimateLoadingScreen()
    {
        // 로딩 메시지 순환 표시
        while (loadingCanvas.alpha > 0)
        {
            yield return new WaitForSeconds(2f);
            
            currentMessageIndex = (currentMessageIndex + 1) % loadingMessages.Length;
            loadingText.text = loadingMessages[currentMessageIndex];
            
            // 부드러운 텍스트 전환 효과
            yield return StartCoroutine(FadeText());
        }
    }
    
    IEnumerator FadeText()
    {
        // 페이드 아웃
        float alpha = 1f;
        while (alpha > 0)
        {
            alpha -= Time.deltaTime * 2f;
            loadingText.alpha = alpha;
            yield return null;
        }
        
        // 페이드 인
        while (alpha < 1)
        {
            alpha += Time.deltaTime * 2f;
            loadingText.alpha = alpha;
            yield return null;
        }
    }
    
    public void UpdateProgress(float progress)
    {
        if (progressBar != null)
        {
            progressBar.fillAmount = Mathf.Clamp01(progress);
        }
        
        // 진행률에 따른 메시지 업데이트
        if (progress > 0.8f && currentMessageIndex < loadingMessages.Length - 1)
        {
            loadingText.text = loadingMessages[loadingMessages.Length - 1];
        }
    }
    
    public void HideLoadingScreen()
    {
        StartCoroutine(FadeOutLoadingScreen());
    }
    
    IEnumerator FadeOutLoadingScreen()
    {
        float alpha = 1f;
        while (alpha > 0)
        {
            alpha -= Time.deltaTime * 3f; // 빠른 페이드아웃
            loadingCanvas.alpha = alpha;
            yield return null;
        }
        
        loadingCanvas.gameObject.SetActive(false);
        
        // 앱인토스에 로딩 완료 알림
        AppsInToss.OnLoadingComplete();
    }
}

7. 성능 모니터링

시작 성능 추적 시스템

c#
public class StartupPerformanceTracker : MonoBehaviour
{
    [System.Serializable]
    public class StartupMetrics
    {
        public float totalStartupTime;
        public float engineInitTime;
        public float assetLoadingTime;
        public float appsInTossInitTime;
        public float firstFrameTime;
        public long peakMemoryUsage;
        public string deviceModel;
        public string osVersion;
    }
    
    private StartupMetrics metrics = new StartupMetrics();
    private float startTime;
    
    void Awake()
    {
        startTime = Time.realtimeSinceStartup;
        StartPerformanceTracking();
    }
    
    void StartPerformanceTracking()
    {
        // 기기 정보 수집
        metrics.deviceModel = SystemInfo.deviceModel;
        metrics.osVersion = SystemInfo.operatingSystem;
        
        StartCoroutine(TrackStartupPerformance());
    }
    
    IEnumerator TrackStartupPerformance()
    {
        // 첫 프레임 시간 측정
        yield return new WaitForEndOfFrame();
        metrics.firstFrameTime = Time.realtimeSinceStartup - startTime;
        
        // 메모리 사용량 추적
        StartCoroutine(TrackMemoryUsage());
        
        // 시작 완료 대기
        yield return new WaitUntil(() => StartupManager.Instance != null && StartupManager.Instance.IsStartupComplete);
        
        // 최종 메트릭 수집
        CollectFinalMetrics();
        
        // 앱인토스 분석 시스템에 전송
        SendStartupMetrics();
    }
    
    IEnumerator TrackMemoryUsage()
    {
        while (!IsStartupComplete())
        {
            long currentMemory = UnityEngine.Profiling.Profiler.GetTotalAllocatedMemory(false);
            metrics.peakMemoryUsage = System.Math.Max(metrics.peakMemoryUsage, currentMemory);
            
            yield return new WaitForSeconds(0.1f);
        }
    }
    
    void CollectFinalMetrics()
    {
        metrics.totalStartupTime = Time.realtimeSinceStartup - startTime;
        
        Debug.Log($"시작 성능 메트릭:");
        Debug.Log($"  총 시작 시간: {metrics.totalStartupTime:F2}초");
        Debug.Log($"  첫 프레임: {metrics.firstFrameTime:F2}초");
        Debug.Log($"  최대 메모리: {metrics.peakMemoryUsage / (1024*1024)}MB");
        Debug.Log($"  기기: {metrics.deviceModel}");
    }
    
    void SendStartupMetrics()
    {
        var metricsData = new Dictionary<string, object>
        {
            {"total_startup_time", metrics.totalStartupTime},
            {"first_frame_time", metrics.firstFrameTime},
            {"peak_memory_mb", metrics.peakMemoryUsage / (1024f * 1024f)},
            {"device_model", metrics.deviceModel},
            {"os_version", metrics.osVersion},
            {"timestamp", System.DateTime.UtcNow.ToString("o")}
        };
        
        AppsInToss.SendAnalytics("startup_performance", metricsData);
        
        // 성능 기준 체크
        if (metrics.totalStartupTime > 5f)
        {
            AppsInToss.ReportPerformanceIssue("startup_slow", metrics.totalStartupTime);
        }
        
        if (metrics.peakMemoryUsage > 200 * 1024 * 1024) // 200MB
        {
            AppsInToss.ReportPerformanceIssue("high_startup_memory", metrics.peakMemoryUsage / (1024f * 1024f));
        }
    }
    
    bool IsStartupComplete()
    {
        return StartupManager.Instance != null && StartupManager.Instance.IsStartupComplete;
    }
}

8. 체크리스트 및 권장사항

시작 최적화 체크리스트

  • Unity PlayerSettings 최적화 적용
  • 스크립트 실행 순서 정의
  • 핵심 에셋 사전 로딩 시스템 구현
  • 점진적 로딩 시스템 적용
  • 앱인토스 API 사전 초기화
  • 시작 시 메모리 최적화
  • 커스텀 로딩 화면 구현
  • 성능 모니터링 시스템 설치
  • 목표 시간 5초 이내 달성 확인
  • 다양한 기기에서 테스트 완료

앱인토스 특화 권장사항

  1. 토스페이 연동 대비: 결제 API 사전 초기화
  2. 사용자 인증 최적화: 토스 로그인 토큰 캐싱
  3. 메모리 제한 준수: 200MB 이하 유지
  4. 분석 데이터 활용: 실제 사용자 시작 시간 모니터링