My goal is to build a WebGL game in Unity that has a specific form and upon submission that form posts data into one of the Firebase storage solutions. After reading this article, it's clear to me I need to use Cloud Firestore instead of Realtime Database. Good news is that as of of March 2020, one of the team members wrote,
we released Firebase Unity SDK 6.12.0 which includes an alpha release
of Firestore.
Thing is, Firebase's Unity SDK isn't for WebGL builds and, for someone going through that thought process, could use Firebase JS SDK (spam alert). From looking at the release notes, one can see that Firebase JS SDK supports Firestore and so this has all the conditions in place for a quick solution.
So, I've gone to Firebase console, created a project, a Web app to use Firebase JS SDK and this process gave as output the following code
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.17.1/firebase-app.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/7.17.1/firebase-analytics.js"></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
</script>
with a message saying
Copy and paste these scripts into the bottom of your tag, but
before you use any Firebase services
In addition to that, this is how to Call JavaScript functions from Unity scripts and this is a Cloud Firestore JS Sample App.
Given this information, how can then the form be created?
Let's say you want a form that receives as input
String
Number
Text from the user
In your Firestore console, create a collection and give it a name (like formDataTree), give an autoID and add the fields
strVal
intVal
webVal
Then, I would put those scripts at the bottom of the head tag in your WebGL template. So, create a folder in Assets named WebGLTemplates, and a folder named New Template (or whatever name you will) and add an index.html there.
According to the documentation, this index.html should be similar to
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Unity WebGL Player | %UNITY_WEB_NAME%</title>
<script src="%UNITY_WEBGL_LOADER_URL%"></script>
<script>
var unityInstance = UnityLoader.instantiate("unityContainer", "%UNITY_WEBGL_BUILD_URL%");
</script>
</head>
<body>
<div id="unityContainer" style="width: %UNITY_WIDTH%px; height: %UNITY_HEIGHT%px; margin: auto"></div>
</body>
</html>
So, with this new information, it'll be something like this
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Unity WebGL Player | %UNITY_WEB_NAME%</title>
<script src="%UNITY_WEBGL_LOADER_URL%"></script>
<script>
var unityInstance = UnityLoader.instantiate("unityContainer", "%UNITY_WEBGL_BUILD_URL%");
</script>
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.17.1/firebase-app.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/7.17.1/firebase-analytics.js"></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
</script>
</head>
<body>
<div id="unityContainer" style="width: %UNITY_WIDTH%px; height: %UNITY_HEIGHT%px; margin: auto"></div>
</body>
</html>
Then, under Player settings, select that template.
Then in the body of the template, have a form with its visibility to hidden. Include things from the game as well as any inputs you want filled out in the browser:
<form id="webForm" style="visibility:hidden;">
<input type="hidden" id="stringInput" name="stringInput">
<input type="hidden" id="intInput" name="intInput">
<label for="webInput">web input</label><input type="text" id="webInput" name="webInput">
<button type="submit">Submit</button>
</form>
Then below the Firebase script and the form, include a submit listener for the form on the page which will submit it to Firestore (based on this answer):
myForm.addEventListener('submit', function(evt) {
evt.preventDefault(); //Prevent the default form submit action
var strVal = myForm.stringInput.value;
var intVal = myForm.intInput.value;
var webVal = intInput.webInput.value;
var formData = {
"strVal" : strVal,
"intVal" : intVal,
"webVal" : webVal
};
firebase.database().ref('/formDataTree').push( formData ); // Adds the new form data to the list under formDataTree node
});
All in all, the index.html should be something like this
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Change Mapping | %UNITY_WEB_NAME%</title>
<script src="%UNITY_WEBGL_LOADER_URL%"></script>
<script>
var unityInstance = UnityLoader.instantiate("unityContainer", "%UNITY_WEBGL_BUILD_URL%");
</script>
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.17.1/firebase-app.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/7.17.1/firebase-analytics.js"></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
</script>
</head>
<body>
<div style="height:20px; width: %UNITY_WIDTH%px; background: green;" onclick="unityInstance.SetFullscreen(1)"><b>Click here to make it full screen.</b></div>
<div id="unityContainer" style="width: %UNITY_WIDTH%px; height: %UNITY_HEIGHT%px; margin: auto"></div>
<form id="webForm" style="visibility:hidden;">
<input type="hidden" id="stringInput" name="stringInput">
<input type="hidden" id="intInput" name="intInput">
<label for="webInput">web input</label><input type="text" id="webInput" name="webInput">
<button type="submit">Submit</button>
</form>
<script>
var myForm = document.getElementById("webForm");
myForm.addEventListener('submit', function(evt) {
evt.preventDefault(); //Prevent the default form submit action
var strVal = myForm.stringInput.value;
var intVal = myForm.intInput.value;
var webVal = intInput.webInput.value;
var formData = {
"strVal" : strVal,
"intVal" : intVal,
"webVal" : webVal
};
firebase.database().ref('/formDataTree').push( formData ); // Adds the new form data to the list under formDataTree node
});
</script>
</body>
</html>
Using the apiKey, authDomain, etc in the template it means that it will show up when inspecting the page or viewing page source as. Yet, as mentioned here, it's ok to share that information.
Then, in your Assets folder, create a Plugins folder and add to it a .jslib file, for instances named form.jslib, that has a function that shows the form, and puts game data into the form's hidden inputs.
mergeInto(LibraryManager.library, {
ShowWebForm: function (importantString, importantInt) {
var myForm = document.getElementById("webForm");
myForm.stringInput.value = Pointer_stringify(importantString);
myForm.intInput.value = importantInt;
myForm.style.visibility="visible"
},
});
After the steps up to this point, if you get in the console net::ERR_BLOCKED_BY_CLIENT, simply deactivate AdBlocker for that site as that's why you get that error.
Finally, in Unity, declare that function and call it when appropriate. So, considering you have a newly created scene (so it only has Main Camera and Directional Light), you could call that method in some code that gets called in the new scene. It's a static method so as long as you can find the data you need for the parameters you can call it from anywhere.
[DllImport("__Internal")]
private static extern void ShowWebForm(string importantString, int importantInt);
public void Start()
{
// Suppose we want to send the version of unity the app is running on
// and the unix timestamp at start
string unityVersion = Application.unityVersion;
System.DateTime epochStart = new System.DateTime(1970, 1, 1, 0, 0, 0,
System.DateTimeKind.Utc);
int cur_time = (int)(System.DateTime.UtcNow - epochStart).TotalSeconds;
ShowWebForm(unityVersion, cur_time);
}
Alternatively, if you don't want to have the user fill things out in the browser, you can leave the form invisible and instead of setting it to visible, dispatch a submit event:
mergeInto(LibraryManager.library, {
ShowWebForm: function (importantString, importantInt) {
var myForm = document.getElementById("webForm");
myForm.stringInput.value = Pointer_stringify(importantString);
myForm.intInput.value = importantInt;
myForm.webInput.value = "some other value from the game could go here";
myForm.dispatchEvent(new Event('submit'));
},
});
Can't test at the moment, so be aware of typos or other syntax errors.
I am using a moisture sensor for my first IoT project. I am saving the data from the sensor in a real-time Firebase database. For my webpage I am using glitch.com, and I am trying to display the data from the db on my webpage. I tried coding this myself, but got pretty much nowhere. So I decided to remix an existing glitch.com "Firebase Read" project. However I am encountering a problem, it's saying: 'firebase' not defined in the following 3 lines (In the first line listed below, it's also saying config is not defined):
firebase.initializeApp(config);
var rootRef = firebase.database().ref();
var myDBConn = firebase.database().ref("Moisture");
I currently have the following in my js file:
<script src="https://www.gstatic.com/firebasejs/7.11.0/firebase.js"></script>
// Initialize Firebase
// TODO: Replace with your project's customized code snippet
// Initialize Firebase
var firebaseConfig = {
apiKey: "xx",
authDomain: "xx",
databaseURL: "xx",
projectId: "xx",
storageBucket: "xx",
messagingSenderId: "xx",
appId: "xx"
};
firebase.initializeApp(config);
var rootRef = firebase.database().ref();
// List to hold my moisture value
var myMoisture = [];
// Define database connection to correct branch, Moisture
var myDBConn = firebase.database().ref("Moisture");
// Function that acts when a 'new child is added to the DB' - i.e. new data is added this function runs.
myDBConn.on("child_added", function(data, prevChildKey){
// The data returned from the branch is put into a variable, dataPoint
var dataPoint = data.val();
// Convert the 'Temp' field from dataPoint into integers, then put them into the myTemps list
myMoisture.push(parseInt(dataPoint.Temp));
// Add all the Temps and get the total
var totalT = 0;
var i=0;
for (i=0; i<myMoisture.length; i++){
totalT += myMoisture[i];
}
// Create an average by dividing the sum of temps by the number of temps
var average = totalT / myMoisture.length;
// Update the page elements with the average and the last item (most recent) off the list
document.getElementById("averageT").innerHTML=average;
document.getElementById("LiveT").innerHTML=myMoisture[myMoisture.length - 1];
});
This in my HTML file:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello!</title>
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.11.0/firebase.js"></script>
<script src="script.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>Reading from Firebase Cloud Database</h1>
Live Moisture Reading: <a id="LiveT">---</a> <br>
Average Temperature: <a id="averageT">---</a>
</body>
</html>
And this is shown by the debugger (I don't know if this information is relevant and what it means, but maybe it's useful):
Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (net.js:1270:14)
at listenInCluster (net.js:1318:12)
at Server.listen (net.js:1405:7)
at Lws.listen (/opt/nvm/versions/node/v10.15.3/pnpm-global/1/node_modules/.registry.npmjs.org/lws/1.3.2/node_modules/lws/index.js:81:12)
at WsServe.execute (/opt/nvm/versions/node/v10.15.3/pnpm-global/1/node_modules/.registry.npmjs.org/lws/1.3.2/node_modules/lws/lib/command/serve.js:296:26)
at WsServe.execute (/opt/nvm/versions/node/v10.15.3/pnpm-global/1/node_modules/.registry.npmjs.org/local-web-server/2.6.0/node_modules/local-web-server/lib/command/serve.js:11:18)
at Map.start (/opt/nvm/versions/node/v10.15.3/pnpm-global/1/node_modules/.registry.npmjs.org/cli-commands/0.4.0/node_modules/cli-commands/index.js:26:18)
at WsCliApp.start (/opt/nvm/versions/node/v10.15.3/pnpm-global/1/node_modules/.registry.npmjs.org/lws/1.3.2/node_modules/lws/lib/cli-app.js:9:26)
at Function.run (/opt/nvm/versions/node/v10.15.3/pnpm-global/1/node_modules/.registry.npmjs.org/lws/1.3.2/node_modules/lws/lib/cli-app.js:15:29)
at Object.<anonymous> (/opt/nvm/versions/node/v10.15.3/pnpm-global/1/node_modules/.registry.npmjs.org/local-web-server/2.6.0/node_modules/local-web-server/bin/cli.js:5:29)
What things could I try next?
Quick scan of the FireBase docs
I see that your FireBase import is slightly wrong:
Try changing it to:
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.11.0/firebase-app.js"></script>
The docs are here: https://firebase.google.com/docs/web/setup
I am having an issue when using Authenticattion with Firebase (using Password-Based Accounts) in Javascript.
I followed this document:
https://firebase.google.com/docs/auth/web/password-auth
and things are working as I expect.
Here is my configuration and where I hit a problem.
I have a main web page (called M.html) which requires a login to be accessed.
I have a login page (called L.html) which is a gate to access the main page.
When a user goes to the login page, he needs to enter credentials to go further.
If he logs in he should access the main page.
If a user attempts to go directly to the main page, a check is performed to see his login status.
If he is logged in all should be fine, if he is not he should be forced back to the login page.
But what happen is that the main page never detects that the user is logged in and he is always brought back to the login page.
I need to know the procedure to follow to make the main page aware that a login has been accepted in the login page.
I have tried various options in my code but it did not work.
I also read that I may have to use firebase.auth().getRedirectResult().then....
but did not find any way to make it work as it should.
To make things clear, I made simplified versions of the main an login pages.
Below is the code for both. I hope that someone can easily see where I should change the code to get the behavior I wish to have.
The M.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://cdn.firebase.com/js/client/2.4.2/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.5.7/firebase.js"></script>
</head>
<body>
<div id="mainPage"></div>
<script>
// Initialize Firebase.
var config = {
apiKey: "myyKeyyy",
authDomain: "......firebaseapp.com",
databaseURL: "https://......firebaseio.com",
projectId: "....",
storageBucket: "........appspot.com",
messagingSenderId: "........."
},
app = firebase.initializeApp(config);
</script>
<script>
function checkUser() {
let user = firebase.auth().currentUser;
if (user) {setMainPage();}
else {window.open("http://.../L.html",'_self');}
}
function setMainPage() {
let label = document.getElementById("mainPage");
label.innerHTML = "<h1>This is the main page!</h1><br/>";
label.innerHTML += "<h1>I can be here because I am logged in !!</h1>";
}
//setMainPage(); // This would show the contents without checking that a user is logged in.
checkUser();
</script>
</body>
</html>
The L.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://cdn.firebase.com/js/client/2.4.2/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.5.7/firebase.js"></script>
</head>
<body>
<script>
// Initialize Firebase.
var config = {
apiKey: "myyKeyyy",
authDomain: "......firebaseapp.com",
databaseURL: "https://......firebaseio.com",
projectId: "....",
storageBucket: "........appspot.com",
messagingSenderId: "........."
},
app = firebase.initializeApp(config);
</script>
<script>
firebase.auth().signOut().then(function() {
// Sign-out successful.
console.log("Sign-out successful.");
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
window.open("http://.../M.html",'_self');
}
});
}).catch(function(error) {
// An error happened.
console.log("Sign-out error.");
});
function LogInProcess() {
let theEmail = document.getElementById("EmlAdr").value.trim(),
thePassword = document.getElementById("PsWd").value;
firebase.auth().signInWithEmailAndPassword(theEmail,thePassword).catch(function (error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log("errorCode: " + errorCode);
console.log("errorMessage: " + errorMessage);
// ...
});
}
</script>
Email address: <input type='text' name='EmlAdr' id='EmlAdr' value=''><br/><br/>
Password: <input type='password' name='PsWd' id='PsWd' value=''><br/><br/>
<input type='button' id='LgIn' style='font-size:20px' value='Log In' onClick='LogInProcess()'><br/>
</body>
</html>
You want to use an onAuthStateChanged observer to check if the user is logged in. Otherwise you will often get the auth object in an incomplete state. Check the latest documentation here.
Replace your checkUser function with this:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// show your main content
} else {
// redirect to login
}
})
Once the firebase app has initialized fully, this will trigger and you should have a user if one has successfully logged in.
I've already created a simple web page which saves and displays data in firebase database. I tried different times to make the offline cache data to be synced with the fire base data. But it doesn't work. I've attached .html and .js files. Could anybody help me, how the local storage cache be synced with fire base data once the connection established after the disconnect of the app?
var output = document.getElementById("data");
var dataText = document.getElementById("data-text");
var firebaseReference = firebase.database().ref('users/');
(function() {
firebaseReference.on("value", function(snapshot) {
output.innerHTML = JSON.stringify(snapshot.val(), null, 2);
});
})();
$(document).ready(function(){
$("form").submit(function(){
firebaseReference.push().set({Name: dataText.value});
});
});
var connectedRef = firebase.database().ref(".info/connected");
connectedRef.on("value", function(snap) {
if (snap.val() === true) {
alert("connected");
} else {
alert("not connected");
}
});
<html>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://www.gstatic.com/firebasejs/4.6.0/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.6.0/firebase-firestore.js"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<title>Firebase</title>
</head>
<body>
<h1>Firebase Example</h1>
<h2>Add New</h2>
<form action="" class="form-group">
<input type="text" required id="data-text">
<input type="submit" id="data-submit" class="btn btn-primary">
</form>
<h2>Existing Data</h2>
<pre id='data'></pre>
<script>
var config = {
apiKey: "AIzaSyBGKWHQlLok3q70Y6Q5CAzWyLbN4GyKnAQ",
authDomain: "my-firebase-project-536a4.firebaseapp.com",
databaseURL: "https://my-firebase-project-536a4.firebaseio.com",
projectId: "my-firebase-project-536a4",
storageBucket: "my-firebase-project-536a4.appspot.com",
messagingSenderId: "711083146609"
};
firebase.initializeApp(config);
</script>
<script src="script.js"></script>
</body>
</html>
Your code is using the Firebase Realtime Database, which doesn't support disk persistence in its web client at the moment. While the feature has been worked on in the open-source repo, it hasn't been released yet.
If you want offline caching support for a web application, I recommend using Cloud Firestore for Firebase where such support is built in.
I'm just getting started with firebase and javascript html to make a website for my app.
all I'm trying to do is access any value from firebase and print it on the website.
I followed firebase's quickstart tutorial and copied the exact same code they have: https://www.youtube.com/watch?v=k1D0_wFlXgo
here is the code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Javascript</title>
</head>
<body>
<h1 id="bigOne"></h1>
<script src="https://www.gstatic.com/firebasejs/3.3.2/firebase.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyD0C9hhfpdKEIahisG0VNInZZGjCyf5Lo0",
authDomain: "game-of-chats-ce897.firebaseapp.com",
databaseURL: "https://game-of-chats-ce897.firebaseio.com",
storageBucket: "game-of-chats-ce897.appspot.com",
};
firebase.initializeApp(config);
var bigOne = document.getElementById('bigOne');
var dbRef = firebase.database().ref().child('text');
dbRef.on('value', snap => bigOne.innerText) = snap.val())
</script>
</body>
</html>
am I missing something? I am new so there might be one small step that I'm missing.
Try with:
dbRef.on('value', function(snapshot) {
bigOne.innerText = snapshot.val();
});