Implement Firebase inside of a Library

I know this is an old question with an accepted answer but all the answers have a big disadvantage - they require the user of your library to do work besides adding your library to their application. There is a way to do it without troubling the user of your library at all if your library is being downloaded from a Maven repository.

Note: this method is a hack and is not supported by Firebase. When asked Firebase Support, I got the following reply:

Firebase SDKs are not intended for library projects. The features available on Firebase were integrated in an application level and not on a per module or per library basis so, the use case for having this integrated on a library project is not possible or not supported.

Nevertheless, I've found a way to do it and maybe someone will find it useful so here it is:

This is an example of using Realtime Database but it should work for all the Firebase SDKs.

In your project's main build.gradle add mavenCentral repository:

allprojects {
    repositories {
        ...
        mavenCentral()
    }
}

In your library project's build.gradle, add Google Play Services (as a dependency, not as a plugin):

compile 'com.google.android.gms:play-services-gcm:11.0.4'

Add the relevant Firebase SDKs (with the same version as Google Play Services):

compile 'com.google.firebase:firebase-core:11.0.4'
compile 'com.google.firebase:firebase-database:11.0.4'

Register your SDK as a project on Firebase, download it's google-services.json and open it with any text editor.

In your library's strings.xml add the following lines and fill these lines with data from google-services.json

<string name="gcm_defaultSenderId">project_number</string>
<string name="google_api_key">current_key</string>
<string name="google_app_id">mobilesdk_app_id</string>
<string name="google_crash_reporting_api_key">current_key</string>
<string name="google_storage_bucket">storage_bucket</string>
<string name="firebase_database_url">firebase_url</string>
<string name="default_web_client_id">client_id</string>
<string name="project_id">project_id</string>

This is it. You can use Firebase Realtime Database in your libaray, then build it and publish it to Maven (publishing to Maven is essential, otherwise the user of your library will have to add the dependencies manually). When activated from inside an application, your database will be used.

Note that this method may cause exceptions and unexpected behavior if the user of your library will use Google Play Services or Firebase so use at your own risk!


These are all kinda hacky or too much work, here’s a nice n simple example (ironic though, cause it’s a long post -- but worth it).

It is possible to use FireBase code in your library project, of course the consuming application will need to register the app and get the app ID / google-services.json file.

But your library doesn’t, and shouldn’t care about about that, it’s the consuming applications job to do that, not your library.

Here’s a brief example using the firebase-messaging module inside of a library project.

YourLibrary module’s build.gradle:

// Other typical library set up 
apply plugin: 'com.android.library'

android {
    compileSdkVersion 27

    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 27
        versionCode 1
        versionName '1.0'

        // Don’t for get your library’s proguard file!
        consumerProguardFiles 'proguard-rules.pro'
    }
}

ext {
    currentFirebaseVersion = "11.8.0"
}

dependencies {
    /* 
    Here we depend on the firebase messaging dependency (via compileOnly),
    allowing us to use the FireBase API within our library module.

    I exclude that org.json module because it may cause build warnings, this 
    step isn’t totally necessary.

    NOTE: You should use `compileOnly` here so the dependency is
    not added to the build output You will be allowed to use the 
    dependency in your library. If the consuming app wants to use firebase
    they’ll need to depend on it (using `implementation`).
    */
    compileOnly("com.google.firebase:firebase-messaging:$currentFirebaseVersion") {
        exclude group: 'org.json', module: 'json'
    }
}

// Other typical library set up. But nothing else relating Firebase.

This is all you need to do in your library project. DON’T apply the gms plug in here, and don’t add the google-services classpath to the libraries build.gradle.

Now here’s how you set up your consuming app:

MyClientApp’s top-level build.gradle:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google() // You know the drill...
    }
    // Any other set up you might have...

    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        /*
        Here in your client app’s top-level build.gradle you add the
        google-services to the app’s classpath.
        */
        classpath 'com.google.gms:google-services:3.2.0'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
// Other basic stuff...
allprojects {
    apply plugin: 'maven'
    apply plugin: 'maven-publish'

    repositories {
        jcenter()
        google()
    }
}

Now we need to set up the consuming applications module build.gradle, it’s simple. We pretty much just need to apply the plug-in, and depend on the library module that we create that has all the FireBase code in it.

MyClientApp’s module level build.gradle:

buildscript {
    repositories {
        google()
        mavenLocal()
    }
}
apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "com.your.application.that.can.use.firebase"
        minSdkVersion 16
        targetSdkVersion 27
        versionCode 1
        versionName '1.0'
    }
    //other typical set up
}

ext {
    currentFirebaseVersion = "11.8.0"
}

dependencies {
    implementation('com.your.library:YourLibrary:1.0@aar') {
        transitive = true
        // Use the consuming application's FireBase module, so exclude it
        // from the dependency. (not totally necessary if you use compileOnly
        // when declaring the dependency in the library project).
        exclude group: 'com.google.firebase'
        // Exclude the "plain java" json module to fix build warnings.
        exclude group: 'org.json', module: 'json'
    }

    implementation("com.google.firebase:firebase-messaging:$currentFirebaseVersion") {
        // Exclude the "plain java" json module to fix build warnings.
        exclude group: 'org.json', module: 'json'
    }
}

// Needs to be at the bottom of file.
apply plugin: 'com.google.gms.google-services'

Some things to note:

  • Must apply google-services plugin at the bottom (only in the client module build.gradle).
  • Depend on the library module that has the FireBase code in it, but exclude it’s version of the FireBase module, in favor of your own dependency version.
  • App depends on it's own FireBase version.
  • classpath 'com.google.gms:google-services:3.1.1’ only goes in the client app’s top level build.gradle.
  • Of course you will need to register the client app and put the google-services.json in your client app’s project.
  • Define the necessary Firebase Services in your app’s manifest (or use manifest merger and merge them in from your library project)
  • Add the google_play_services_version meta-data tag to your client app’s Manifest.
  • The library can/should use compileOnly when declaring the FireBase dependency.

Now you’ll be able to use FireBase code in your app that you defined in your library that uses FireBase. Or you could let your library module do all the FireBase work!

Of course this is typically used for internal libraries, as frameworks like Firebase weren’t designed to be implemented in library modules, but sometimes you need to, so this is a simple non-hacky/sane solution to the issue. It can be used on projects that are distributed through maven -- my library uses this, and it’s never caused any issues.

Update:

You should use compileOnly when declaring the library module's Firebase dependency. By doing so the dependency will not be added to the build output. But you will be allowed to use the dependency in your library. If the consuming app wants to use firebase they’ll need to depend on it manually (using implementation). This will help cut down on unneeded dependencies/bloat in applications and the “right” way to declare a dependency like this. Note: You may need to perform runtime checks to make sure the library is available before using it’s code in your module.


Yes you can actually do this, on your library build.gradle put this inside the defaultConfig field

buildConfigField("String", "FIREBASE_APP_KEY", "\"${firebaseAppKey}\"")

Then inside your project's gradle.properties

firebaseAppKey = <yourFirebaseAppSecret>;

For each project/app you must define this variable on your gradle.properties.

You'll have to create a firebase app for each project, but your library can now have the Firebase SDK.

When you want to access this environment variable value use BuildConfig.FIREBASE_APP_KEY (e.g. instantiate firebase).