I posted this on <#C0B8M7BUY|android>, but maybe t...
# gradle
d
I posted this on #android, but maybe this is a better place for this question: Is it possible to compile multiple android gradle modules into one aar file using Kotlin DSL, or do I have to publish each one separately? Say I have a
:common
some-android-lib
depends on
:common
and
android-app
depends on
some-android-lib
, I want to only publish
some-android-lib
to maven and include
:common
in it, and then only refer to
some-android-lib
in
android-app
...
e
as long as your publishing is set up right, just publish both; a consumer can depend on
groupId:some-android-lib
which will transitively pull in
groupId:common
without the consumer needing to explicitly mention it
d
Yeah... but I really split it into modules for code organisation more than really needing multiple modules... if they were in the same gradle project, I could have just used
implementation(project(":some-android-lib"))
... I can't do that here in any way? I'm trying to avoid all the mess in publication configuration and versioning of these modules...
v
Just version all the same and publish all the same? Shouldn't be much more effort. Just do the logic once in a convention plugin and apply that to all the modules.
d
Do you have an example of the setup @Vampire?
e
implementation("groupId:some-android-lib:version")
should work in an external project just like
implementation(":some-android-lib")
in an internal Gradle project
for consistency you should have the same
project.version
in every project, but it's possible to set that (and
group
) by gradle properties, you don't need a plugin unless you want more logic to it
d
I don't get how
groupId
would get resolved if I have an
app
dir with the application with the gradle root, and another
some-lib
dir with the lib and it's own gradle root... how would gradle know to pull from`some-lib` to compile it with the app without any publications? Originally I separated the lib out of the main project because the main project was managed by another developer, and I was managing the library... but now I have to manage both, and I already have two separate git repos and versioning for each. I actually didn't mind publishing the lib, but when I split it into a few modules, I started getting into this problem.
If there was some kind of example out there, it could make it easier for me to understand how to set this up... I'm not the best at gradle 🤒...
e
Gradle will translate project dependencies into artifact coordinates when publishing
d
Even when they're in completely separate root projects?
e
if they're separate roots how do your current dependencies work?
if it's by maven, it already works. if it's by includedBuild, it should also already work
d
Well, I publish the library to maven (nexus on server, and mavenLocal for development).. but now that I have multiple modules in the lib... it's getting a bit unwieldy...
includedBuild?
v
For local I would strongly recommend not using maven local, but composite build (so includeBuild, yes)
but there may be something I'm just not understanding about your setup
you have two repos, one with multiple projects to publish, and another that wants to consume them?
also, you are publishing directly from Gradle, not manually uploading aar files into your maven instance or something, right?
d
The app, which is only the UI in one module and project (with it's own repo). And the lib (it's own repo too), which has multiple modules, but I really only want it to be compiled into a single aar to be used in the app. And publishing is done to our private Nexus instance straight from gradle.
At first, I thought to make a git submodule, and just put the library into the app's project... but submodules in Git are a bit of a pain...
So I was looking for some easy way to do something similar.
e
then I don't see what the issue is, it should already work out of the box -
Copy code
lib-repo/some-android-lib/build.gradle # group = groupId, name = some-android-lib, version = 1.0
    dependencies { implementation(project(":common")) }
lib-repo/common/build.gradle # group = groupId, name = common, version = 1.0
when you publish this to Maven, you should have
groupId:some-android-lib:1.0
with metadata that indicates that it also depends on
groupId:common:1.0
v
Yeah, submodules are not really good for that. They are nice if you need to integrate something that is not changing at a certain point in its history. But for developing alongside it is not really nice. You could use the https://github.com/melix/includegit-gradle-plugin instead to automatically pull the dependency repository at a certain branch for example and then use a composite build to combine the builds.
e
for local development, if you have access to both repos, then you can use includegit; if you have both repos checked out separately, then you can use includeBuild. but either way, you should use the same maven coordinates as when you're publishing to Maven
d
So it boils down that for development, I could avoid publishing to maven, but for production builds, I need to configure and publish each and every module even if it's in the same project along with the library... I guess something like shadowJar could have solved this problem... but that would be a bit messy too...
v
Why do you need to publish, especially if it is in the same project? o_O
If it is in the same project, you can just use dependencies
And if you use a composite build (either manually or for example using the plugin I mentioned), then it's the same
d
Because the app and the lib depends on one of the modules in the lib... even if I use
api(":common")
in the lib, the code just isn't in the lib's aar...
e
so? it'll follow the dependency to the common lib
v
But the lib depends on common and thus will get pulled in as dependency
Whether you have it in the current build or published doesn't make a difference in that regard
d
So I need to publish common too... I was hoping it would all be included in the lib's aar...
e
Copy code
app-repo/app/build.gradle
  dependencies { implementation("groupId:some-android-lib:1.0") }
if you use
./gradlew --include-build=../lib-repo
then
groupId:some-android-lib
will be resolved from the included build, and otherwise it'll be resolved from maven
(that's what Björn was saying earlier about included builds being better than mavenLocal)
yes, publish both
fat/shadow jars don't work for Android - you'd need to merge the Android resources too, and I don't believe there are any supported tools for that
d
Ok, I guess that's the best option, thanks 🙂! Is there any way to do
--include-build=../lib-repo
straight in the gradle script or in a way Android Studio will do that on a dev build?
e
you can add it to
settings.gradle
, see the docs
v
And if you use the includegit plugin, or even does it for you
e
with its own checkout of the repo, yes
so IMO includebuild is better if you're working on both the libraries and the app at once, while includegit is better for things that are published in git but not published in maven (yet?)
d
Thanks for all the help 😃, all this is clearer now!
Oh well, it looks like
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
doesn't work with composite builds...
e
you should treat includeBuild more like a binary dependency than a project dependency - e.g.
group:module:version
. putting that in a version catalog should work
d
Where do I find the group and version in an android library?
e
(unless you mean that typesafe project accessors don't work inside of an included build? I haven't encountered that, but if so, that should be a bug)
whatever you set them to
by default, group is derived from the project path, and version is UNSPECIFIED. also version doesn't actually matter for included builds, but I was assuming you had set those already since you had mentioned publishing to start with…
d
Where? In each library in the
android { ... }
block, outside it, or maybe in the root build.gradle.kts?... I'm really not so familiar with the more advanced gradle setups...
e
the top level of each project's gradle script
d
So I tried
implementation(":lib-folder-name:module-name")
but it didn't find it...
d
I don't need to include each of the modules separately?
e
drop the leading
:
and it's more likely to be
module-parent:module-name
or
undefined:module-name
, depending on the path structure
no, you should include a complete Gradle build (e.g. the one that contains
settings.gradle
)
but if you're going to publish anything to maven, you should be setting group to something sensible anyway
d
I did that in the publications block:
Copy code
create<MavenPublication>("release") {
                from (components["release"])

                // You can then customize attributes of the publication as shown below.
                groupId = "some-lib-group"
                artifactId = "some-lib"
                version = currLibVersion
            }
Does that help for composite builds?
e
I'm not sure if it does. I've always set the project's group and version; publications' groupId, artifactId, and version default to the project's group, name, and version
(I think it might work, I just never tried)
d
This is getting a bit hard... the app code is still not finding the library code, even though Intellij's gradle pane shows both projects...
e
does it build from command line? (just to rule out IDE issues)
d
same problem
e
and your project names are all unique? not sure then
./gradlew app:dependencies
should show something like
some-lib-group:some-lib -> project :some-lib
d
OOOH.... I put the
includeBuild
in
pluginManagement
like it said in the docs... but in the sample I noticed it was outside of it... so I put it outside and it seems like now it's compiling finally... I just wonder the difference between the two, and how the other one works... the docs are not so clear.
v
The docs are pretty clear imho. Inside the
pluginManagement
is when you are building a Gradle plugin in the included build that you want to use in your build. Outside the
pluginManagement
is when you are building a dependency of your project in the included build like in your case.
d
I guess it's clear for those that understand certain background information about gradle... gradle isn't just a drop it in and it works system... it needs to be learned in more depth to be able to accomplish anything but the more trivial tasks.
v
Well, opinions about that majorly differ. But at least it is more "drop in and it works" than Maven. But however, if you find documentation that you think is not clear, open an issue in the Gradle GitHub. Imho the Gradle docs are one of the best software docs I know and they also always strive to improve, so if you think something is not clear, tell them so they can improve. 🙂