How to use Firestore SDK in WebGL built by Unity
2022-10-15
UnityFirestoreC#Firebase offers Cloud Firestore which is a well-known NoSQL document datastore that has been widely used in particularly mobile app development.
One of the key features of Firestore I think is realtime-ish data propagation through Firestore SDK. When a client is subscribing a (sub-)collection and new documents being added to it, the documents are pushed to the client in streaming fashion.
Unity can use Firestore via official SDK including various platforms like Android and iOS, however, WebGL is not supported for the time being.
https://github.com/firebase/firebase-unity-sdk/tree/47295d3610304a13b4491cb9dd2347daaec9aa1f#building
The only way to use Firestore SDK in Unity WebGL is using Firestore JavaScript SDK. This post describes how to do that and some tips in addition to basic usage of Firestore JS SDK from Unity WebGL.
How to use JS in Unity WebGL
Since WebGL is basically a web technology based on HTML and JavaScript, we can write JS code to manipulate WebGL objects as we want. But, it's not an easy way. An alternative way is using JavaScript code in .jslib extension.
https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html
A .jslib file will be available when it's placed in Assets/YourAssembly/Plugins/
directory.
Then, C# files can run JavaScript functions through [DllImport("__Internal")]
annotation.
To subscribe new documents to a collection, write .jslib code like below:
mergeInto(LibraryManager.library, {
OnSnapshotCollection: function (collectionPath, objectName, onUpdate) {
const _objectName = UTF8ToString(objectName);
const _onUpdate = UTF8ToString(onUpdate);
firebase
.firestore()
.collection(UTF8ToString(collectionPath))
.onSnapshot(function (snapshot) {
snapshot.docChanges().forEach((change) => {
if (change.type === "added") {
const data = JSON.stringify(change.doc.data());
unityInstance.Module.SendMessage(_objectName, _onUpdate, data);
}
});
});
},
});
Key points are:
- String arguments should be cast into JavaScript object via
UTF8ToString
UnityInstance
should be globally available in WebGL htmlwindow.unityInstance = ...
is required beforehand
- An
Object
(orGameObject
) namedobjectName
should be available in the active scene
C# implementation to use the function OnSnapshotCollection
defined in the .jslib file looks like the below code snippet.
using UnityEngine;
namespace Firebase
{
public static class Firestore
{
#if UNITY_WEBGL && !UNITY_EDITOR && !UNITY_INCLUDE_TESTS
[DllImport("__Internal")]
public static extern void OnSnapshotCollection(string collectionPath, string objectName, string callbackMethodName);
#else
public static void OnSnapshotCollection(string collectionPath, string objectName, string callbackMethodName)
{
Debug.Log($"OnSnapshotCollection {collectionPath} called.");
}
#endif
}
}
That's it.
A function marked with DllImport
annotation can use .jslib function that has the same name, OnSnapshotCollection
in this example.
The reason why #if
macros needed is that when calling OnSnapshotCollection
in UnityEditor, .jslib can't work since it's actually not in WebGL.
If you can install Firebase Unity SDK in addition to JS SDK, #else
block can use the native SDK instead.
To get updated documents that .jslib function notify through unityInstance.Module.SendMessage
, an Object
that is named objectName
and has a function named callbackMethodName
should exist in the active scene in Unity.
As an example, Receiver#receive
is the Object
to be receiving notifications of updated firestore documents.
namespace YourNamespace
{
public class Receiever : MonoBehavior
{
public void Receive(string data)
{
Debug.Log("[Receive]received: {data}")
}
}
}
If Receiver
object named myReceiver
exists in hierarchy, how to use OnSnapshotCollection
would look like:
Firebase.Firestore.OnSnapshotCollection("/my-collection/my-doc/sub-collection", "myReceiver", "Receive");
Then, the .jslib function starts subscribing given collection that new documents to be added and notify them to myReciever
.