• 티스토리 홈
  • 프로필사진
    개양반
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
개양반
  • 프로필사진
    개양반
    • Everybody Happyvirus (87)
      • Unity DOTS (19)
        • ECS Sample Projtect (8)
        • Unity.Physics (1)
        • TIP (9)
      • Unity Assets 추천 (6)
        • BG Database (5)
        • I2 Localization - 현지화 (1)
      • Unity 자습서 (15)
        • Addressable (4)
        • 유니티 + 파이어베이스 (0)
        • GamingServices (10)
      • 주식 이야기 (4)
        • 회사 소개 (2)
        • 회사 정보 (1)
        • 실적 발표 (0)
      • 일상 생활 (9)
        • 도서리뷰 (2)
        • 제품리뷰 (6)
      • 게임일기 (2)
        • 리그오브레전드 (2)
      • 게임소개 (4)
      • 게임리뷰 (7)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • 파이어베이스 유니티 Realtime Database
        2017년 11월 21일
        • 개양반
        • 작성자
        • 2017.11.21.오전05:22

        선행 작업


        SDK 다운로드 [내용보기]

        이메일/비밀번호 로그인 [내용보기]

         

         

        FirebaseDatabase SDK 임포트


        앞에서 다운로드한 SDK 중에 FirebaseDatabase.unitypackage 를 로그인을 완료한 유니티프로젝트에

        임포트합니다. (PS: 임포트할 때, 오류가 생겼는데 다시 유니티를 실행하고 임포트하니 잘되네요.)

         

        파이어베이스 콘솔창 설정 변경


        콘솔창에서 Database > 시작하기 버튼 클릭을 합니다.

         

        변경된 google-services.json 파일을 다시 다운받고 유니티의 google-services 파일은 변경해줍니다.

        ( 위 내용은 앞의 포스팅에서 설명했습니다. )

         

        SetEditorServiceAccountEmail 가져오기


        지금 세팅하는 것은 유니티 에디터에서 파이어베이스 데이터베이스를 사용하려면 필요한 세팅입니다. ( 이 세팅을 안해도 모바일에서는 잘 됩니다. )

        Firebase 콘솔창에서 좌측 상단 톱니바퀴를 누르시고 설정으로 들어가서 프로젝트ID 를 복사합니다.

         

         

        https://console.cloud.google.com/iam-admin/serviceaccounts/project?project=프로젝트ID 를 인터넷 주소창에 입력합니다.

        그럼 프로젝트의 서비스 계정 어쩌고 하는 페이지로 이동하는데요. 작업이라고 적힌 버튼을 클릭해서 키 만들기를 선택합니다.

         

        P12 형식을 사용하는 코드와의 하위 호환용 을 선택하고 만들기 버튼을 눌러주세요.

         

        그럼 파일 하나를 다운 받는데요. 그거를 유니티의 Editor Defult Resources 로 붙여넣기 합니다.

         

         

         

        DatabaseReference 가져오기


        먼저 유저정보를 다른 스크립트에서 가져오기 위해 

        Login.cs 의 FirebaseUser user; 변수를 스테틱으로 선언합니다.

        FirebaseUser user -> public static FirebaseUser user;

         

         

        유니티에 RealtimeDatabase.cs 를 만듭니다.

        아래 코드를 입력합니다.

        using UnityEngine;
        using Firebase.Unity.Editor;
        using Firebase.Database;
        using Firebase;
        
        public class RealtimeDatabase : MonoBehaviour
        {
            FirebaseApp firebaseApp;
            DatabaseReference databaseReference;
        
        
            private void Awake()
            {
                firebaseApp = FirebaseDatabase.DefaultInstance.App;
                firebaseApp.SetEditorDatabaseUrl("https://firsttestapp-eac16.firebaseio.com/");
                databaseReference = FirebaseDatabase.DefaultInstance.RootReference;
        	FirebaseApp.DefaultInstance.SetEditorFileName("파일이름.p12");
        
        	// 아래 비밀번호에는 특별하게 설정한거 없으면 notasecret 일 겁니다.
        	FirebaseApp.DefaultInstance.SetEditorP12Password("notasecret");
            } 
            
        }

         

         

        firebaseApp.SetEditorDatabaseUrl( "콘솔창의 정보를 입력해야 한다." );

         

        데이터 쓰기


        RealtimeDatabase.cs 에 아래 코드를 추가합니다.

            public void InitDatabase()
            {
                if (Login.user != null)
                {
                    WriteNewUser(Login.user.UserId , Login.user.DisplayName, Login.user.Email);
                }
            }
        
            private void WriteNewUser(string uid, string name, string email)
            {
                User user = new User(name, email);
                string json = JsonUtility.ToJson(user);
                databaseReference.Child("users").Child(uid).SetRawJsonValueAsync(json);
            }
         

         

        Hierarchy 에 Database 라는 오브젝트를 만들고 RealtimeDatabase.cs를 연결해줍니다.

        데이터를 저장시켜주는 버튼을 만든 다음 클릭이벤트에 Database 를 연결해줍니다.

         

        모바일로 빌드하고 저장버튼을 누르면 유저의 이름과 이메일주소가 저장됩니다.

         

        콘솔창에서 저장된 데이터가 보이네요~

        databaseReference.Child("users").Child(uid).SetRawJsonValueAsync(json);

        는 동일한 uid 가 들어오면 SetRawJsonValueAsync 의 데이터로 덮어 씌웁니다.

         

        특정 변수값만 변경하고 싶다면

        databaseReference.Child("users").Child(uid).Child("username").SetValueAsync(name);

        를 입력하시면 됩니다.

         

         

        특정 필드 업데이트


        다른 하위 노드를 덮어쓰지 않고 특정 하위 노드에 여러개를 동시에 쓰기를 하려면 

        UpdateChildrenAsync()updateChildValues() 메소드를 사용합니다.

        public void OnClickUpdateChild()
            {
                Dictionary<string, object> childUpdates = new Dictionary<string, object>();
                childUpdates["/users/" + Login.user.UserId + "/" + "username"] = Login.user.DisplayName;
                childUpdates["/users/" + Login.user.UserId + "/" + "score"] = 100;
        
                databaseReference.UpdateChildrenAsync(childUpdates);
            }
         

         

         

        데이터 푸쉬


        전투 로그처럼 데이터를 덮어씌우지 않고 새로 저장해야 할 때가 있습니다.

        이럴 때는 Push() 를 사용 합니다.

        	public void OnClickPush()
            {
                Dictionary<string, object> childUpdates = new Dictionary<string, object>();
                childUpdates["/users/" + Login.user.UserId + "/" + "username"] = Login.user.DisplayName;
                childUpdates["/users/" + Login.user.UserId + "/" + "score"] = 100;
        
                databaseReference.Push().Child(Login.user.UserId).UpdateChildrenAsync(childUpdates);
            }
         

         

        트랜잭션으로 저장하기


        여러 사람이 쓰는 데이터는 동시 수정으로 데이터가 손상될 수 있습니다.

        예로 랭킹같은 경우 여러 유저가 랭킹데이터를 수정하기 때문에 수정 작업 중에

        데이터가 손상되어 각 유저의 랭킹정보가 달라질 수 있죠.

         

        이럴 때 사용하는 것이 트랜잭션이라고 합니다.

        public void OnClickTransactionSave()
            {
                const int MaxScoreRecordCount = 5;
                int score = Random.Range(0, 100);
                string email = "testEmail";
        
                databaseReference.Child("users").RunTransaction(mutableData => {
                    List<object> leaders = mutableData.Value as List<object>;
        
                    if (leaders == null)
                    {
                        leaders = new List<object>(); 
                    }
        
                    // 랭킹에 등록된 점수를 비교합니다.
                    else if (mutableData.ChildrenCount >= MaxScoreRecordCount)
                    {
                        long minScore = long.MaxValue;
                        object minVal = null;
                        foreach (var child in leaders)
                        {
                            if (!(child is Dictionary<string, object>))
                                continue;
                            long childScore = (long)((Dictionary<string, object>)child)["score"];
                            if (childScore < minScore)
                            {
                                minScore = childScore;
                                minVal = child;
                            }
                        }
                        if (minScore > score)
                        {
                            // 현재 점수가 최하위 점수보다 낮으면 중단합니다.(랭킹에 못오르니깐)
                            return TransactionResult.Abort();
                        }
        
                        // 기존 최하위 데이터를 제거합니다.(랭킹 변경)
                        leaders.Remove(minVal);
                    }
        
                    Dictionary<string, object> newScoreMap = new Dictionary<string, object>();
        
                    newScoreMap["score"] = score;
                    newScoreMap["email"] = email;
        
                    leaders.Add(newScoreMap);
                    mutableData.Value = leaders;
                    return TransactionResult.Success(mutableData);
                });
            }

         

         

         

        기록을 비교하는 중간의코드를 제외하면 이해하기 쉬우실겁니다.

        // 가져올 데이터의 이름
        databaseReference.Child("users").RunTransaction(mutableData => {
                    List<object> leaders = mutableData.Value as List<object>;
                    /* 작업할 내용 시작
                    
                        // 랭킹 5위의 기록을 비교하면서
                        // 현재 점수가 5위 안에 들어갈 수 있는지 등을
                        // 체크
        
                    작업할 내용 끝   */
        
                    Dictionary<string, object> newScoreMap = new Dictionary<string, object>();
                    leaders.Add(newScoreMap);            
                    mutableData.Value = leaders; // 랭킹 5위의 기록을 덮어씌웁니다.
                    return TransactionResult.Success(mutableData); // 값을 전달합니다.
        }

         

         

        기타 설명


        네크워크가 종료되어도 자동으로 로컬에 저장한 뒤에 해당 데이터를 원격 데이터베이스 서버 및 다른 클라이언트와 '최선을 다해' 동기화 한다고 하네요. ( 최선을 다한다는게 무섭네요? )

        네트워크에 다시 연결되면 앱에서 해당 이벤트 세트를 수신하여 클라이언트와 현재 서버 상태를 동기화한다고 합니다.

        그래서 별도의 코드를 작성할 필요가 없다네요.

         

        데이터 삭제


        데이터를 삭제하는 코드는 간단합니다.

        지울려는 대상.RemoveValueAsync() 를 하면 됩니다.

         public void OnClickRemove()
            {
                databaseReference.Child("users").Child("노드이름").Child("노드이름")
        	.RemoveValueAsync();
            }
         

         

        데이터 읽기


         

        한번만 읽어오기


        public void OnClickDataRead()
            {
                FirebaseDatabase.DefaultInstance
                    .GetReference("users") // 읽어올 데이터 이름
                    .GetValueAsync().ContinueWith(task =>
                    {
                        if (task.IsFaulted)
                        {
                        }
                        else if (task.IsCompleted)
                        {
                            DataSnapshot snapshot = task.Result;
                            
                            // DataSnapshot 타입에 저장된 값 불러오기
                            foreach (var item in snapshot.Children)
                            {
                                Debug.Log(item.Child("email").Value);
                                Debug.Log(item.Child("score").Value);
                            }
                        }
                    });
            }
         
         

         

        이벤트 수신해서 읽어오기


        데이터베이스에 저장된 값이 변경/삭제/이동/추가 등을 감지하고 각 클라이언트에게 변경된 내용을

        동기화시켜줄 수 도 있습니다. 

        public void OnClickEventListner()
            {
                
                DatabaseReference reference = FirebaseDatabase.DefaultInstance.GetReference("users");
                
                reference.ValueChanged += HandleValueChanged;
                reference.ChildAdded += HandleChildAdded;
                reference.ChildChanged += HandleChildChanged;
                reference.ChildRemoved += HandleChildRemoved;
                reference.ChildMoved += HandleChildMoved;
            }
        
            //users 데이터 전체의 변화에 수신
            void HandleValueChanged(object sender, ValueChangedEventArgs args)
            {
                if (args.DatabaseError != null)
                {
                    Debug.LogError(args.DatabaseError.Message);
                    return;
                }
                SnapshotAllDataRead(args.Snapshot);
            }
        
            //users 데이터의 하위목록의 값이 추가되면 수신
            void HandleChildAdded(object sender, ChildChangedEventArgs args)
            {
                if (args.DatabaseError != null)
                {
                    Debug.LogError(args.DatabaseError.Message);
                    return;
                }
                SnapshotDataRead(args.Snapshot);
            }
        
        
            //users 데이터의 하위목록의 값이 변경되면 수신
            void HandleChildChanged(object sender, ChildChangedEventArgs args)
            {
                if (args.DatabaseError != null)
                {
                    Debug.LogError(args.DatabaseError.Message);
                    return;
                }
                SnapshotDataRead(args.Snapshot);
            }
        
            //users 데이터의 하위목록의 값이 제거되면 수신
            void HandleChildRemoved(object sender, ChildChangedEventArgs args)
            {
                if (args.DatabaseError != null)
                {
                    Debug.LogError(args.DatabaseError.Message);
                    return;
                }
                SnapshotDataRead(args.Snapshot);
            }
        
            //users 데이터의 하위목록의 값이 이동하면 수신
            void HandleChildMoved(object sender, ChildChangedEventArgs args)
            {
                if (args.DatabaseError != null)
                {
                    Debug.LogError(args.DatabaseError.Message);
                    return;
                }
                SnapshotDataRead(args.Snapshot);
            }
        
        
            // 데이터를 읽어온다.
            public void SnapshotDataRead(DataSnapshot Snapshot)
            {
                DataSnapshot snapshot = Snapshot;
        
                foreach (var item in snapshot.Children)
                {
                    Debug.Log(item.Value);
                }
            }
        
            public void SnapshotAllDataRead(DataSnapshot Snapshot)
            {
                foreach (var item in Snapshot.Children)
                {
                    Debug.Log(item.Child("email").Value +" : "+ item.Child("score").Value);
                 }
            }
         
         

        데이터 정렬


        하위 키의 값에 따라 / 하위 키에 따라 / 하위 값에 따라 결과를 정렬할 수 있습니다.

        아래는 score 로 정렬한 방법에 대한 내용입니다.

        public void OnClickOrderby()
            {
                FirebaseDatabase.DefaultInstance
                    .GetReference("users").OrderByChild("score")
                    .GetValueAsync().ContinueWith(task =>
                    {
                        if (task.IsFaulted)
                        {
                        }
                        else if (task.IsCompleted)
                        {
                            DataSnapshot snapshot = task.Result;
        
                            foreach (var item in snapshot.Children)
                            {
                                Debug.Log(item.Child("email").Value + " : " + item.Child("score").Value);
                            }
                        }
                    });
            }​

         

         

        보안규칙


        파이어베이스(firebase) 콘솔창의 Database -> 규칙탭에서 유저의 쓰기/읽기 권한을 조절할 수 있습니다.

        예로 쓰기할때는 

        자신의 유저노드에만 쓸 수 있고 타인의 유저노드는 읽기만 가능하도록 할 수 있습니다.

        위의 내용은 디바이스에서 테스트할 때만 적용됩니다.

         

        규칙에서는 데이터 관련 다양한 규칙들을 설정할 수 있습니다.

        입력 글자 수 제한 등

        저작자표시 비영리 (새창열림)

        'Unity 자습서 > 유니티 + 파이어베이스' 카테고리의 다른 글

        파이어베이스(firebase) Cloud Functions #2  (0) 2017.11.22
        파이어베이스(firebase) Cloud Functions #1  (2) 2017.11.22
        파이어베이스 유니티로 구글로그인  (10) 2017.11.17
        파이어베이스 유니티 로그인(이메일/비밀번호)  (4) 2017.11.16
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바

        개인정보

        • 티스토리 홈
        • 포럼
        • 로그인

        단축키

        내 블로그

        내 블로그 - 관리자 홈 전환
        Q
        Q
        새 글 쓰기
        W
        W

        블로그 게시글

        글 수정 (권한 있는 경우)
        E
        E
        댓글 영역으로 이동
        C
        C

        모든 영역

        이 페이지의 URL 복사
        S
        S
        맨 위로 이동
        T
        T
        티스토리 홈 이동
        H
        H
        단축키 안내
        Shift + /
        ⇧ + /

        * 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.