Lightweight Firebase Library, made on top of REST API.
Implement Firebase to any Project without importing any Firebase SDK. This Library comes with all major features of Firebase SDK, including Realtime Database, Authentication, Storage and others are coming soon.
Open Package Manager in Unity and Click on Plus Icon -> Add package from git URL, paste following link https://github.com/SrejonKhan/FirebaseRestClient.git
and click Add.
Other methods (Asset Store, UPM, Release Page) will be added later after a stable release.
After importing to your project, Open Settings from (Edit -> Project Settings -> Firebase Rest Client). This is where we will set all api configuration.
- Go to Google Cloud Platform and Create a Project
- Go to Firebase Console and Create New Project. While creating project, make sure to connect GCP Project rather than creating new one.
- After creating Firebase Project, enable your desired service(s) e.g Authentication / Realtime Database.
- Remember, for Web API Key, you need to enable Authentication. Else, it will be empty.
This is recommended way to setup project if you're planning add authentication. If you're only planning to use Realtime Database with no authentication, try below procedures. Please keep in mind, if you connect your Firebase Project with GCP Project, there are somethings to remember. For instance, if you delete Firebase Project, it will delete your GCP project too.
- Go to Firebase Console and Create New Project. This time, no need to connect any GCP Project.
- After creating Firebase Project, enable your desired service(s) e.g Authentication / Realtime Database.
- Remember, for Web API Key, you need to enable Authentication. Else, it will be empty.
If you follow this procedure, and planning to add Google Sign-In SDK, you may face some problem with ClientId and Secret. It's better to follow recommended procedure to avoid any unwanted problem.
This library is so far supporting Realtime Database, Authentication and Storage from Firebase. Planning to add more support in future.
- Read
- RawRead (Json Format)
- Push
- Write
- Update
- Remove
- Child Events
- OnValueChanged
- OnChildAdded
- OnChildRemoved
- OnChildChanged
- Ordering
- Order by Key
- Order by Value
- Order by Child value
- Filtering
- StartAt
- EndAt
- EqualTo
- LimitTo
- Locally generate Push ID
- Email-Password Authentication
- Login and Registration
- Forget Password Email
- Email Verification Email
- Change Email/Password
- Anonymous Authentication
- OAuth Login
- Login with oauth token from any provider
- Google OAuth Desktop Flow (Loopback)
- User Profile Actions (Display Name, Photo URL)
- Change/Add Display Name
- Change/Add Photo URL
- Get full profile
- Upload File
More Features are being added on regular basis.
This is a general documentation. In future, there will be fully explained video and Knowledgebase. For any immediate support or discussion, join the Discord Server.
new RealtimeDatabase().ReadKeyValuePairs<User>();
new RealtimeDatabase().ReadKeyValuePairs();
new RealtimeDatabase().ReadValue();
new RealtimeDatabase().RawRead();
new RealtimeDatabase().RawRead(true);
new RealtimeDatabase().Read<User>();
new RealtimeDatabase().Push(user);
new RealtimeDatabase().Push(jsonString);
new RealtimeDatabase().WriteValue(user);
new RealtimeDatabase().WriteValue(jsonString);
new RealtimeDatabase().WriteKeyValuePair("key","value");
new RealtimeDatabase().WriteKeyValuePair("key","value", true);
new RealtimeDatabase().Update(user);
new RealtimeDatabase().Update(jsonString);
new RealtimeDatabase().ChildAdded(res => { });
new RealtimeDatabase().ChildRemoved(res => { });
new RealtimeDatabase().ChildChanged(res => { });
new RealtimeDatabase().ValueChanged(res => { });
new RealtimeDatabase().OrderByKey().OnSuccess(json => { });
new RealtimeDatabase().OrderByValue().OnSuccess(json => { });
new RealtimeDatabase().OrderByChild("id").OnSuccess(json => { });
new RealtimeDatabase().LimitToFirst(10).OrderByChild("id").OnSuccess(json => { });
new RealtimeDatabase().LimitToLast(5).OrderByChild("id").OnSuccess(json => { });
new RealtimeDatabase().StartAt(25).OrderByChild("id").OnSuccess(json => { });
new RealtimeDatabase().EndAt(125).OrderByChild("id").OnSuccess(json => { });
new RealtimeDatabase().EqualTo("srejon").OrderByChild("username").OnSuccess(json => { });
string pushId = new RealtimeDatabase().GeneratePushID();
var firebase = new RealtimeDatabase();
firebase.Child("users").ReadKeyValuePairs().OnSuccess(res =>
{
//Returns response in Dictionary<string,string> (Dictionary<string,string>)
//item.value.id is a property of user class
foreach (var item in res)
Debug.Log($"Key: {item.Key} - Value: {item.Value}\n");
}).
OnError(error =>
{
Debug.LogError(error.Message);
});
firebase.Child("users").ReadKeyValuePairs<User>().OnSuccess(res =>
{
//Returns response in Dictionary<string,User> (Dictionary<string,T>)
//item.value.id is a property of user class
foreach (var item in res)
Debug.Log($"Key: {item.Key} - Value: {item.Value.id}\n");
});
firebase.Child("notices/51").ReadValue().OnSuccess(res =>
{
//response can be in Json or simple string value
//JSON will be returned if child value is an json object
//simple string value will be returned if child value represents key-pair value
Debug.Log(res);
});
firebase.Child("user/999").Read<User>().OnSuccess(res =>
{
//response will be converted to desired type
//Throws JsonUtilty error if couldn't be converted to desired type
//best case to use when value is known as an object
Debug.Log(res);
});
firebase.Child("product").Child("orange").RawRead().OnSuccess(res =>
{
//Returns response in Json string
Debug.Log(res);
});
//Shallow
firebase.Child("product").Child("orange").RawRead(true).OnSuccess(res =>
{
//Returns response in Json string
Debug.Log(res);
});
Push functionality in this library is a bit different from actual Firebase SDK. In this library, when Push() function called, it implicitly complete followings task -
- Generate a Push ID locally
- Write passed body to following path (childs + push id)
- Returns generated Push ID as string
If you just want a Push ID, not directly writing, you can call firebase.GeneratePushID()
, which returns push id in string format.
var userObject = new User("DefaultName");
firebase.Child("users").Push(userObject).OnSuccess(uid =>
{
//Returns Push ID in string
Debug.Log(uid);
});
string jsonString = JsonUtility.ToJson(userObject);
firebase.Child("users").Push(jsonString).OnSuccess(uid =>
{
//Returns Push ID in string
Debug.Log(uid);
});
// Write to specific node
// Object as payload, it can be any datatypes, even raw Json
firebase.Child("product").Child("orange").WriteValue(anyObject).OnSuccess( () =>
{
Debug.Log("Successfully written.");
});
firebase.Child("product").Child("orange").WriteValue(123);
firebase.Child("product").Child("orange").WriteValue(324.25f);
firebase.Child("product").Child("stockout").WriteValue(true);
// Key and Value Pair, suitable for key-value pair leaderboard or similar.
firebase.Child("leaderboard").WriteKeyValuePair("player123", "123");
firebase.Child("leaderboard").WriteKeyValuePair("player321", "521", true); //append to parent
// Object as payload
firebase.Child("users").Child("123").Update(user).OnSuccess( () => { /*...Codes...*/ });
// Json string as payload
firebase.Child("users").Child("123").Update(jsonString);
// Primitive datatype as payload
firebase.Child("users").Child("123").Update(5654.5f);
firebase.Child("users").Child("123").Update(123);
firebase.Child("users").Child("123").Update(false);
firebase.Child("product").Child("orange").Remove().OnSuccess( () => { /*...Codes...*/ });
firebase.Child("product").Child("orange").Remove();
There are 4 types of Events available in this library.
- ChildAdded
- ChildRemoved
- ChildChanged
- ValueChanged
Listen for Child addition to targeted path and in-depth.
Recommended not to use in root level, as internally a snapshot creates and run query internally on each put
response from server to differentiate among Update and Addition.
If it is required to listen in root level childs only, use bool shallow = true
for listen to surface level child, not in-depth childs.
firebase.Child("notices").ChildAdded(res =>
{
//Firebase send full snapshot of child node, you can ignore by checking isInitial
if (res.isInitial)
Debug.Log(res.path + " | " + res.data);
//This is real snapshot of event, you will get Json from res.data
else
Debug.Log(res.path + "\n" + res.data);
});
//Shallow Read
firebase.Child("users").ChildAdded(res =>
{ /*...Codes...*/ }, true); //true indicates shallow read, by default is false
Listen for Child Remove at any level from targeted path.
firebase.Child("users").ChildRemoved(res =>
{
//Firebase send full snapshot of child node, you can ignore by checking isInitial
if (res.isInitial)
Debug.Log(res.path + " | " + res.data);
//This is real snapshot of event, you will get null from res.data
else
Debug.Log(res.path + "\n" + res.data);
});
//Shallow Read
firebase.Child("users").ChildRemoved(res =>
{ /*...Codes...*/ }, true); //true indicates shallow read, by default is false
Combination of both ChildAdded and ChildRemoved.
firebase.Child("messages").ChildChanged(res =>
{
//Firebase send full snapshot of child node, you can ignore by checking isInitial
if (res.isInitial)
Debug.Log(res.path + " | " + res.data);
//This is real snapshot of event, you will get Json or null from res.data
else
Debug.Log(res.path + "\n" + res.data);
});
//Shallow Read
firebase.Child("users").ChildChanged(res =>
{ /*...Codes...*/ }, true); //true indicates shallow read, by default is false
Remember, as ChildChanged
listen to both Add and Remove event, to make differentiate, check if(res.data == "null")
. If server returns null
in string format, that means a child was removed at specific path.
Union of all server events.
firebase.ValueChanged(res =>
{
//Firebase send full snapshot of child node, you can ignore by checking isInitial
if (res.isInitial)
Debug.Log(res.path + " | " + res.data);
//This is real snapshot of event, you will get Json or null from res.data
else
Debug.Log(res.path + "\n" + res.data);
});
//Shallow Read
firebase.Child("users").ValueChanged(res =>
{ /*...Codes...*/ }, true); //true indicates shallow read, by default is false
Order functions return a Json String. Remember, returned JSON isn't in order, as JSON interpreters don't enforce any ordering. Same applies to any filtered result.
If you want to order, you have to order itself in application. I'm planning to write a helper function to order json in future updates.
Remember, before using order function, make sure to Index your Database Rules. You can use OnError
callback before setting up a index rules. OnError
will throw error and tell exactly what is needed to add in index rules.
firebase.Child("users").OrderByKey().OnSuccess(json =>
{
//returns json string
});
firebase.Child("leaderboard").OrderByValue().OnSuccess(json =>
{
//returns json string
});
firebase.Child("users").OrderByChild("id").OnSuccess(json =>
{
//returns json string
});
Things to remember while filtering -
- Filter functions come before Order function. E.g
StartAt("5").OrderByKey()
- Returned JSON isn't in order, as JSON interpreters don't enforce any ordering.
- Filter functions params are in string, if you pass
5
as string, it will count it as number. If you want to filter by string, pass string inside quoutes. E.gEqualTo(""\Orange"\")
If you want to order, you have to order itself in application. I'm planning to write a helper function to order json in future updates.
//StartAt
firebase.Child("users").StartAt("5").OrderByKey().OnSuccess(json =>
{
//returns json string
});
//EndAt
firebase.Child("users").EndAt("125").OrderByKey().OnSuccess(json =>
{
//returns json string
});
//LimitToFirst
firebase.Child("users").LimitToFirst("25").OrderByChild("id").OnSuccess(json =>
{
//returns json string
});
//LimitToLast
firebase.Child("users").LimitToLast("25").OrderByChild("id").OnSuccess(json =>
{
//returns json string
});
//EqualTo
firebase.Child("users").EqualTo("\"John Doe\"").OrderByChild("name").OnSuccess(json =>
{
//returns json string
});
string pushId = firebase.GeneratePushID();
FirebaseAuthentication firebaseAuth = new FirebaseAuthentication();
firebaseAuth.CreateUserWithEmailAndPassword(email, password); //Password Signup
firebaseAuth.SignInWithEmailAndPassword(email, password); //Password Signin
firebaseAuth.SignInAnonymously(); //Anonymous SignIn
firebaseAuth.SignInWithOAuth("ACCESS_TOKEN_FROM_PROVIDER", "YOUR_PROVIDER_ID"); //OAuth SignIn
firebaseAuth.GoogleSignIn("AUTH_CODE_FROM_GOOGLE_TO_EXCHANGE_ACCESS_TOKEN"); //Google SignIn
firebaseAuth.FacebookSignIn("AUTH_CODE_FROM_FACEBOOK_TO_EXCHANGE_ACCESS_TOKEN"); //Facebook SignIn
firebaseAuth.SendPasswordResetEmail(email); //Password Reset Mail
firebaseAuth.SendEmailVerification(); //Email Verification (user must be signed in)
firebaseAuth.RefreshIdToken(refreshToken);
firebaseAuth.GetUserFromIdToken(idToken);
FirebaseUser user = firebaseAuth.CurrentUser; //Current User automatically updates after any sign-in actions
user.ChangeEmail(newEmail); //Change Email
user.ChangePassword(newPassword); //Change Password
user.UpdateProfile("NEW_DISPLAY_NAME", "PHOTO_URL"); //Update Profile
user.Reload(); //Refresh User
user.RefreshAccessToken(); //Force to refresh token
user.Delete(); //Delete user
//User props
string displayName = user.DisplayName;
string userEmail = user.Email;
bool isEmailVerified = user.IsEmailVerified;
bool isAnonymous = user.IsAnonymous;
string photoUrl = user.PhotoUrl;
string provider = user.Provider;
firebaseAuth.SignOut(); //Sign out any signed-in user
firebaseAuth.StateChanged += AuthStateChanged;
// Track state changes of the auth object.
void AuthStateChanged(object sender, System.EventArgs eventArgs)
{
if (firebaseAuth.CurrentUser != user)
{
bool signedIn = user != firebaseAuth.CurrentUser && firebaseAuth.CurrentUser != null;
if (!signedIn && user != null)
{
Debug.Log("Signed out " + user.LocalId);
}
user = firebaseAuth.CurrentUser;
if (signedIn)
{
Debug.Log("Signed in " + user.LocalId);
}
}
}
We can reauthenticate user with Refresh Token. IdToken generally expires in one hour, where Refresh Token in Firebase usually long lived unless any major action taken to account (Password Change, Email change etc.).
Reauthentication should be done from the library, but as there is not any proper implementation for persistency, Library won't take liability of Reauthentication. Anyway, library provides some methods to reauthenticate from User side.
// Step 1 - Get new IdToken using Refresh Token
string refreshToken = /*Get refresh token*/;
firebaseAuth.RefreshIdToken(refreshToken).
OnSuccess(res =>
{
// Step 2 - Get User using IdToken
firebaseAuth.GetUserFromIdToken(res.accessToken).
OnSucess(user =>
{
// user authenticated
// do your work
});
});
var firebaseStorage = new FirebaseStorage();
string filePath = @"D:\Download\audacity-win-2.4.2.exe";
firebaseStorage.Upload(filePath, "File_From_File_Path_Array", progress =>
{
Debug.Log(progress);
}).
OnSuccess(res =>
{
//res = UploadResponse
Debug.Log(res.downloadUrl);
}).
OnError(err => Debug.LogError(err.Message));
byte[] data = File.ReadAllBytes(filePath);
firebaseStorage.Upload(data, "File_From_Byte_Array", progress =>
{
Debug.Log(progress);
}).
OnSuccess(res =>
{
//res = UploadResponse
Debug.Log(res.downloadUrl);
});
Progress are between 0~1. Progress action can be passed as null argument, or simply without passing any.
firebaseStorage.Upload(filePath, "File_From_File_Path_Array", null);
firebaseStorage.Upload(filePath, "File_From_File_Path_Array");
-
Download Google SignIn SDK and Unity Jar Resolver. When importing SignIn SDK, make sure to exclude Parse & PlayServicesResolver folder. After importing SignIn Sdk, Import
external-dependency-manager-latest.unitypackage
from Unity Jar Resolver. -
Go to Configure Project and configure your desired project.
-
Make sure Android is selected and exact Package Name and SHA-1 cert provided same as your project Package Name. For creating Keystore, use Unity's default Keystore Manager and for generating SHA-1 Certificate, use Keystore Explorer or command.
-
Go to Credential Tab in GCP and click on Web client (Auto-created for Google Sign-in) in OAuth 2.0 Client IDs Section.
-
Add http://127.0.0.1:5050 in Authorized Redirect URIs.
-
Copy Client ID and Client Secret, paste them in Firebase Configuration (Edit -> Project Settings -> Firebase Rest Client).
-
Enable Google SignIn Method in Firebase Authentication. And copy Client ID and Client Secret from GCP (Step 4) and Paste them in Web SDK Configuration.
-
Invoke this code when necessery.
GoogleSignIn.Configuration = new GoogleSignInConfiguration { RequestIdToken = true, // Copy this ClientID from GCP OAuth Client IDs(Step 4). WebClientId = "723306904970-2kdkej7jcucl2b8kktpvivucov6t0r76.apps.googleusercontent.com", RequestAuthCode = true, AdditionalScopes = new List<string>() { "https://www.googleapis.com/auth/userinfo.email" } //Scope for Email }; //Google Sign-In SDK Task<GoogleSignInUser> signIn = GoogleSignIn.DefaultInstance.SignIn(); signIn.ContinueWith(task => { if (task.IsCanceled) { Debug.LogError("Cancelled"); } else if (task.IsFaulted) { Debug.LogError(task.Exception.Message); using (IEnumerator<System.Exception> enumerator = task.Exception.InnerExceptions.GetEnumerator()) { if (enumerator.MoveNext()) { GoogleSignIn.SignInException error = (GoogleSignIn.SignInException)enumerator.Current; Debug.LogError("Got Error: " + error.Status + " " + error.Message); } else { Debug.LogError("Got Unexpected Exception?!?" + task.Exception); } } } //No Error else { string authCode = task.Result.AuthCode; //Auth Code //Signing-in to Firebase Auth firebaseAuth.GoogleSignIn(authCode).OnSuccess(user => { string resulText = $"\n " + $"Email: {user.Email}, \n " + $"Local ID : {user.LocalId}, \n " + $"Provider : {user.Provider}, \n " + $"Is Anon : {user.IsAnonymous}, \n " + $"Display Name : {user.DisplayName}"; Debug.Log(resulText); }). OnError(error => { Debug.Log(error.Message); }); } });
-
DONE!
-
Skip if you have already configured GCP Project. If you're planning to implement Google Sign-In both for Android/IOS and Standalone, follow previous segment to configure project. If you're only planning for Desktop Sign-In, follow all steps below-
- Go to Credential Tab in GCP and click on Create Credentials -> OAuth Client ID
- Select Web Application as Application Type.
- Give meaningful name
- Add
http://127.0.0.1:5050
to Authorized redirect URIs. - Click Create
-
Go back to Credential Tab in GCP and click on previously created Client ID in OAuth 2.0 Client IDs Section.
-
Copy Client ID and Client Secret, paste them in Firebase Configuration (Edit -> Project Settings -> Firebase Rest Client). You can either get ID and Secret from Firebase or GCP.
-
Enable Google SignIn Method in Firebase Authentication. And copy Client ID and Client Secret from GCP (Step 3) and Paste them in Web SDK Configuration.
-
Invoke this code when necessary.
firebaseAuth.GoogleSignInLoopback().OnSuccess(user => { string resulText = $"\n " + $"Email: {user.Email}, \n " + $"Local ID : {user.LocalId}, \n " + $"Provider : {user.Provider}, \n " + $"Is Anon : {user.IsAnonymous}, \n " + $"Display Name : {user.DisplayName}"; Debug.Log(resulText); }). OnError(error => { Debug.Log(error.Message); });
-
Done!
There will be a well written Documentation on a Stable Release and web-based Wiki in future.
This library is still under development. All limitations are being resolved one-by-one. Check CHANGELOG for more details.