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 😀)
Related
This question was previously closed, telling me to "update the question so it focuses on one problem only;" I don't know what the problem is, and if I did, I wouldn't be posting this question. Regardless, I'll make some clarifications here:
I was previously using just the normal Firebase module (the one imported using "npm i firebase"); everything worked perfectly before. The issue has to do with the authentication (as far as I am aware) with the Firebase Admin SDK. I don't understand how I'm supposed to send this to the Heroku build without revealing the service account key JSON file on my GitHub.
As for the GOOGLE_APPLICATION_CREDENTIALS path, is there a way where I don't have to set it every session? The Heroku app restarts once a day, and I would need to somehow automate this entry process (or skip it entirely). That's the way I currently understand it. Here's a quote from a previous answer:
When I set the GOOGLE_APPLICATION_CREDENTIALS path, doesn't this only set it on my local machine?
Environment variables only work on the individual machine and process where they have been set. If you want it set on another machine and process, you will have to arrange for that separately. According to the documentation:
Set the environment variable GOOGLE_APPLICATION_CREDENTIALS to the file path of the JSON file that contains your service account key. This variable only applies to your current shell session, so if you open a new session, set the variable again.
My main question here is as follows: "I implemented the Firebase Admin SDK incorrectly. How do I do it the right way?"
Even just posting a link to guides that would help would be appreciated (although I understand this is typically discouraged as links sometimes break).
Original:
Note: this is my first time using the Firebase Admin SDK, so I'm really not sure what I'm doing (although I have used Firebase quite a bit).
Recently, I decided I would go back to one of my older Discord bots and actually authenticate its requests to Firebase properly (I hadn't done this previously as I've never authenticated from a server before and didn't think it was possible). I discovered the Firebase Admin SDK, which sounded perfect for my needs (the bot is being hosted on Heroku, for the record).
I found this guide: https://firebase.google.com/docs/admin/setup, but there's a few things I can't wrap my head around (note that these are purely rhetorical, you don't need to answer them in your answer; I'm just providing them so you can understand my thought process):
When I set the GOOGLE_APPLICATION_CREDENTIALS path, doesn't this only set it on my local machine? I could also try running the export command on the server (using "heroku run" in the CLI), but then the path would be pointing to a file that doesn't exist on the server (since the service account key JSON file is on my local machine). Do I need to set an environment variable in Heroku or something?
How does "admin.credential.applicationDefault()" know how to get the credentials?
I can't find any other guides that make sense.
The way I currently have it setup must be wrong, since reads and writes fail silently.
Firebase setup code:
// Setup Firebase:
const admin = require('firebase-admin');
// Initialize Firebase:
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: "https://<APP>.firebaseio.com" // I removed the actual <APP> name to ask this question
});
let database = admin.database();
Things like database.ref("test").set("Hello World!"); don't change the data in the database, and no errors are thrown (I've also tried attaching a .then and a .catch to the end of this; still nothing). This was working before I switched over to the Firebase Admin SDK (I was just using the "firebase" module previously, rather than the "firebase-admin" module that I'm now using). The same goes for reading data.
Any help would be appreciated.
Here was my problem:
I was sending res.status(200) outside of the async firebase call, killing the request before firebase had a chance to finish. Somehow localhost allows this to work properly but when its hosted things go sideways.
so I had this
fireabse.database().ref('parent/foo').set('bar');
res.status(200)
I needed this:
firebase.database().ref('parent/foo').set('bar').then(() => {
res.status(200);
});
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/
I am using the latest version of FirebaseSDK (currently 4.2.1) in my Unity game. I have everything setup as mentioned in the docs. Realtime database and authentication are working fine but I am getting the following error when running in Editor:
InvalidOperationException: FirebaseApp was not initialized with a bucket name.
when I does the following:
StorageReference storageRef = FirebaseStorage.DefaultInstance.RootReference;
But if I make the reference using bucket name its fine, for example:
StorageReference storageRef = FirebaseStorage.DefaultInstance.GetReferenceFromUrl("gs://bucketname");
does not produce an error.
Anybody having any idea what's wrong?
When calling App.Create, you can pass in options via the app options struct. I believe this gets filled automatically, if you are running on device (and it can access the google-services plist/xml) but in the editor, you need to specify it. If you call FirebaseStorage.DefaultInstance.RootReference without doing so, then it won't actually know what the root reference for your project is. (Getting references directly from gs:// links works, since those are absolute.)
Try setting the bucket via AppOptions when you call App.Create().
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.
I am building a very simple cron job backup system for a friend's firebase app;
I have PHP code, using firebase-php that can communicate with the firebase and the API docs state that adding the'?format=export" parameter will retrieve a .json file. Cool, so far.
My question is this: What path (after the firebase URL) is required?
The API doc appears to state that it should be /.json but it returns a 404 /json/ works on the simulator, but also returns a 404 in testing
(note: looking for a single text file, similar to the "Export json" data dashboard, if possible)
Thanks in advance.
The path defined the portion of the Firebase data tree that is being loaded. That means that you can load /any/possible/string and it will return a value, though that value is likely to be null unless you've written data to that path. Also note that without a defined extension (i.e. .json) you'll be attempting to load Firebase's in-browser graphical debugger.
In short, if you're using the REST API, you'll always want to end your paths in .json, but nothing else is required, i.e. https://<your-firebase>.firebaseio.com/.json is perfectly valid, and would download your entire Firebase. The format=export parameter ensures that any Firebase priority values are preserved in your JSON output, under the key .priority at any node, where they would normally be excluded.