블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2858)
Unity3D (897)
Programming (479)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (192)
협업 (64)
3DS Max (3)
Game (12)
Utility (142)
Etc (99)
Link (34)
Portfolio (19)
Subject (90)
iOS,OSX (53)
Android (16)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (19)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday

[수정] Unity 6000.2.9f1에서 Tilde(~)가 Android 빌드에서는 제외되지만, iOS 빌드에서는 제외되지 않는 버그를 확인해서 그냥 Import 되지 않는 다른곳(프로젝트 내 Assets 외부의 _Backup 폴더)으로 이동(Move) 시키도록 소스를 변경함.(2025-10-30)

----

[수정] Unity 6.2 에서 Dot(.)이 숨겨지긴 하지만 빌드에서 제외되지 않는 버그가 확인돼서 Dot(.)과 Tilde(~) 둘다 붙이도록 수정함(Tilde(~)는 빌드 제외 되는 것 확인함) [2025-08-28]

※ 아래 링크에서 설명을 보면 StreamingAssets 폴더 하위에서 dot(.) 정책이 변경 된 것 같다.

[Hidden assets] https://docs.unity3d.com/Manual/SpecialFolders.html

- Files and folders which start with ., except for those under StreamingAssets where this pattern is not ignored.

----

[수정] Rename 방식으로 변경 [2024-07-04]

----

 

[빌드 시, Builtin AssetBundles에서 해당 Platform 에셋번들만 빌드 되도록 하기 위한 PreProcessor 추가]

기본적으로 에셋번들은 플랫폼 별로 모두 가지고 있는데 해당 플랫폼에 맞는 에셋번들만 빌드 되도록 하기 위해서

빌드 전(Preprocessor) 해당 안되는 AssetBundle을 Hidden 폴더(예: .Android / .iOS)로 Rename 했다가, 빌드 후(Postprocessor) 되돌려 놓음.

빌드 전(Preprocessor) 해당 안되는 AssetBundle을 Hidden 폴더(예: .Android~ / .iOS~)로 Rename 했다가, 빌드 후(Postprocessor) 되돌려 놓음.

빌드 전(Preprocessor) 해당 안되는 AssetBundle을 _Backup 폴더로 Move 했다가, 빌드 후(Postprocessor) 되돌려 놓음.

 

using System;
using UnityEngine;
using UnityEditor;
using UnityEditor.Build;
using System.IO;
using System.Collections.Generic;
#if UNITY_2018_1_OR_NEWER
using UnityEditor.Build.Reporting;
#endif
using UnityEditor.Callbacks;

namespace blueasa
{
    /// <summary>
    /// 빌드 시, Built-in AssetBundle에서 해당 Platform AssetBundle만 빌드 되도록 하기 위한 Preprocessor
    /// 빌드 전(Preprocessor) 해당 안되는 AssetBundle을 Hidden 폴더(예: .Android~ / .iOS~)로 Rename 했다가, 빌드 후(Postprocessor) 되돌려 놓음
    /// [Hidden(./~) 참조] https://docs.unity3d.com/Manual/SpecialFolders.html
    /// [수정] Unity6 이상에서 dot(.)이 안먹혀서, tilde(~)도 함께 붙이도록 함(예: .Android~ / .iOS~)
    /// </summary>
#if UNITY_2018_1_OR_NEWER
    public class BuildPreprocessor_BuiltinResourceInStreamingAssets : IPreprocessBuildWithReport, IPostprocessBuildWithReport
#else
    public class BuildPreprocessor_BuiltinResourceInStreamingAssets : IPreprocessBuild, IPostprocessBuild
#endif
    {
        private static readonly string m_strDataPath = Application.dataPath;
        private static readonly string m_strStreamingAssetsPath = Application.streamingAssetsPath;

        private static readonly string m_strAssets = "Assets";
        private static readonly string m_strBackup = "_Backup";
        private static readonly string m_strStreamingAssets = "StreamingAssets";

        private static readonly string m_strRaw = "Raw";
        private static readonly string m_strDot_Raw_Tilde = ".Raw~";
        private static readonly string m_strAndroid = "Android";
        private static readonly string m_strDot_Android_Tilde = ".Android~";
        private static readonly string m_striOS = "iOS";
        private static readonly string m_strDot_iOS_Tilde = ".iOS~";
        private static readonly string m_strDotMeta = ".meta";
        private static readonly string m_strAssetBundles = "AssetBundles";

        private static readonly string m_strStreamingAssetsPath_Builtin_Raw = string.Format("{0}/{1}/{2}/", m_strAssets, m_strStreamingAssets, m_strRaw);
        private static readonly string m_strBackupPath_Builtin_Raw = string.Format("{0}/{1}/", m_strBackup, m_strRaw);
        private static readonly string m_strStreamingAssetsPath_Builtin_Android = string.Format("{0}/{1}/{2}/{3}/", m_strAssets, m_strStreamingAssets, m_strAssetBundles, m_strAndroid);
        private static readonly string m_strBackupPath_Builtin_Android = string.Format("{0}/{1}/", m_strBackup, m_strAndroid);
        private static readonly string m_strStreamingAssetsPath_Builtin_iOS = string.Format("{0}/{1}/{2}/{3}/", m_strAssets, m_strStreamingAssets, m_strAssetBundles, m_striOS);
        private static readonly string m_strBackupPath_Builtin_iOS = string.Format("{0}/{1}/", m_strBackup, m_striOS);

        /// 
        private static readonly string m_strStreamingAssetsPath_Builtin_Raw_FullPath = string.Format("{0}/{1}", m_strStreamingAssetsPath, m_strRaw);
        private static readonly string m_strStreamingAssetsPath_Builtin_Dot_Raw_Tilde_FullPath = string.Format("{0}/{1}", m_strStreamingAssetsPath, m_strDot_Raw_Tilde);

        private static readonly string m_strAssetBundlesPath_Builtin_FullPath = string.Format("{0}/{1}", m_strStreamingAssetsPath, m_strAssetBundles);
        private static readonly string m_strAssetBundlesPath_Builtin_Android_FullPath = string.Format("{0}/{1}", m_strAssetBundlesPath_Builtin_FullPath, m_strAndroid);
        private static readonly string m_strAssetBundlesPath_Builtin_Dot_Android_Tilde_FullPath = string.Format("{0}/{1}", m_strAssetBundlesPath_Builtin_FullPath, m_strDot_Android_Tilde);
        private static readonly string m_strAssetBundlesPath_Builtin_iOS_FullPath = string.Format("{0}/{1}", m_strAssetBundlesPath_Builtin_FullPath, m_striOS);
        private static readonly string m_strAssetBundlesPath_Builtin_Dot_iOS_Tilde_FullPath = string.Format("{0}/{1}", m_strAssetBundlesPath_Builtin_FullPath, m_strDot_iOS_Tilde);

        public int callbackOrder { get { return 0; } }

        private static void Refresh()
        {
            System.Threading.Thread.Sleep(100);
            AssetDatabase.Refresh();
            System.Threading.Thread.Sleep(100);
        }

#if UNITY_2018_1_OR_NEWER
        public void OnPreprocessBuild(BuildReport report)
#else
        public void OnPreprocessBuild(BuildTarget target, string path)
#endif
        {
            Debug.LogWarning($"[OnPreprocessBuild] {this}");

            // [빌드 전] 사용되지 않는 폴더 임시 제외
            Move_StreamingAssetsUnusedFolders();
            //Rename_StreamingAssetsUnusedFolders();

            // Start listening for errors when build starts
            Application.logMessageReceived += OnBuildError;
        }

        // CALLED DURING BUILD TO CHECK FOR ERRORS
        private void OnBuildError(string condition, string stacktrace, LogType type)
        {
            Debug.LogWarning($"[OnBuildError] {condition} {stacktrace} {type}");

            if (type == LogType.Error)
            {
                // FAILED TO BUILD, STOP LISTENING FOR ERRORS
                Application.logMessageReceived -= OnBuildError;

                // 빌드 에러 시에도 이동된 폴더 되돌리기
                Restore_StreamingAssetsUnusedFolders();
                //Restore_Rename_StreamingAssetsUnusedFolders();
            }
        }

#if UNITY_2018_1_OR_NEWER
        public void OnPostprocessBuild(BuildReport report)
#else
        public void OnPostprocessBuild(BuildTarget target, string path)
#endif
        {
            Debug.LogWarning($"[OnPostprocessBuild] {this}");

            // [빌드 후] 제외 됐던 다른 폴더 되돌리기
            Restore_StreamingAssetsUnusedFolders();
            //Restore_Rename_StreamingAssetsUnusedFolders();

            // IF BUILD FINISHED AND SUCCEEDED, STOP LOOKING FOR ERRORS
            Application.logMessageReceived -= OnBuildError;
        }

        //////////////////////////////////////////////////////////////////

        #region Move
        public static void Move_StreamingAssetsUnusedFolders()
        {
            Debug.LogWarning($"[Move_StreamingAssetsUnusedFolders]");
            // [빌드 전] 다른 플랫폼 AssetBundle 폴더 임시 제외

            switch (GuitarGirl.ClientSettings.ResourceLoadType)
            {
                case eResourceLoadType.Local_Resource:
                    {
                        // AssetBundles 폴더 모두 제거
                        Move_StreamingAssetsUnusedFolder_iOS();
                        Move_StreamingAssetsUnusedFolder_Android();
                    }
                    break;

                case eResourceLoadType.Local_AssetBundle:
                case eResourceLoadType.Server_AssetBundle:
                    {
                        // Raw / 해당 안되는 플랫폼 폴더 제거
                        Move_StreamingAssetsUnusedFolder_Raw();
#if UNITY_ANDROID
                        Move_StreamingAssetsUnusedFolder_iOS();
#elif UNITY_IOS
                        Move_StreamingAssetsUnusedFolder_Android();
#endif
                    }
                    break;
            }

            Refresh();
        }

        public static void Move_StreamingAssetsUnusedFolder_Raw()
        {
            // [Move]
            if (MoveFolder(m_strStreamingAssetsPath_Builtin_Raw, m_strBackupPath_Builtin_Raw))
            {
                // 빈(Empty) 폴더 생성을 방지하기 위해서 폴더의 meta 파일도 함께 삭제
                if (true == File.Exists(m_strStreamingAssetsPath_Builtin_Raw_FullPath + m_strDotMeta))
                {
                    File.Delete(m_strStreamingAssetsPath_Builtin_Raw_FullPath + m_strDotMeta);
                }

                AssetDatabase.Refresh();
            }

            //if (true == Directory.Exists(m_strStreamingAssetsPath_Builtin_Raw_FullPath)
            //    && false == Directory.Exists(m_strStreamingAssetsPath_Builtin_Dot_Raw_Tilde_FullPath))
            //{
            //    Debug.LogWarning("[OnPreprocessBuild] Move 'Raw' Folder to '.Raw'");
            //    Directory.Move(m_strStreamingAssetsPath_Builtin_Raw_FullPath, m_strStreamingAssetsPath_Builtin_Dot_Raw_Tilde_FullPath);
            //    // 빈(Empty) 폴더 생성을 방지하기 위해서 폴더의 meta 파일도 함께 삭제
            //    if (true == File.Exists(m_strStreamingAssetsPath_Builtin_Raw_FullPath + m_strDotMeta))
            //    {
            //        File.Delete(m_strStreamingAssetsPath_Builtin_Raw_FullPath + m_strDotMeta);
            //    }
            //}
        }

        public static void Move_StreamingAssetsUnusedFolder_iOS()
        {
            // [Move]
            if (MoveFolder(m_strStreamingAssetsPath_Builtin_iOS, m_strBackupPath_Builtin_iOS))
            {
                // 빈(Empty) 폴더 생성을 방지하기 위해서 폴더의 meta 파일도 함께 삭제
                if (true == File.Exists(m_strAssetBundlesPath_Builtin_iOS_FullPath + m_strDotMeta))
                {
                    File.Delete(m_strAssetBundlesPath_Builtin_iOS_FullPath + m_strDotMeta);
                }

                AssetDatabase.Refresh();
            }

            //if (true == Directory.Exists(m_strAssetBundlesPath_Builtin_iOS_FullPath)
            //    && false == Directory.Exists(m_strAssetBundlesPath_Builtin_Dot_iOS_Tilde_FullPath))
            //{
            //    Debug.LogWarning("[OnPreprocessBuild] Move 'iOS' Folder to '.iOS~'");
            //    Directory.Move(m_strAssetBundlesPath_Builtin_iOS_FullPath, m_strAssetBundlesPath_Builtin_Dot_iOS_Tilde_FullPath);
            //    // 빈(Empty) 폴더 생성을 방지하기 위해서 폴더의 meta 파일도 함께 삭제
            //    if (true == File.Exists(m_strAssetBundlesPath_Builtin_iOS_FullPath + m_strDotMeta))
            //    {
            //        File.Delete(m_strAssetBundlesPath_Builtin_iOS_FullPath + m_strDotMeta);
            //    }
            //}
        }

        public static void Move_StreamingAssetsUnusedFolder_Android()
        {
            // [Move]
            if (MoveFolder(m_strStreamingAssetsPath_Builtin_Android, m_strBackupPath_Builtin_Android))
            {
                // 빈(Empty) 폴더 생성을 방지하기 위해서 폴더의 meta 파일도 함께 삭제
                if (true == File.Exists(m_strAssetBundlesPath_Builtin_Android_FullPath + m_strDotMeta))
                {
                    File.Delete(m_strAssetBundlesPath_Builtin_Android_FullPath + m_strDotMeta);
                }

                AssetDatabase.Refresh();
            }

            //if (true == Directory.Exists(m_strAssetBundlesPath_Builtin_Android_FullPath)
            //    && false == Directory.Exists(m_strAssetBundlesPath_Builtin_Dot_Android_Tilde_FullPath))
            //{
            //    Debug.LogWarning("[OnPreprocessBuild] Move 'Android' Folder to '.Android~'");
            //    Directory.Move(m_strAssetBundlesPath_Builtin_Android_FullPath, m_strAssetBundlesPath_Builtin_Dot_Android_Tilde_FullPath);
            //    // 빈(Empty) 폴더 생성을 방지하기 위해서 폴더의 meta 파일도 함께 삭제
            //    if (true == File.Exists(m_strAssetBundlesPath_Builtin_Android_FullPath + m_strDotMeta))
            //    {
            //        File.Delete(m_strAssetBundlesPath_Builtin_Android_FullPath + m_strDotMeta);
            //    }
            //}
        }

        /// <summary>
        /// 숨겨진 폴더 되돌리기
        /// Move : 이동시켜 놨던게 있다면 다 되돌리기
        /// Rename : 옮겨진게(./~찍힌게) 있다면 다 되돌리기
        /// </summary>
        public static void Restore_StreamingAssetsUnusedFolders()
        {
            Debug.LogWarning($"[Restore_StreamingAssetsUnusedFolders]");

            // [Move] 이동 시켰던 폴더 되돌리기
            Restore_Move_StreamingAssetsUnusedFolders();

            // [Rename] 제외 됐던(./~) 폴더 되돌리기
            //Restore_Rename_StreamingAssetsUnusedFolders();
        }

        public static void Restore_Move_StreamingAssetsUnusedFolders()
        {
            // [Restore] 이동 시켰던 폴더 되돌리기

            bool bExcute = false;

            // [Move] Raw
            if (MoveFolder(m_strBackupPath_Builtin_Raw, m_strStreamingAssetsPath_Builtin_Raw))
            {
                bExcute = true;
            }

            // [Move] iOS
            if (MoveFolder(m_strBackupPath_Builtin_iOS, m_strStreamingAssetsPath_Builtin_iOS))
            {
                bExcute = true;
            }

            // [Move] Android
            if (MoveFolder(m_strBackupPath_Builtin_Android, m_strStreamingAssetsPath_Builtin_Android))
            {
                bExcute = true;
            }

            if (true == bExcute)
            {
                Refresh();
            }
        }

        private static bool MoveFolder(string _strPath_Src, string _strPath_Dest)
        {
            AssetDatabase.Refresh();
            bool isSuccess = false;
            if (System.IO.Directory.Exists(_strPath_Src))
            {

                System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(_strPath_Src);
                var files = di.GetFiles();

                if (files != null && files.Length > 0)
                {
                    if (System.IO.Directory.Exists(_strPath_Dest))
                    {
                        UnityEditor.FileUtil.DeleteFileOrDirectory(_strPath_Dest);
                    }
                    else
                    {
                        string[] arrKeys = _strPath_Dest.Split(new string[] { "/" }, System.StringSplitOptions.RemoveEmptyEntries);
                        string strPath = "";
                        for (int i = 0; i < arrKeys.Length - 1; i++)
                        {
                            strPath += arrKeys[i] + "/";
                            if (!System.IO.Directory.Exists(strPath))
                            {
                                Directory.CreateDirectory(strPath);
                            }
                        }

                    }
                    AssetDatabase.Refresh();
                    UnityEditor.FileUtil.MoveFileOrDirectory(_strPath_Src, _strPath_Dest);
                    //FileUtil.ReplaceDirectory(_sPath, _sNewPath);
                    isSuccess = true;
                }
                else
                {
                    Debug.LogWarning("Files Empty! Can't move files - " + _strPath_Src);
                }
            }
            else
            {
                Debug.LogWarning(_strPath_Src + " Not Exist");
            }

            return isSuccess;
        }

        #endregion

        //////////////////////////////////////////////////////////////////

        #region Rename

        public static void Rename_StreamingAssetsUnusedFolders()
        {
            Debug.LogWarning($"[Rename_StreamingAssetsUnusedFolders]");
            // [빌드 전] 다른 플랫폼 AssetBundle 폴더 임시 제외

            switch (GuitarGirl.ClientSettings.ResourceLoadType)
            {
                case eResourceLoadType.Local_Resource:
                    {
                        // AssetBundles 폴더 모두 제거
                        Rename_StreamingAssetsUnusedFolder_iOS();
                        Rename_StreamingAssetsUnusedFolder_Android();
                    }
                    break;

                case eResourceLoadType.Local_AssetBundle:
                case eResourceLoadType.Server_AssetBundle:
                    {
                        // Raw / 해당 안되는 플랫폼 폴더 제거
                        Rename_StreamingAssetsUnusedFolder_Raw();
#if UNITY_ANDROID
                        Rename_StreamingAssetsUnusedFolder_iOS();
#elif UNITY_IOS
                        Rename_StreamingAssetsUnusedFolder_Android();
#endif
                    }
                    break;
            }

            Refresh();
        }

        public static void Rename_StreamingAssetsUnusedFolder_Raw()
        {
            // [Rename]
            if (true == Directory.Exists(m_strStreamingAssetsPath_Builtin_Raw_FullPath)
                && false == Directory.Exists(m_strStreamingAssetsPath_Builtin_Dot_Raw_Tilde_FullPath))
            {
                Debug.LogWarning("[OnPreprocessBuild] Rename 'Raw' Folder to '.Raw'");
                Directory.Move(m_strStreamingAssetsPath_Builtin_Raw_FullPath, m_strStreamingAssetsPath_Builtin_Dot_Raw_Tilde_FullPath);
                // 빈(Empty) 폴더 생성을 방지하기 위해서 폴더의 meta 파일도 함께 삭제
                if (true == File.Exists(m_strStreamingAssetsPath_Builtin_Raw_FullPath + m_strDotMeta))
                {
                    File.Delete(m_strStreamingAssetsPath_Builtin_Raw_FullPath + m_strDotMeta);
                }
            }
        }

        public static void Rename_StreamingAssetsUnusedFolder_iOS()
        {
            // [Rename]
            if (true == Directory.Exists(m_strAssetBundlesPath_Builtin_iOS_FullPath)
                && false == Directory.Exists(m_strAssetBundlesPath_Builtin_Dot_iOS_Tilde_FullPath))
            {
                Debug.LogWarning("[OnPreprocessBuild] Rename 'iOS' Folder to '.iOS~'");
                Directory.Move(m_strAssetBundlesPath_Builtin_iOS_FullPath, m_strAssetBundlesPath_Builtin_Dot_iOS_Tilde_FullPath);
                // 빈(Empty) 폴더 생성을 방지하기 위해서 폴더의 meta 파일도 함께 삭제
                if (true == File.Exists(m_strAssetBundlesPath_Builtin_iOS_FullPath + m_strDotMeta))
                {
                    File.Delete(m_strAssetBundlesPath_Builtin_iOS_FullPath + m_strDotMeta);
                }
            }
        }

        public static void Rename_StreamingAssetsUnusedFolder_Android()
        {
            // [Rename]
            if (true == Directory.Exists(m_strAssetBundlesPath_Builtin_Android_FullPath)
                && false == Directory.Exists(m_strAssetBundlesPath_Builtin_Dot_Android_Tilde_FullPath))
            {
                Debug.LogWarning("[OnPreprocessBuild] Rename 'Android' Folder to '.Android~'");
                Directory.Move(m_strAssetBundlesPath_Builtin_Android_FullPath, m_strAssetBundlesPath_Builtin_Dot_Android_Tilde_FullPath);
                // 빈(Empty) 폴더 생성을 방지하기 위해서 폴더의 meta 파일도 함께 삭제
                if (true == File.Exists(m_strAssetBundlesPath_Builtin_Android_FullPath + m_strDotMeta))
                {
                    File.Delete(m_strAssetBundlesPath_Builtin_Android_FullPath + m_strDotMeta);
                }
            }
        }

        /// <summary>
        /// 숨겨진 폴더 되돌리기
        /// (옮겨진게(.찍힌게) 있다면 다 되돌리기)
        /// </summary>
        public static void Restore_Rename_StreamingAssetsUnusedFolders()
        {
            Debug.LogWarning($"[Restore_Rename_StreamingAssetsUnusedFolders]");

            // [Restore] 제외 됐던(.) 폴더 되돌리기

            bool bExcute = false;

            // [Rename] Raw
            if (true == Directory.Exists(m_strStreamingAssetsPath_Builtin_Dot_Raw_Tilde_FullPath)
                && false == Directory.Exists(m_strStreamingAssetsPath_Builtin_Raw_FullPath))
            {
                Debug.LogWarning("[OnPostprocessBuild] Rename '.Raw~' Folder to 'Raw'");
                Directory.Move(m_strStreamingAssetsPath_Builtin_Dot_Raw_Tilde_FullPath, m_strStreamingAssetsPath_Builtin_Raw_FullPath);
                bExcute = true;
            }

            // [Rename] iOS
            if (true == Directory.Exists(m_strAssetBundlesPath_Builtin_Dot_iOS_Tilde_FullPath)
                && false == Directory.Exists(m_strAssetBundlesPath_Builtin_iOS_FullPath))
            {
                Debug.LogWarning("[OnPostprocessBuild] Rename '.iOS~' Folder to 'iOS'");
                Directory.Move(m_strAssetBundlesPath_Builtin_Dot_iOS_Tilde_FullPath, m_strAssetBundlesPath_Builtin_iOS_FullPath);
                bExcute = true;
            }

            // [Rename] Android
            if (true == Directory.Exists(m_strAssetBundlesPath_Builtin_Dot_Android_Tilde_FullPath)
                && false == Directory.Exists(m_strAssetBundlesPath_Builtin_Android_FullPath))
            {
                Debug.LogWarning("[OnPostprocessBuild] Rename '.Android~' Folder to 'Android'");
                Directory.Move(m_strAssetBundlesPath_Builtin_Dot_Android_Tilde_FullPath, m_strAssetBundlesPath_Builtin_Android_FullPath);
                bExcute = true;
            }

            if (true == bExcute)
            {
                Refresh();
            }
        }

        #endregion

    }
}

 

 

반응형
Posted by blueasa
, |