Does it possible to provide dependency w/o direct ...
# dagger
m
Does it possible to provide dependency w/o direct module dependency? Hilt: 2.40.5 AGP: 7.1.2 Gradle: 7.4 e.g:
Copy code
:presentation -> :domain <- :data
Copy code
// in :domain module
class class AnalyticsUseCase @Inject constructor(
    private val repository: AnalyticsRepository,
) {
   // omitted
}
Copy code
// in :data module

@InstallIn(SingletonComponent::class)
@Module
interface BindAnalyticsModule {
    @get:[Binds]
    val AnalyticsRepositoryImpl.analyticsRepo: AnalyticsRepository
}

internal const val DEFAULT_DATASTORE = "_datastore"

@InstallIn(SingletonComponent::class)
@Module
object ProvideAnalyticsModule {
    @Singleton
    @Provides
    fun provideDataStorePreference(
        @ApplicationContext context: Context,
    ): DataStore<Preferences> {
        val packageName = context.packageName
        val dataStoreName = "$packageName$DEFAULT_DATASTORE"
        return PreferenceDataStoreFactory.create(
            produceFile = { context.preferencesDataStoreFile(dataStoreName) }
        )
    }
}
Copy code
// in :presentation module

@HiltViewModel
class DashboardViewModel @Inject constructor(
    private val analyticsUseCase: AnalyticsUseCase,
    private val dataStore: DataStore<Preferences>,
)
:presentation
has no dependency to
:data
in
presentation/build.gradle
This seems not possible especially since depends on
hilt-android
, after trying it out
will try this with
hilt-core
(for dependency that not requires android related)
j
it is possible
m
in my part, especially when depends on both
hilt-android
&
datastore-preferences
(w/o
-core
suffix, has android dependencies) fails to compile. Any references or samples to lookup first, if there’s any?
j
data is being added as dependency in app or the di module?
m
currently still using the former (added as dependency in app) as failed to compile when doing the later (added as deps in di module)
j
is it open source?
m
unfortunately no 🙏
j
if you create a repro I can try to fix it
🙏 1
m
hopefully, will do this weekend!
👍 1
https://github.com/mochadwi/hilt-bridge-module hopefully this minimal project makes senses, lmk if there’s something I can do to help 🙏
j
can you add the presentation module with hilt and viewmodel dependencies?
m
updated
j
I can't see the presentation module, you want that the app and the presentation module would be the same?
in that case you can't isolate data for presentation, app module needs to know everything
the only way is: app adds as dependencies the three modules presentation -> domain <- data
merging presentation and app into one implies presentation needs to know everything
m
wait, I’m renaming the module from
legacy
to
presentation
now
cmiiw, did you mean we need to have a dedicated
presentation
module? e.g:
Copy code
| domain // kotlin library
| data:analytics // android library
| presentation // contains dagger moduler provider etc, android library
| app // android application
j
exactly
providers can be in data or in app
presentation probably doesn't need providers since they are viewmodels so the viewmodel annotation is enough
I mean, presentation only needs @Provides if it has to provide some presentation dependency, which is not usual because you usually provides third party dependencies which would be in data, generally. There can be exceptions tho
✍️ 1
i.e. ktor or retrofit client, room and so on, they are in data
1
m
I seee, til 🙏. Previously we though the
app
modules behaves as
presentation
app adds as dependencies the three modules
This part seems inevitable right? I tho’ we can prevent our application to have import from
data
layer
j
you can't prevent that
😭 1
but at same time you can organice your modules so you app module is almost empty (only having the application file with hilt annotation and the manifest
✍️ 1
m
this is also applicable for dynamic feature I presume? as our original codebase using dynamic feature and due to its limitation us frequently provide dependencies inside dynamic feature module as well
j
I only mounted the setup for dynamic feature one time, but before hilt even exists. I don't like how it works because the dependencies are totally (or was) inversed. If that doesn't change, I wouldn't use it
and Hilt doesnt work very well with dynamic features
you have to do hacks/workarounds
😞 1
m
Thank you for the guidance, there’s might be a few questions in mind, one of them are following: Does it also mean
:app
needs to depends on different data-layer implementation
:data:<sub module>
, e.g:
Copy code
:data // common or core
:data:analytics // implementation details of analytics tracker
dependency:
Copy code
:presentation -> :domain <- :data <- :data:analytics // like this, I presume?
:presentation <- :data:analytics // avoid doing this?
Based on your suggestions here (cmiiw):
Copy code
:app -> :domain
:app -> :data
:app -> :data:analytics
:app -> :presentation
j
it depends
if data modules are adding as dependency other data modules using api, no, if not, yes
✍️ 1
m
to summarize, the
:app
required to add everything (
:data:<submodule(s)>
) as dependencies (using
api
?) even tho’ there’s no direct import / usage in
:app
as long all of the
@Provider
(for concrete impl.) are exist inside
:data:<submodule>
(and
:data
) in order for dagger to compiled properly? cmiiw
let me also confirm this statement here:
if data modules are adding as dependency other data modules using api,
does this means (see image attachment by order): 1️⃣ 2️⃣ 3️⃣
j
app —impl—> analytics —api—> data
🙏 1
app should not have api in its gradle file, because no module adds app as dependency
today i learned 1
m
another issues I’ve found: e.g:
Copy code
// interface in :data (a kotlin library)
interface DataSource {}

// and injected by
class SomeClassDataStore @Inject constructor(private val dataSource: DataSource)
Copy code
// concrete implementation & DI provider in :data:sharedprefs
// (is an android library)
class SharedPrefsManager : DataSource {}

@InstallIn(SingletonComponent::class)
@Module
interface BindSharedPrefsModule {
    @get:[Binds DataStorePreferences]
    val SharedPrefsManager.sharedPrefsManager: DataSource
}
as
:data
doesn’t have direct dependencies to
:data:sharedprefs
, meanwhile doing that will resulting in a cyclic dependencies
is there any workaround for this that I might’ve missed? should we move the
SomeClassDataStore
to another modules’ that has dependencies on both:
:data
&
:data:sharedprefs
in this case?
j
probably yes
but not sure what are you putting inside data and inside sharedPrefs
what you app module is adding as dependencies?
if it knows everything dagger should has no problems
m
what you app module is adding as dependencies?
Copy code
// app/build.gradle

implementation(project(":data"))
implementation(project(":data:analytics"))
implementation(project(":data:shared-preferences"))
Does it possible to create a dagger bridge module instead? so the app module can depends on dagger bridge module only e.g:
Copy code
:app -> :dagger-bridge

:dagger-bridge -> :data
:dagger-bridge -> :data:sharedprefs
:dagger-bridge -> :domain
j
yes
🙏 1