Your android libraries should not ask for an application context

What is the first thing we need to do when we import a library ? Override an Application class to initialize it with a context 😞 But why ? and why some libs like Firebase 🔥don’t need to be initialized ? lets take a look 🧐

We need to initialize our library

Let’s take an example, we want to use Stetho in our app, following the documentation, it needs to be initialized with the app context, so we need to create an application if we don’t have one :

class MainApplication : Application() override fun onCreate() super.onCreate() 
Stetho.initializeWithDefaults(this)
>
>

This application needs to be declared in our AndroidManifest.xml to be executed :

application 
android:name=".MainApplication"
.

A lot of libraries

Now imagine we use Stetho, JodaTimeAndroid, Crashlytics and Realm, our application will look like

class MainApplication : Application() override fun onCreate() super.onCreate() Fabric.with(this, new Crashlytics()) 
Stetho.initializeWithDefaults(this)
JodaTimeAndroid.init(this)
Realm.init(this)
>
>

In my project, I need to override an application only for… initializing my libraries

Libraries that do not need to be initialized

When you include Firebase 🔥, it does not ask for any initialization, you just have to use :

This database access do not needs a context, and can stored locally, for offline access. We can assume it’s initialized automatically, and has a mechanism to retrieve the application context.

ContentProvider & Manifest-Merger

Your APK file can contain just one AndroidManifest.xml file, but your Android Studio project may contain several—provided by the main source set, build variants, and imported libraries. So when building your app, the Gradle build merges all manifest files into a single manifest file that's packaged into your APK.

If we take a look at our merged AndroidManifest.xml :

We can find at the end of this file a provider that have been imported from the Firebase library :

Looking inside the FirebaseInitProvider, we understand that this provider has access to the application’s context using this.getContext().

ContentsProviders are initialized and called directly after the application’s object is created, it’s a good idea to use them to init a library !

Automatically initialize our library

We can imagine facebook adding a StethoInitProvider for its initialization :

class StethoInitProvider : ContentProvider()  
override fun onCreate(): Boolean Stetho.initializeWithDefaults(context)
return true
>
.
>

And exposing this provider in its AAR/AndroidManifest file

provider 
android:name=".StethoInitProvider"
android:authorities="com.facebook.stetho.StethoInitProvider"
/>

Using Gradle to import this version of Stetho, we will not need extra code to initialize this library in our project 😎

As a result, if we have to configure Stetho, it should have some statics methods like

Our project without application

If our library doesn’t use InitProviders, we can create our own :

class JodaTimeInitProvider : ContentProvider()  
override fun onCreate(): Boolean JodaTimeAndroid.init(this)
return true
>
.
>
class RealmInitProvider : ContentProvider()
override fun onCreate(): Boolean Realm .init(this)
return true
>
.
>

And add them to our AndroidManifest :

provider 
android:name=".JodaTimeInitProvider"
android:authorities="
$.JodaTimeInitProvider" />
provider
android:name=".RealmInitProvider"
android:authorities="
$.RealmInitProvider" />

We can now remove our useless MainApplication.class

BONUS STAGE

I developed a library to retrieve the Application from anywhere and the current Activity, don’t hesitate to try it !