De acordo com a documentação do android:
Seu arquivo APK pode conter apenas um arquivo AndroidManifest.xml, mas o projeto do Android Studio pode conter vários - fornecidos pelo main source set, built variants e libs importadas. Portanto, ao criar seu aplicativo, a compilação do Gradle mescla todos os arquivos de manifesto em um único arquivo de manifesto que é empacotado no seu APK.
A ferramenta de merge combina todos os elementos XML de cada arquivo, seguindo algumas heurísticas de merge e obedecendo às preferências de merge que você definiu.
E o porque estamos falando de Manifest-Merger? Se dermos uma olhada em nosso AndroidManifest, iremos descobrir como algumas libs conseguem fazer sua inicialização sem a interferência do programador que irá utilizá-la…
Em nosso Estudo de caso iremos investigar como o Firebase faz essa magia. No final do nosso AndroidManifest após o processo de merge, podemos ver o import de um provider
<provider
android:name="com.google.firebase.provider.FirebaseInitProvider"
android:authorities="APPTEMPLATE.firebaseinitprovider"
android:exported="false"
android:initOrder="100" />
Se investigarmos a classe FirebaseInitProvider poderemos ver que esse provider tem acesso ao contexto da aplicação usando this.getContext()
public boolean onCreate() {
if (FirebaseApp.initializeApp(this.getContext()) == null) {
Log.i("FirebaseInitProvider", "FirebaseApp initialization unsuccessful");
} else {
Log.i("FirebaseInitProvider", "FirebaseApp initialization successful");
}
return false;
}
Mas se analisarmos essa classe poderemos ver que o fato dela extender a ContentProvider a obriga implementar os métodos insert, query, onCreate, update, delete, getType.
DefaultProvider
Como vimos, a necessidade de implementar todos os métodos citados acaba tornando nosso Provider longo… Para mitigarmos esse problema, utilizaremos um DefaultProvider, uma open class.
open class DefaultProvider : ContentProvider() {
override fun insert(uri: Uri?, values: ContentValues?): Uri { TODO("not implemented") }
override fun query(uri: Uri?, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor { TODO("not implemented") }
override fun onCreate(): Boolean { TODO("not implemented") }
override fun update(uri: Uri?, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int {TODO("not implemented")}
override fun delete(uri: Uri?, selection: String?, selectionArgs: Array<out String>?): Int { TODO("not implemented")}
override fun getType(uri: Uri?): String { TODO("not implemented") }
}
A partir disso, iremos fazer com que nosso provider estenda-o.
KoinProvider, StethoProvider, CacheProvider
Diante do exposto, iremos construir nossos providers.
class KoinInitProvider : DefaultProvider() {
override fun onCreate(): Boolean {
context?.let { startKoin(it, appTemplateModules) }
return true
}
}
class PreferenceCacheInitProvider : DefaultProvider() {
override fun onCreate(): Boolean {
context?.let { PreferencesCache.init(it) }
return true
}
}
class StethoInitProvider : DefaultProvider() {
override fun onCreate(): Boolean {
if (BuildConfig.DEBUG) context?.let { Stetho.initializeWithDefaults(it) }
return true
}
}
e em nosso AndroidManifest.xml
<provider
android:name=".provider.koin.KoinInitProvider"
android:authorities=".provider.koin.KoinInitProvider" />
<provider
android:name=".provider.cache.PreferenceCacheInitProvider"
android:authorities=".provider.cache.PreferenceCacheInitProvider" />
<provider
android:name=".provider.stetho.StethoInitProvider"
android:authorities="com.facebook.stetho.StethoInitProvider" />
Conclusão
Bom, com a utilização do ContentProvider podemos eliminar a nossa classe AppTemplateApplication.class e utilizar um recurso do Android para inicializarmos as libs que o projeto utiliza.
Além da retirada da AppTemplateApplication, notamos que todos os providers utilizam o null safety do Kotlin para atribuir o contexto a inicialização das libs.
Esse artigo surgiu de um papo de dois devs paixão, valeu Matheus Kreuz Bristot pelo café e por essa abstração show.
Ps: Quer trocar uma ideia sobre o artigo ou sobre desenvolvimento mobile? Deixa um comentário show, que vai ser um prazer responde-lo.