Unity

Strategy Pattern을 이용한 Unity Firebase 로그인

lipnus 2023. 10. 15. 16:52
반응형

플랫폼별 로그인 분기에 사용

Android, UnityEditor, Ios일때 Firebase로그인 방법을 각각 다르게 구현하여야 한다.

 

Strategy Pattern

 

연습용으로 해보기 좋은 것 같아 블로그에 기록해둠.

이 패턴으로 안하면 클래스에 If문으로 나누고, 여러 매소드를 만들어서 구현하면 된다.

ex)

private void MockLogin();

private void AndroidLogin();

private void IosLogin();

 

 

Mock은 UnityEditor에서 테스트하기 위한 용도

 

📌Monobehavior 상속

비동기 처리를 위해 코루틴이 사용된다.

코루틴은 Monobehavior에서만 동작하므로 BaseLoginController는 Monobehavior를 상속하고, new가 아니라

addComponent로 씬에 추가하여야 함.

 

📌UnityAction 사용

비동기 과정이라 UnityAction을 이용하여 callback을 받도록 하였다. (Observer Pattern?)

 

📌Template Method로의 확장

BaseLoginController에 공통적으로 사용될 메소드 구현하면 Template Method가 된다. 

 

 

📑LoginManager

public class LoginManager : MonoBehaviour
{
    [SerializeField] private Button loginButton;
    private BaseLoginController loginController; // Strategy Pattern;

    private void Start()
    {
#if UNITY_EDITOR
        loginController = this.AddComponent<MockLoginController>();
#elif UNITY_ANDROID        
    loginController = this.AddComponent<AndroidLoginController>();
#elif UNITY_IOS
        loginController = gameObject.AddComponent<IOSLoginController>();
#endif

        Debug.Log(loginController.Init() ? "초기화 성공" : "초기화 실패");
        loginButton.onClick.AddListener(delegate { loginController.TryLogin(OnLogin); });
    }

    private void OnLogin(bool result, string message)
    {
        Debug.Log($"{message}");
    }

    private void OnLogout(bool result, string message)
    {
        Debug.Log($"{message}");
    }

    private void OnFirebaseLogin(AuthResult result)
    {
        Debug.Log($"{result.Msg}");
    }
}

 

📑BaseLoginController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class AuthResult
{
    public bool Result { get; }
    public string Msg { get; }
    public string Uid{ get; }
    public string Email{ get; }
    
    public AuthResult(bool result, string msg)
    {
        Result = result;
        Msg = msg;
    }

    public AuthResult(bool result, string msg, string uid, string email)
    {
        Result = result;
        Msg = msg;
        Uid = uid;
        Email = email;
    }
}

public abstract class BaseLoginController : MonoBehaviour
{
    public abstract bool Init();
    public abstract void TryLogin(UnityAction<bool, string> callback);
    public abstract void TryLogout(UnityAction<bool, string> callback);
    public abstract void TryFirebaseLogin(UnityAction<AuthResult> callback);
}

 

📑MockLoginController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class MockLoginController : BaseLoginController
{
    public override bool Init()
    {
        return true;
    }

    public override void TryLogin(UnityAction<bool, string> callback)
    {
        callback.Invoke(true, "Mock Login Success");
    }

    public override void TryLogout(UnityAction<bool, string> callback)
    {
        callback.Invoke(true, "Mock Logout Success");

    }

    public override void TryFirebaseLogin(UnityAction<AuthResult> callback)
    {
        var authResult = new AuthResult(
            true,
            "Mock FirebaseLogin Success",
            "this is mock uid",
            "test@test.com"
        );
        callback.Invoke(authResult);
    }
}

 

📑AndroidLoginController

using System;
using System.Collections;
using Firebase.Auth;
using GooglePlayGames.BasicApi;
using GooglePlayGames;
using UnityEngine;
using UnityEngine.Events;

public class AndroidLoginController : BaseLoginController
{
    private FirebaseAuth _fbAuth;
    
    public override bool Init()
    {
        Debug.Log("### LoginManager Start");

        try
        {
            PlayGamesPlatform.InitializeInstance(new PlayGamesClientConfiguration.Builder()
                .RequestIdToken()
                .RequestEmail()
                .Build());
            PlayGamesPlatform.DebugLogEnabled = true;
            PlayGamesPlatform.Activate();
            _fbAuth = FirebaseAuth.DefaultInstance;            
        }
        catch(Exception e)
        {
            Debug.LogException(e);
            return false;
        }
        return true;
    }

    public override void TryLogin(UnityAction<bool, string> callback)
    {
        Debug.Log("### TryGoogleLogin");
        PlayGamesPlatform.Instance.Authenticate(SignInInteractivity.CanPromptAlways, (success) =>
        {
            if (success == SignInStatus.Success)
            {
                callback.Invoke(false, "Google Login Success");
            }
            else
            {
                callback.Invoke(false, "Google Login Failure");
            }
        });
    }

    public override void TryLogout(UnityAction<bool, string> callback)
    {
        throw new System.NotImplementedException();
    }

    public override void TryFirebaseLogin(UnityAction<AuthResult> callback)
    {
        StartCoroutine(FirebaseLoginCoroutine(callback));
    }

    private IEnumerator FirebaseLoginCoroutine(UnityAction<AuthResult> callback)
    {
        while (string.IsNullOrEmpty(((PlayGamesLocalUser)Social.localUser).GetIdToken()))
        {
            yield return null;
        }

        var idToken = ((PlayGamesLocalUser)Social.localUser).GetIdToken();
        var credential = GoogleAuthProvider.GetCredential(idToken, null);
        

        _fbAuth.SignInWithCredentialAsync(credential).ContinueWith(task => {
            if (task.IsCanceled)
            {
                var authResult = new AuthResult(false, "Firebase Canceled");
                callback.Invoke(authResult);
            }
            else if (task.IsFaulted)
            {
                var authResult = new AuthResult(false, "Firebase Faulted");
                callback.Invoke(authResult);
            }
            else
            {
                var authResult = new AuthResult(
                    false,
                    "Firebase Success",
                    _fbAuth.CurrentUser.UserId,
                    _fbAuth.CurrentUser.Email);
                callback.Invoke(authResult);
            }
        });
    }
}

 

📑IosLoginController

public class IosLoginController : BaseLoginController
{
    public override bool Init()
    {
        throw new System.NotImplementedException();
    }

    public override void TryLogin(UnityAction<bool, string> callback)
    {
        throw new System.NotImplementedException();
    }

    public override void TryLogout(UnityAction<bool, string> callback)
    {
        throw new System.NotImplementedException();
    }

    public override void TryFirebaseLogin(UnityAction<AuthResult> callback)
    {
        throw new System.NotImplementedException();
    }
}

지금 당장은 구현할 계획이 없지만, 나중에 필요할 때 여기만 채워넣어서 구현하면 된다.

반응형

'Unity' 카테고리의 다른 글

Character에 새 애니매이션 추가  (1) 2023.11.19
[잡담] 유니티 공부를 하면서  (0) 2021.05.30
음악 중간부터 재생  (0) 2019.04.28
UI Image의 크기조정  (0) 2018.10.29
코루틴 콜백 받기  (0) 2018.10.28