W2D5: Microservices: how games talk to backends
Wiring a Unity game to Firebase — email auth, push notifications and a realtime database, plus the Android build setup needed to test it on a real phone.
Lucian Lazar · 20 Jul 2024
Last session of week two, and it’s the one where the game stops being a closed box on your machine. Lucian walks through what a microservice actually is in game terms, then spends most of the three hours proving it with Firebase: registration and login, push notifications delivered to a physical Android phone, and a realtime database storing per-user data. There’s theory at the front, but the bulk is hands-on and occasionally goes wrong on camera, which is arguably the useful part.
What’s covered
The concept, without the buzzword fog
- Microservices as small backend apps, each specialised for one job: chat, leaderboards, matchmaking, inventory, auth, purchases.
- Third-party vs internal. PlayFab, Amazon GameLift, Firebase on one side; your own server with your own uncensored LLM or your own leaderboard on the other.
- Why you should start with a monolith. Splitting your backend into separate services running in different regions is a problem you get after you have a team and traffic, not before.
- Idle games as the clearest case: the logic runs on the server, the client is a window onto it, and a push notification tells the player their crops are done.
- Hosting options, with a dry aside that Google Cloud is unnecessarily complicated at times.
Firebase setup done the lean way
- Creating a project, disabling analytics, enabling the email/password sign-in provider.
- Downloading only the
.tgzpackages you need — external dependency manager, Firebase App (core), Auth, Messaging, Realtime Database — into aGooglePackagesfolder next to the project. - Wiring them up by hand in
Packages/manifest.jsonwith relativefile:../paths, instead of importing the giant Unity SDK. Lucian is firm about this: import what you need, know what you have, avoid the headaches. google-services.json, bundle identifiers, and why you decide the bundle ID in Unity first and then match it in Firebase.
Auth, messaging, database
- A canvas with two TMP input fields and two buttons, with click listeners added in code rather than dragged in the inspector — so the logic lives in one place and fields stay private.
- Push notifications: getting the FCM token, subscribing to
TokenReceivedandMessageReceived, and unsubscribing inOnDestroybecause the messaging object outlives the scene. - A detour into C# events,
+=, lambdas and event parameters, since the messaging API forces you to use them. - Realtime database with an assembly definition file, because Firebase ships DLLs that aren’t auto-referenced.
Android build reality
- Developer options, USB debugging, IL2CPP, target API 33, custom Gradle templates, force resolve.
- Faster builds vs faster runtime, and why you flip that switch back before you ship.
Timestamps
- 00:04:30 — Switching to the day-five branch in the repo, and where the branch switcher lives in Rider vs VS Code
- 00:08:00 — Week two recap and an honest note that this session is theory-heavy by design
- 00:11:00 — What a microservice actually is: mobile, web and desktop clients hitting the same backend
- 00:17:00 — Third-party services vs your own: PlayFab, GameLift, Firebase, and rolling your own LLM endpoint
- 00:24:00 — Monolith first. Splitting into separate services comes much later, when the project outgrows you
- 00:29:00 — Push notifications explained through the idle-farming-game example
- 00:36:00 — Creating the Firebase project, disabling analytics, enabling email/password sign-in
- 00:44:00 — Downloading the
.tgzpackages and editingmanifest.jsonby hand instead of importing the full SDK - 00:58:00 —
google-services.json, bundle identifier, and matching it in player settings - 01:08:00 — Building the login canvas, then the auth script:
FirebaseAuth.DefaultInstanceandContinueWithOnMainThread - 01:22:00 — Live register and login, including a too-short password and a deliberately wrong one
- 01:29:00 — Scripting define symbols and
#ifblocks stripping code out of the build - 01:33:00 — Viewing users in the console, and why passwords are hashed (with Lucian admitting he stored plaintext two years ago)
- 01:45:00 — Cloud Messaging package, getting the FCM token, and a full aside on C# events and lambdas
- 02:05:00 — Android build setup: developer mode, USB debugging, IL2CPP, target API 33, Gradle templates
- 02:20:00 — Build and run to the phone, building the wrong scene, and the much faster second build
- 02:32:00 — Sending a campaign notification from the console, then a test send to a single device token
- 02:50:00 — Realtime Database: test mode, the DLL problem, and creating an asmdef with the right references
- 03:02:00 — Toggles, anchors, prefabbing the auth UI, and the submit script writing a dictionary to the database
What you build
By the end you have a Unity project talking to three Firebase services. A login scene where users register and sign in with email and password, with errors surfaced and successful users appearing in the Firebase console. A notifications scene that pulls the device token, displays it in a copyable input field, and handles messages that arrive while the app is in the foreground — tested for real by sending a campaign from the console to a Pixel over USB. And a data scene where three toggles representing collected items get serialised into a dictionary and written under users/{userId} in the realtime database, visible updating live in the console.
The auth handler is short:
private void HandleLogin()
{
auth.SignInWithEmailAndPasswordAsync(emailInput.text, passwordInput.text)
.ContinueWithOnMainThread(task =>
{
if (task.IsFaulted)
{
Debug.LogError($"Login failed: {task.Exception}");
return;
}
if (task.IsCompleted)
Debug.Log($"Login successful, user is {task.Result.User.Email}");
});
}
And the database write, built from whichever toggles are on:
```csharp
var userData = new Dictionary<string, object>
{
["name"] = "player",
["lastUpdate"] = DateTime.UtcNow.ToString("o"),
["items"] = enabledToggles.ConvertAll(t => t.GetComponentInChildren<TMP_Text>().text)
};
db.GetReference("users").Child(userId)
.UpdateChildrenAsync(userData)
.ContinueWithOnMainThread(OnSaveResult);
Small habit worth stealing from that last one: the submit button gets disabled the moment it's clicked and re-enabled in the callback. It stops double submits and gives the player immediate feedback. Lucian reckons 90% of apps and sites skip it.
## Who should watch this
If you've only ever made single-player games that save to `PlayerPrefs`, this is where the other half of the job appears. It's aimed at people who want a login, a leaderboard or notifications in a real shipped game and don't want to wade through outdated tutorials to get there. Absolute beginners can watch it for the concepts and come back for the setup later — the value is in seeing the whole chain, from a tarball in a folder to a notification landing on a phone.
Part of the full curriculum. Course overview.