Configure multiple Firebase projects with Unity - firebase

Is it possible to configure multiple Firebase projects for my Unity application without diving into the Android or iOS code? I tried simply switching out the google-services.json file, but this failed to point my Unity app to the correct Firebase app. Ideally I'd like to be able to do something like this:
void Awake()
{
if (environment == Environment.Development)
{
SetDevelopmentEnvironment();
}
FirebaseApp.CheckDependencies();
FirebaseApp.FixDependenciesAsync();
auth = FirebaseAuth.DefaultInstance;
}
public void SetDevelopmentEnvironment()
{
AppOptions firebaseDevelopmentAppOptions = new AppOptions();
firebaseDevelopmentAppOptions.ProjectId = "test";
firebaseDevelopmentAppOptions.StorageBucket = "test.appspot.com";
firebaseDevelopmentAppOptions.AppId = "1:12345:android: xyz";
firebaseDevelopmentAppOptions.ApiKey = "123Key";
firebaseDevelopmentAppOptions.MessageSenderId = "123SenderID";
System.Uri dbURL = new System.Uri("https://test.firebaseio.com");
firebaseDevelopmentAppOptions.DatabaseUrl = dbURL;
FirebaseApp.Create(firebaseDevelopmentAppOptions);
}
Or better yet, simply pass the appropriate google-services.json from the Resources folder.

To add more information on Unity specifically:
The shortest answer is that right now, multiple configurations are not officially supported by the Unity plugin. There are a number of custom processes put into place for backwards compatibility
The way this works on Android is that the script generate_xml_from_google_services_json.py converts your google-services.json file into google-services.xml and places it in a place that gets copied over to the Android build (note that on Windows, this is compiled into generate_xml_from_google_services_json.exe so developers don't have to install python). Ths means that when you swap out this file, you need to make sure the xml gets regenerated (and if you export an Android project before changing your google-services file, then you need to replace the xml rather than the json). This basically duplicates the process of the google services plugin whilst also maintaining backwards compatibility with versions of Unity that predate gradle support. Since it does use the Android resources system, this would be hard to swap out after building a game.
On iOS, GoogleServices-Info.plist is copied over to the final XCode project. It would be rather simple to replace this at any point in your build process, although it wouldn't be easy to swap out after making a build.
Now to do what you first ask in your question, if you can do it at run time in some way. You have to be really careful, Firebase in Unity is a lazily initialized singleton. That is, accessing the property FirebaseApp.DefaultInstance or invoking any function that depends on it will cause a Firebase singleton to be created. You can try manually create a Firebase instance with FirebaseApp.Create(AppInfo), but you'll have to be very structured in your game design to ensure that it gets called before FirebaseApp is implicitly constructed (Create should setup the global default instance, but CheckAndFixDependenciesAsync is an async call that may take more than one frame to complete. This could present a tricky bug surface). You can pass in AppOptions generated from a json file as #Twinsens points out, but having multiple files named google-services.json in your Assets/ directory is not a well defined scenario. You will want to rename your non-default configurations (likely changing the extension to .txt as well so you can retrieve them as a TextAsset).
Something like this:
async void Awake()
{
var dependencyStatus = await FirebaseApp.CheckAndFixDependenciesAsync();
if (dependencyStatus != DependencyStatus.Available) {
// error handling here
return;
}
FirebaseApp app;
if (environment == Environment.Development)
{
// I'm being extra cautious. `DefaultInstance` should have the one you create.
app = SetDevelopmentEnvironment();
}
else {
app = FirebaseApp.DefaultInstance;
}
// I'm being extra explicit just in case
// for large projects, I'd prefer some sort of DI over the singletons anyway
auth = FirebaseAuth.GetAuth(app);
}
public FirebaseApp SetDevelopmentEnvironment()
{
AppOptions firebaseDevelopmentAppOptions = new AppOptions();
firebaseDevelopmentAppOptions.ProjectId = "test";
firebaseDevelopmentAppOptions.StorageBucket = "test.appspot.com";
firebaseDevelopmentAppOptions.AppId = "1:12345:android: xyz";
firebaseDevelopmentAppOptions.ApiKey = "123Key";
firebaseDevelopmentAppOptions.MessageSenderId = "123SenderID";
System.Uri dbURL = new System.Uri("https://test.firebaseio.com");
firebaseDevelopmentAppOptions.DatabaseUrl = dbURL;
return FirebaseApp.Create(firebaseDevelopmentAppOptions);
}

You can try this;
AppOptions.LoadFromJsonConfig(string json);
for more information please visit,
https://firebase.google.com/docs/reference/unity/class/firebase/app-options#loadfromjsonconfig

You need to setup some configurations on each platform (android and ios) to load the different firebase config files (google-services.json)
Android:
Basically, you can configure different product flavours to separate between the different config files
Add the flavours to the build.gradle. You could add more environment specific field here as you like:
Resources
https://developer.android.com/studio/build/build-variants
iOS:
its pretty similar on iOS, but you setup different targets in xcode instead of product flavours
you add each firebase config file to its own folder
and include them in the xcode project
assign each file to the correct target
Resources:
https://www.appcoda.com/using-xcode-targets/

Related

Google Login without google-services.json file

I have been looking for a method in order to add the google-services.json at runtime as we use same base code to configure the application for the different client, hence we want to add google-services.json at runtime.
I have tried several links but am unable to find such a way to do it.
Any help will be very much appreciated.
The google-services.json is actually never read at runtime. During the build process of your Android app, the relevant information from google-services.json is translated into your App's XML resources, and that is where it's read when the app starts. Since the destination where the build plugin puts the values is hard-wired, you can't configure it to have multiple sets of configuration data.
Instead of trying to read google-services.json at runtime, I'd recommend configuring the FirebaseApp instance in your code explicitly, like this:
// Manually configure Firebase Options
FirebaseOptions options = new FirebaseOptions.Builder()
.setApplicationId("1:27992087142:android:ce3b6448250083d1") // Required for Analytics.
.setApiKey("AIzaSyADUe90ULnQDuGShD9W23RDP0xmeDc6Mvw") // Required for Auth.
.setDatabaseUrl("https://myproject.firebaseio.com") // Required for RTDB.
.build();
Now you can determine yourself where to keep the relevant information from the google-services.json and which ones to use when the app starts.
and then:
// Initialize with secondary app.
FirebaseApp.initializeApp(this /* Context */, options, "secondary");
// Retrieve secondary app.
FirebaseApp secondary = FirebaseApp.getInstance("secondary");
// Get the database for the other app.
FirebaseDatabase secondaryDatabase = FirebaseDatabase.getInstance(secondary);
Also see:
The documentation section on using multiple build flavors (where I now copied the code snippets from)
My previous answer on a related topic (where I think the code snippets in the docs originated 😀)

How to generate DownloadUrl from Google-Cloud storage (I came from firebase)

Just trying to figure out something that seemed trivial in firebase, in google-cloud.
It seems as though if you're making a node.js app for HTML (i'm talking to it through Unity actually, but it's a desktop application) you can't use firebase-storage for some odd reason, you have to use google-cloud, even the firebase-admin tools use the cloud storage to do storage from here.
Nevertheless, i got it working, i am uploading the files to the firebase storage; however, the problem is in firebase, you could specify a specific file, and then do storage().ref().child(filelocation).GetDownloadURL(): this would generate a unique url for some set time that can be used publicly, without having to give out access to read to all anonymous users.
I did some research and i need to implement something called GS UTIL in order to generate my own special urls, but it's so damn complicated (im a newbie to this whole server stuff), i don't even know where to start to get this working in my node server.
Any pointers? I'm really stuck here.
-------if anyones interested, this is what im trying to do high level-----
I'm sending 3d model data to node app from Unity
the node app is publishing this model on sketchfab
then it puts the model data onto my own storage, along with some additional data specially made for my app
after it gets signed to storage, it gets saved to my Firebase DB in my global model database
to be accessed later, by users, to try to get the downloadURL of this storage file and send them all back to Unity users(s)
I would just download the files into my node app, but i wanna reduce any server load, it's supposed to be just a middleman between Unity and Firebase
(i would've done it straight from Unity, but apparently firebase isn't for desktop windows apps).
Figured it out:
var firebase_admin = require("firebase-admin");
var storage = firebase_admin.storage();
var bucket = storage.bucket();
bucket.file(childSnapshot.val().modelLink).getSignedUrl({
action: 'read',
expires: expDate
},function(err,url){
if(err){
reject(err);
}
else{
finalData.ModelDownloadLink = url;
console.log("Download model DL url: " + url);
resolve();
}
});

Can Firebase RemoteConfig be accessed from cloud functions

I'm using Firebase as a simple game-server and have some settings that are relevant for both client and backend and would like to keep them in RemoteConfig for consistency, but not sure if I can access it from my cloud functions in a simple way (I don't consider going through the REST interface a "simple" way)
As far as I can tell there is no mention of it in the docs, so I guess it's not possible, but does anyone know for sure?
firebaser here
There is a public REST API that allows you to read and set Firebase Remote Config conditions. This API requires that you have full administrative access to the Firebase project, so must only be used on a trusted environment (such as your development machine, a server you control or Cloud Functions).
There is no public API to get Firebase Remote Config settings from a client environment at the moment. Sorry I don't have better news.
This is probably only included in newer versions of firebase (8th or 9th and above if I'm not mistaken).
// We first need to import remoteConfig function.
import { remoteConfig } from firebase-admin
// Then in your cloud function we use it to fetch our remote config values.
const remoteConfigTemplate = await remoteConfig().getTemplate().catch(e => {
// Your error handling if fetching fails...
}
// Next it is just matter of extracting the values, which is kinda convoluted,
// let's say you want to extract `game_version` field from remote config:
const gameVersion = remoteConfigTemplate.parameters.game_version.defaultValue.value
So parameters are always followed by the name of the field that you defined in Firebase console's remote config, in this example game_version.
It's a mouthful (or typeful) but that's how you get it.
Also note that if value is stored as JSON string, you will need to parse it before usage, commonly: JSON.parse(gameVersion).
Similar process is outlined in Firebase docs.

How can I get current projectId inside Google Cloud Functions?

The question is simple. I need projectId in order to establish connection insde Google Cloud Function. I found the documentation where it said, that projectId is optional parameter and will be checked from GCLOUD_PROJECT, but on deployed function it didn't work.
So it is the question now how can I get the projectId env variable in order to pass it as argument for Datastore connection instance, or what should be done to not pass this id and establish connection with datastore inside Google Cloud Function?
Update 1
I found that I actually can get variable from process.env.GCLOUD_PROJECT, just like any other env.variable.
But, know is the last question, is it actually possible to use #google-cloud/datastore without any configuration object?
You can get project ID as const projectId = process.env.GCP_PROJECT.
But for some reason the environmet variable "GCP_PROJECT" is not set when running the emulator. Instead the deprecated variable name "GCLOUD_PROJECT" is the one to select. So you might try them both.
const projectId = process.env.GCP_PROJECT || process.env.GCLOUD_PROJECT
The answer depends on which runtime you are using.
If your using Python 3.7 and Go 1.11 you are in luck. Use
process.env.GCP_PROJECT
If using any of the new runtimes, bad luck, either access the metadata server, or google suggests
Note: If your function/app requires one of the environment variables from
an older runtime, you can set the variable when deploying your
function. For example:
gcloud functions deploy envVarMemory \
--runtime nodejs10 \
--set-env-vars FUNCTION_MEMORY_MB=2Gi \
--memory 2Gi \
--trigger-http
If using terraform:
resource "google_cloudfunctions_function" "my-function" {
name = "my-function"
runtime = "nodejs16"
environment_variables = {
GCP_PROJECT = var.project_id
}
#...
}
Under Cloud Functions v2 public preview (Oct 2022), there's a section called built-in parameters that allows require of Project ID, Database URL and Storage bucket.
Presumably also Location ID ("Default GCP resource location") would be listed here, though that's not in the current documentation.
I did not get that to work.
However, this does:
const firebaseConfig = JSON.parse( process.env.FIREBASE_CONFIG );
const locationId_maybe = firebaseConfig.locationId || null;
const projectId = firebaseConfig.projectId;
const databaseURL = firebaseConfig.databaseURL;
The env.var. is always defined. locationId is defined only if there's an active Firebase project. This makes sense, since it needs access to the GCP project in the cloud.
Firebase CLI 11.15.0
As I wrote in update 1 we can get all the information about environment from the process.env variable.
And the second question about configuration object for #google-cloud/datastore, it actually can work without any options. It will trying to fetch all required parameters from environment variables. So, it didn't work beacuase of error in my code.
if it's an HTTP function, we can use the URL to figure out the current project and region with req.header('host')
For any runtimes after node 8 you can use https://www.npmjs.com/package/gcp-metadata
const gcpMetadata = require('gcp-metadata');
export const getGCPProjectIdFromMetadata = async () => {
const isAvailable = await gcpMetadata.isAvailable();
if (!isAvailable) {
return undefined;
}
return gcpMetadata.project('project-id');
};
This will also work across any other instances you wish to launch (such as app engine).
When having deployed with firebase deploy there's:
functions.config().firebase.projectId
functions.config().firebase.databaseURL
functions.config().firebase.storageBucket
functions.config().firebase.locationId

How to upload files from JAVA server to Firebase Storage by any means necessary [duplicate]

How can I integrate Firebase with a Java desktop application?
Is there a .jar file I could download?
I've seen plain Java docs on the old Firebase version but I'm unable to find any documentation on the latest version of Firebase.
My IDE is Netbeans.
Thanks.
According to the documentation website Firebase will not work just like that, it's an application designed to run only on 3 platforms, namely:
Android
iOS
Web
You can try and use the maven repository for the integration purpose, with any build script. I'm not exactly sure what you expect to do.
For Firebase Storage on the server, I recommend using gcloud-java:
// Authenticate using a service account
Storage storage = StorageOptions.builder()
.authCredentials(AuthCredentials.createForJson(new FileInputStream("/path/to/my/key.json"))
.build()
.service();
// Create blob
BlobId blobId = BlobId.of("bucket", "blob_name");
// Add metadata to the blob
BlobInfo blobInfo = BlobInfo.builder(blobId).contentType("text/plain").build();
// Upload blob to GCS (same as Firebase Storage)
Blob blob = storage.create(blobInfo, "Hello, Cloud Storage!".getBytes(UTF_8));
You can use firebase-server-sdk-3.0.1.jar (current version)
In Netbeans I would recommend to create Maven project and use artifact: GroupId - com.google.firebase, ArtifactId: firebase-server-sdk.
I works perfectly for me.
You can find some documentation here.
To initialize SDK just follow documentation: add service account (I use Owner role, I haven't tried weaker roles), download private key, and use this snippet:
FirebaseOptions options = new FirebaseOptions.Builder()
.setServiceAccount(new FileInputStream("path/to/downloaded private key.json"))
.setDatabaseUrl("https://your database name.firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);

Resources