16

EDIT: I should emphasize, I have flavors, for which I don't want to use any of these Google services, and attempting to apply the google-services plugin in such a case, without having an applicable google-services.json, would result in a failed build.

I would like to be able to initialize the Firebase SDK, specifically to use the Remote Config, WITHOUT using the google-services.json.

I see that FirebaseApp has an initialize method, which receives a FirebaseOptions object.

I've built the FirebaseOptions with values provided in the google-services.json, and after a call to FirebaseApp.initialize with these options, I always get

FirebaseInitProvider: FirebaseApp initialization unsuccessful

I know it's the recommended way to use the google-services.json file, but I need to be able to make the app call different Firebase projects, depending on debug/release builds, while keeping the package name the same.

The way I would like to do this is to have a debug/release pairs for all values necessary to initialize Firebase, and then dynamically do the initialization.

        FirebaseOptions options = new FirebaseOptions.Builder()
                .setApplicationId(appId)
                .setApiKey(apiKey)
                .setGcmSenderId(appContext.getString(
                        isDebug ? R.string.firebase_testing_gcm_sender_id :
                                R.string.firebase_production_gcm_sender_id))
                .setDatabaseUrl(appContext.getString(
                        isDebug ? R.string.firebase_testing_database_url :
                                R.string.firebase_production_database_url))
                .setStorageBucket(
                        appContext.getString(
                                isDebug ? R.string.firebase_testing_storage_bucket :
                                        R.string.firebase_production_storage_bucket))
                .build();
        FirebaseApp.initializeApp(appContext, options);

So far it doesn't seem to work.

All help is greatly appreciated!

Matej
  • 1,917
  • 2
  • 11
  • 22
  • 1
    Not an answer to your question, but perhaps helpful: The documentation for the [Google Services Gradle Plugin](https://developers.google.com/android/guides/google-services-plugin#adding_the_json_file) explains that you can have multiple `google-services.json` files for a project to support different build types and flavors. – Bob Snyder Aug 15 '16 at 20:05
  • @qbix, thanks, I've updated my question. I am aware of this, but the issue is that I have some flavors for which I just don't want to use any of these Google services, since I don't need them. If I don't still provide a google-services.json, the build will fail. – Matej Aug 15 '16 at 20:10
  • This worked for me: http://stackoverflow.com/questions/37634767/how-to-connect-to-more-than-one-firebase-database-from-an-android-app/37643374#37643374. What isn't working for you? – Frank van Puffelen Aug 15 '16 at 20:12
  • @FrankvanPuffelen, that's pretty much exactly what I'm doing, and I'm getting the "Initialization unsuccessful" message. – Matej Aug 15 '16 at 20:16
  • @FrankvanPuffelen It could be that, in order to successfully manually initialize the FirebaseApp instance, I have to give it a non-default name, but the problem is that FirebaseRemoteConfig, doesn't have a parametrized getInstance method where I could pass such a non-default FireabaseApp instance, and so when calling FirebaseRemoteConfig.getInstance, the app crashes. – Matej Aug 15 '16 at 20:23
  • @FrankvanPuffelen, nope, tried that, fails to initialize even with a non-default name. Hmmm. – Matej Aug 15 '16 at 20:29
  • So i'm trying to do exactly the same thing, but getting an error: Missing google_app_id. Firebase Analytics disabled. - It seems that it requires a resource value. If i provide a invalid value, it crashes, and if I provide a valid one, it uses that no matter what I write in setApplicationId() - any help? – user230910 Aug 08 '17 at 12:29
  • Sam put together a blog on how to do this: https://medium.com/@samstern_58566/how-to-use-firebase-on-android-without-the-google-services-plugin-93ecc7dc6c4 – Kato Jun 14 '19 at 14:50

4 Answers4

16

Here are couple pointers on how to use multiple firebase apps / databases in the same android project Firebase Blog and New Config Docs

However these talk about using a secondary app in addition to the default app -- which still uses the google-services.json. I did a little bit of research and poking around in their Slack channel. Firebase uses a ContentProvider called FirebaseInitProvider. This uses the google-services.json to initialize the DEFAULT app at start up. It barfs if the json file is not present. I did the following steps:

  • Removed the google-services.json
  • Removed com.google.gms.google-services plugin. This plugin always looks for the json file.
  • FirebaseInitProvider is added via manifest merging. However in the top level manifest you can specify a node=remove tag to remove this from being added in the final manifest.

    <provider android:authorities="${applicationId}.firebaseinitprovider"
        android:name="com.google.firebase.provider.FirebaseInitProvider" 
        android:exported="false"
        tools:node="remove"/>
    

However, even after this, I still see an exception:

java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process myfirebasedemo.net. Make sure to call FirebaseApp.initializeApp(Context) first.
                                                                 at com.google.firebase.FirebaseApp.getInstance(Unknown Source)
                                                                 at com.google.firebase.iid.FirebaseInstanceId.getInstance(Unknown Source)
                                                                 at com.google.firebase.iid.FirebaseInstanceIdService.zza(Unknown Source)
                                                                 at com.google.firebase.iid.FirebaseInstanceIdService.zzm(Unknown Source)
                                                                 at com.google.firebase.iid.zzb$2.run(Unknown Source)
                                                                 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
                                                                 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
                                                                 at java.lang.Thread.run(Thread.java:818)

Looks like FirebaseInstanceIdService still looks for the instance app. If you disable the service, using the same manifest node removal technique then this exception goes away. But I think this Service does important sync-ing / messaging stuff. So not sure if its wise to remove this. Long story short -- I am still looking for the perfect solution for disabling the default app / not using the google-services.json. Any further pointers will be deeply appreciated.

UPDATE:

Looks like this solution works after all -- without disabling the FirebaseInstanceIdService and just removing the FirebaseInitProvider as mentioned above. Just need to make sure that the Firebase.initializeApp called the first thing in Application::onCreate method.

FirebaseApp.initializeApp(context, new FirebaseOptions.Builder().setApiKey("<VAL>").
                    setApplicationId("<VAL>").
                    setDatabaseUrl("<VAL>").
                    setGcmSenderId("<VAL>").
                    setStorageBucket("<VAL>").build());  
nhaarman
  • 90,392
  • 51
  • 233
  • 265
exifguy
  • 580
  • 6
  • 13
  • I've tried this and it's not working for me. What version of Firebase is this? – user1743524 Apr 10 '17 at 03:06
  • 1
    @user1743524 i have tried this with version 10.0.1 and seems to work for me. – exifguy Apr 16 '17 at 16:58
  • 1
    @exifguy I'm getting the `Default FirebaseApp is not initialized` error when the app is killed and I receive a push notification (using the same method as mentioned above). Does this scenario work for you? – dabo248 Dec 14 '19 at 16:53
2

I've found interesting workaround. Try the following: put your google-services.json to any sample app google provides for Firebase integration. Compile it.

Take a look on path app/build/generated/res/google-services/debug/values/ there should be generated values.xml file with bunch of strings mentioned in errors you described. Copy these strings to value.xml file of your project. That's it.

Gennadiy Ryabkin
  • 6,364
  • 3
  • 28
  • 37
2

The google-services.json is totally optional and meant to be convenient. So if you find it inconvenient then definitely don't use it.

As you may have noticed, the json file is only used at build time. The google-services plugin turns the JSON file into a resources xml file containing some specific strings. It looks like this:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <! -- Present in all applications -->
    <string name="google_app_id" translatable="false">1:1035469437089:android:73a4fb8297b2cd4f</string>

    <! -- Present in applications with the appropriate services configured -->
    <string name="gcm_defaultSenderId" translatable="false">1035469437089</string>
    <string name="default_web_client_id" translatable="false">337894902146-e4uksm38sne0bqrj6uvkbo4oiu4hvigl.apps.googleusercontent.com</string>
    <string name="ga_trackingId" translatable="false">UA-65557217-3</string>
    <string name="firebase_database_url" translatable="false">https://example-url.firebaseio.com</string>
    <string name="google_api_key" translatable="false">AIzbSyCILMsOuUKwN3qhtxrPq7FFemDJUAXTyZ8</string>
    <string name="google_crash_reporting_api_key" translatable="false">AIzbSyCILMsOuUKwN3qhtxrPq7FFemDJUAXTyZ8</string>
    <string name="project_id" translatable="false">mydemoapp</string>

</resources>

You can just create these entries in your own strings.xml file and then FirebaseApp.initializeApp() will find them at runtime. Not all of the keys are required, it depends what service you're using. For example almost all services require the google_app_id key. Firestore only needs that and the project_id, while Firebase Auth needs the google_api_key as well. It shouldn't be too hard to experiment and figure out which ones you need.

Some links:

Sam Stern
  • 22,713
  • 12
  • 83
  • 117
1

I'm also using build variants for applying different configurations for different environments. I had the same issue, as some of the variants didn't have an appropriate entry on the google-services.json file. that caused some of my builds to fail when generating an app package that was not configured in firebase.

My workaround for this was to add dummy applications entries for the missing packages on the relevant firebase projects, on the firebase dashboard - then getting the updated google-services.json file from it.

Might not be the best practice, but did the job in my case.

Shlomi
  • 345
  • 5
  • 23