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")
}
}
}