유니티 쓰레드(Task)사용 시 메인쓰레드에서 호출되도록 하는 방법

카테고리 없음|2021. 5. 13. 11:23

Task를 실행 후 ContinueWith로 콜백을 실행할 때 두번째 인자로 TaskScheduler.FromCurrentSynchronizationContext()를 넘겨주면 메인쓰레드에서 실행한다.

 

별도의 MainthreadDispatcher를 사용하지 않아도 된다.

 

댓글()

유니티 안드로이드 키스토어 비밀번호 자동 입력

카테고리 없음|2021. 5. 7. 16:02

Project Settings 윈도우에서 비밀번호를 입력할 수 있으며, 유니티를 끄고 켜도 입력이 유지된다.

#if UNITY_ANDROID
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;

namespace Waker.BuildTools
{
    public partial class AndroidKeystore : ScriptableObject
    {
        public const string CustomSettingsPath = "Assets/Editor/Android Keystore Password.asset";

        [SerializeField] private string keystorePassword;
        [SerializeField] private string keyaliasPassword;

        public void UpdatePlayerSettings()
        {
            var i = GetOrCreateSettings(); 

            PlayerSettings.Android.keystorePass = i.keystorePassword;
            PlayerSettings.Android.keyaliasPass = i.keyaliasPassword;
        }

        internal static AndroidKeystore GetOrCreateSettings()
        {
            var settings = AssetDatabase.LoadAssetAtPath<AndroidKeystore>(CustomSettingsPath);
            if (settings == null)
            {
                settings = ScriptableObject.CreateInstance<AndroidKeystore>();
                AssetDatabase.CreateAsset(settings, CustomSettingsPath);
                AssetDatabase.SaveAssets();
            }
            return settings;
        }

        internal static SerializedObject GetSerializedSettings()
        {
            return new SerializedObject(GetOrCreateSettings());
        }

        [SettingsProvider]
        public static SettingsProvider CreateSettingsProvider()
        {
            // First parameter is the path in the Settings window.
            // Second parameter is the scope of this setting: it only appears in the Project Settings window.
            var provider = new SettingsProvider("Project/Waker/Android Keystore Password", SettingsScope.Project)
            {
                // By default the last token of the path is used as display name if no label is provided.
                label = "Android Keystore Password",
                // Create the SettingsProvider and initialize its drawing (IMGUI) function in place:
                guiHandler = (searchContext) =>
                {
                    var settings = AndroidKeystore.GetSerializedSettings();

                    settings.Update();

                    EditorGUILayout.PropertyField(settings.FindProperty("keystorePassword"), new GUIContent("keystorePassword"));
                    EditorGUILayout.PropertyField(settings.FindProperty("keyaliasPassword"), new GUIContent("keyaliasPassword"));

                    settings.ApplyModifiedProperties();

                    if (GUILayout.Button("Update"))
                    {
                        AndroidKeystore.GetOrCreateSettings().UpdatePlayerSettings();
                    }
                },

                // Populate the search keywords to enable smart search filtering and label highlighting:
                // keywords = new HashSet<string>(new[] { "Number", "Some String" })
            };

            return provider;
        }
    }
}
#endif

댓글()

유니티 빌드 시 버전 관리

카테고리 없음|2021. 5. 7. 15:49

System.Version클래스를 이용해 시멘틱 버전을 관리한다.

C# System.Version 문서를 보면 다음과 같은 내용이 나온다.

더보기

설명

버전 번호는 주 버전, 부 버전, 빌드 버전 및 수정 버전의 구성 요소로 구성 됩니다. 주 및 보조 구성 요소가 필요 합니다. 빌드 및 수정 구성 요소는 선택 사항 이지만 수정 구성 요소가 정의 되어 있으면 빌드 구성 요소가 필요 합니다. 정의 된 모든 구성 요소는 0 보다 크거나 같은 정수 여야 합니다. 버전 번호의 형식은 다음과 같습니다. 선택적 구성 요소는 대괄호 ([및])로 표시 됩니다.

주. minor[.빌드[.수정 버전]]

구성 요소는 규칙에 따라 다음과 같이 사용 됩니다.

  • Major: 이름은 같지만 주 버전이 다른 어셈블리는 교환할 수 없습니다. 버전 번호가 높으면 이전 버전과의 호환성을 가정할 수 없는 제품의 주요 재작성이 표시 될 수 있습니다.
  • Minor: 두 어셈블리의 이름과 주 버전 번호가 동일 하지만 부 버전 번호가 다른 경우 이전 버전과의 호환성을 위해 크게 향상 된 기능을 나타냅니다. 이 버전의 부 버전 번호는 제품의 시점 릴리스 또는 완전히 이전 버전의 제품 버전을 나타낼 수 있습니다.
  • 빌드: 빌드 번호의 차이는 동일한 소스의 재컴파일를 나타냅니다. 프로세서, 플랫폼 또는 컴파일러가 변경 될 때 다른 빌드 번호를 사용할 수 있습니다.
  • 수정 버전: 같은 이름, 주 버전 및 부 버전 번호가 있지만 수정 버전이 다른 어셈블리는 완전히 교환할 수 있도록 설계 되었습니다. 이전에 릴리스된 어셈블리에서 보안 허점을 해결 하는 빌드에 사용 될 수 있는 수정 번호가 더 높습니다.

여기에서 유니티를 빌드할 때에 빌드 버전을 자동으로 증가시키는 스크립트를 작성한다.

버전 관리

namespace Waker.BuildTools
{
	public class VersionUpdater : ScriptableObject
    {
        [SerializeField] private int major;
        [SerializeField] private int minor;
        [SerializeField] private int build;

        public Version GetVersion()
        {
            return new System.Version(major, minor, build);
        }

		// 빌드 버전을 증가시키고 유니티 플레이어 셋팅에 적용
        private void IncreaseBuild()
        {
            build++;
            UpdatePlayerSettings();
        }

		// 버전을 플레이어 셋팅에 적용
        public void UpdatePlayerSettings()
        {
            PlayerSettings.bundleVersion = GetVersion().ToString(3);
            
            // 안드로이드일 경우 번들 버전도 같이 증가
#if UNITY_ANDROID
            PlayerSettings.Android.bundleVersionCode = build;
#endif
        }
    }
}

IncreaseBuild를 호출하여 빌드 버전을 자동으로 증가시킬 수 있다.

빌드 후 버전 자동 증가

internal static VersionUpdater GetOrCreateSettings()
{
    var settings = AssetDatabase.LoadAssetAtPath<VersionUpdater>(CustomSettingsPath);
    if (settings == null)
    {
        settings = ScriptableObject.CreateInstance<VersionUpdater>();
        settings.major = 1;
        settings.minor = 1;
        settings.build = 0;
        AssetDatabase.CreateAsset(settings, CustomSettingsPath);
        AssetDatabase.SaveAssets();
    }
    return settings;
}

[PostProcessBuildAttribute(1)]
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
{
    var i = GetOrCreateSettings();
    i.IncreaseBuild();

    EditorUtility.SetDirty(i);
}

PostProcessBuildAttribute를 이용해 빌드 작업 후 빌드 버전을 자동으로 증가시킬 수 있다.

프로젝트 셋팅

internal static SerializedObject GetSerializedSettings()
{
    return new SerializedObject(GetOrCreateSettings());
}
        
[SettingsProvider]
public static SettingsProvider CreateSettingsProvider()
{
    // First parameter is the path in the Settings window.
    // Second parameter is the scope of this setting: it only appears in the Project Settings window.
    var provider = new SettingsProvider("Project/Waker/Version Updater", SettingsScope.Project)
    {
        // By default the last token of the path is used as display name if no label is provided.
        label = "Version Updater",
        // Create the SettingsProvider and initialize its drawing (IMGUI) function in place:
        guiHandler = (searchContext) =>
        {
            var settings = VersionUpdater.GetSerializedSettings();

            settings.Update();

            EditorGUILayout.PropertyField(settings.FindProperty("major"), new GUIContent("major"));
            EditorGUILayout.PropertyField(settings.FindProperty("minor"), new GUIContent("minor"));
            EditorGUILayout.PropertyField(settings.FindProperty("build"), new GUIContent("build"));

            settings.ApplyModifiedProperties();

            if (GUILayout.Button("Version Update"))
            {
                VersionUpdater.GetOrCreateSettings().UpdatePlayerSettings();
            }
        },

    // Populate the search keywords to enable smart search filtering and label highlighting:
    // keywords = new HashSet<string>(new[] { "Number", "Some String" })
    };

    return provider;
}

SettingsProvider를 이용해 프로젝트 셋팅에서 값을 설정할 수 있다.

전체 코드

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;

namespace Waker.BuildTools
{
    public class VersionUpdater : ScriptableObject
    {
        public const string CustomSettingsPath = "Assets/Editor/Version Updater.asset";

        [SerializeField] private int major;
        [SerializeField] private int minor;
        [SerializeField] private int build;

        public Version GetVersion()
        {
            return new Version(major, minor, build);
        }

        private void IncreaseBuild()
        {
            build++;
            UpdatePlayerSettings();
        }

        public void UpdatePlayerSettings()
        {
            PlayerSettings.bundleVersion = GetVersion().ToString(3);
#if UNITY_ANDROID
            PlayerSettings.Android.bundleVersionCode = build;
#endif
        }

        internal static VersionUpdater GetOrCreateSettings()
        {
            var settings = AssetDatabase.LoadAssetAtPath<VersionUpdater>(CustomSettingsPath);
            if (settings == null)
            {
                settings = ScriptableObject.CreateInstance<VersionUpdater>();
                settings.major = 1;
                settings.minor = 1;
                settings.build = 0;
                AssetDatabase.CreateAsset(settings, CustomSettingsPath);
                AssetDatabase.SaveAssets();
            }
            return settings;
        }

        internal static SerializedObject GetSerializedSettings()
        {
            return new SerializedObject(GetOrCreateSettings());
        }
        
        [PostProcessBuildAttribute(1)]
        public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
        {
            var i = GetOrCreateSettings();
            var prevVersion = i.GetVersion();
            i.IncreaseBuild();

            EditorUtility.SetDirty(i);

            Debug.Log($"VersionUpdater Previous Version is {prevVersion}, Current Version is {i.GetVersion()}.");
        }

        [SettingsProvider]
        public static SettingsProvider CreateSettingsProvider()
        {
            // First parameter is the path in the Settings window.
            // Second parameter is the scope of this setting: it only appears in the Project Settings window.
            var provider = new SettingsProvider("Project/Waker/Version Updater", SettingsScope.Project)
            {
                // By default the last token of the path is used as display name if no label is provided.
                label = "Version Updater",
                // Create the SettingsProvider and initialize its drawing (IMGUI) function in place:
                guiHandler = (searchContext) =>
                {
                    var settings = VersionUpdater.GetSerializedSettings();

                    settings.Update();

                    EditorGUILayout.PropertyField(settings.FindProperty("major"), new GUIContent("major"));
                    EditorGUILayout.PropertyField(settings.FindProperty("minor"), new GUIContent("minor"));
                    EditorGUILayout.PropertyField(settings.FindProperty("build"), new GUIContent("build"));

                    settings.ApplyModifiedProperties();

                    if (GUILayout.Button("Version Update"))
                    {
                        VersionUpdater.GetOrCreateSettings().UpdatePlayerSettings();
                    }
                },

                // Populate the search keywords to enable smart search filtering and label highlighting:
                // keywords = new HashSet<string>(new[] { "Number", "Some String" })
            };

            return provider;
        }
    }
}

댓글()

에디터 스크립트에서 직접 스크립트를 생성하는 방법

유니티 & C#|2021. 3. 10. 16:41
// 코드를 받아 스크립트를 생성하거나 업데이트 하는 함수
private void CreateScript(string path, string code)
{
    File.WriteAllText("Assets/" + path, code);
    AssetDatabase.Refresh();
}

Path와 코드 내용을 입력받아 해당 Path에 스크립트를 생성할 수 있다.

 

다음은 팝업 접근에 용이하도록 MyPopups.cs를 생성하는 에디터 코드이다.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;

namespace Waker.Popups.Editors
{
    [CustomEditor(typeof(PopupController))]
    public class PopupControllerEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            if (GUILayout.Button("Generate MyPopups.cs"))
            {
                PopupController instance = target as PopupController;

                var popups = instance.GetComponentsInChildren<PopupBase>();
                string code = CreateCode(popups);
                CreateScript(code);
            }
        }

        private string CreateCode(IEnumerable<PopupBase> popups)
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine("using Waker.Popups;");
            sb.AppendLine("// PopupController.cs에 의해 자동으로 생성된 스크립트입니다. 네임스페이스를 추가하거나 에러를 수정하는 등 자유롭게 수정 가능합니다.");
            sb.AppendLine("public static class MyPopups");
            sb.AppendLine("{");

            foreach (var popup in popups)
            {
                string typeName = popup.GetType().Name;
                string popupName = popup.PopupName;
                string propertyName = String.Concat(popupName.Where(c => !Char.IsWhiteSpace(c)));
                sb.AppendLine($"\tpublic static {typeName} {propertyName} => PopupController.Instance.Get<{typeName}>(\"{popupName}\");");
            }

            sb.AppendLine("}");

            return sb.ToString();
        }

		// 코드를 받아 스크립트를 생성하거나 업데이트 하는 함수
        private void CreateScript(string code)
        {
            File.WriteAllText("Assets/MyPopups.cs", code);
            AssetDatabase.Refresh();
        }
    }
    
}

댓글()

BigInteger를 유닛 단위 문자열로 변환하는 함수

유니티 & C#|2020. 12. 27. 00:56

 

댓글()

유니티 UGUI 드래그 앤 드랍

유니티 & C#|2020. 11. 11. 00:21

댓글()

유니티 Android SDK 업데이트

유니티 & C#|2020. 10. 3. 12:24

https://www.youtube.com/watch?v=3Qay9h14swM

댓글()

유니티에서 다국어 폰트 지원하는 방법

유니티 & C#|2020. 10. 1. 15:58

 영어 폰트와 한글 폰트를 각각 적용하고 싶을 경우 둘 중 하나의 폰트를 선택 한 후, 글꼴 이름에서 추가하고자 하는 폰트의 이름을 추가하면 된다.

 

 하나의 Text 컴포넌트에 여러가지 언어의 글자를 입력하면 자동으로 해당 언어를 지원하는 폰트를 적용해준다.

 

 로컬라이징 에셋을 사용할 때 별도로 언어별 폰트를 지정해줄 필요 없이 이 방법을 사용하면 매우 간편하게 다국어를 지원할 수 있다.

댓글()

Pagination of IEnumerable<T>

유니티 & C#|2020. 9. 29. 15:18

 

댓글()

BundleTool - 유니티에서 빌드된 aab 파일을 안드로이드에 설치

유니티 & C#|2020. 9. 20. 14:24

JDK 및 SDK 설치

jdk와 sdk가 설치되어 있어야 하고, JAVA_HOME 환경변수를 등록해야 한다.

BundleTool

aab파일을 디바이스에 설치하기 위해서는 BundleTool이라는 파일이 필요하다. 다운로드 하는 위치는 다음과 같다.

https://github.com/google/bundletool/releases

bundletool을 실행하기 위한 명령어는 다음과 같다.

java -jar "./bundletool-all-1.2.0.jar" --version

apks 빌드

A.aab 파일을 apks파일로 빌드한다. 현재 컴퓨터와 연결된 안드로이드에 맞도록 필터링 하려면 --connected-device 을 추가한다.

java -jar "./bundletool-all-1.2.0.jar" build-apks 
    --connected-device 
    --bundle="A.aab" 
    --output="A.apks" 
    --ks=key.keystore 
    --ks-pass=pass:123456 
    --ks-key-alias="alias" 
    --key-pass=pass:123456 
    --adb="PATH_TO_SDK\\platform-tools\\adb.exe"

설치

빌드된 apks파일을 연결된 안드로이드에 설치한다.

java -jar "./bundletool-all-1.2.0.jar" install-apks 
    --apks="A.apks" 
    --adb="PATH_TO_SDK\\platform-tools\\adb.exe"

실행

adb를 통해 설치된 앱을 안드로이드에서 실행한다.

PATH_TO_SDK\\platform-tools\\adb.exe shell monkey -p "PACKAGE_NAME" -c android.intent.category.LAUNCHER 1

댓글()