- 파이어베이스 유니티 Realtime Database2017년 11월 21일
- 개양반
- 작성자
- 2017.11.21.: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 다음글이전글이전 글이 없습니다.댓글