Thomas Chan
04/09/2025, 6:34 AMβββββββββββββ
βApplicationβ
ββ¬βββββββββ¬ββ
ββ½βββββββββ½βββββββββββββββββββββββ
βFeatureββExternal Library B (v4)β
ββ¬ββββββββββββββββββββββββββββββββ
ββ½ββββββββββββββββββ
βExternal Library Aβ
ββ¬ββββββββββββββββββ
ββ½βββββββββββββββββββββββ
βExternal Library B (v5)β
βββββββββββββββββββββββββ
β’ We can modify Application
and `Feature`; we CANNOT modify external libraries A
and B
.
β’ Application
requires version 4 of library B
to run, and crashes when B
is updated to version 5.
β’ External Library A
declared version 5 of B
as dependency, but actually works perfectly fine with version 4 of B
.
Problem is that the Application
crashes due to library B
being "automatically upgraded" (resolved) to version 5.
My solution to this is to add a resolutionStrategy
block to force the use of version 4 of B
through all its transitive dependencies:
configurations.all{
resolutionStrategy {
force("test.library:b:4.0.0")
}
}
Trouble is, the above resolutionStrategy
block only works when it is put in the build script of the top level project (i.e. Application
in this case); it does not work when put in the build script of Feature
.
As such, we have to instruct all users of Feature
to add the resolutionStrategy
block above. While this works it is clearly not a very nice solution.
Is there a way to handle this such that the users of Feature
don't have to perform the version resolution?
(like perhaps, a way to resolve the version on Feature
project, such that top level projects don't have to handle it?)Vampire
04/09/2025, 6:51 AMBenedikt Ritter
04/09/2025, 8:10 AMApplication
, why don't you update the code to work with B v5? It's just a question of time until you will find yourself in the same situation again, when Lib A stops working with Bv4.Thomas Chan
04/09/2025, 8:14 AMconstraints
block don't seem to exist for Kotlin Multiplatform's plugin's dependencies
, and doing it separately out of the block don't work neither:
dependencies {
//<http://docs.gradle.org/8.5/userguide/single_versions.html#sec:declaring_without_version>
commonMainImplementation("test.library:b")
constraints {
commonMainImplementation("test.library:b:4.0.0")
}
}
Thomas Chan
04/09/2025, 8:17 AMB
to v5 is a good solution, but for my case I am actually developing Feature
for my coworker who maintain Application
. I want to make using my Feature
as easy as possible for my coworker.Benedikt Ritter
04/09/2025, 8:19 AMVampire
04/09/2025, 8:37 AMcommonMainApi
instead so the constraint propagates to the consumer? π€·ββοΈVampire
04/09/2025, 8:37 AMThomas Chan
04/09/2025, 8:37 AMFeature
with strict versioning syntax on B
(even though Feature
doesn't use B
directly)
val androidMain by getting {
dependencies {
//...
implementation("test.library:b:4.0.0!!")
}
}
Vampire
04/09/2025, 8:38 AMVampire
04/09/2025, 8:39 AMVampire
04/09/2025, 8:40 AMThomas Chan
04/09/2025, 8:45 AMconstraint
block with commonMainApi
and api
didn't workThomas Chan
04/09/2025, 8:46 AMVampire
04/09/2025, 8:46 AMThomas Chan
04/09/2025, 8:52 AMimplementation("test.library:b"){
version{
strictly("[2.0.0, 4.0.0]")
prefer("4.0.0")
}
}
But yes I see your point... this can only be done with the assumption that all consumers of Feature
does not depend on v5 of B
, and it removes their flexibility to do that in the future...
So you're right, its the best to just make version conflict handling the responsibility of the end-project π€Vampire
04/09/2025, 8:54 AMVampire
04/09/2025, 8:55 AMThomas Chan
04/09/2025, 8:58 AMexclude
block didn't work somehow, this didn't work:
val androidMain by getting {
dependencies {
//***
api("test.library:a:1.0.0"){
exclude(group = "test.library", module = "b")
}
}
}