Android Gradle Dependency - android-gradle-plugin

I am using local aar files for one of our projects and have below Query.
I have 2 libraries and 1 application.
2 libraries are:
1. TestLib2
2. TestLib1
1 Application is:
1. Test
I use a aar file created for TestLib2 and refer it using flatDir in TestLib1. I can access the functions present in TestLib2 without any problems.
Now I use a aar file created for TestLib1 and refer it using flatDir in Test. I can access only the functions present in TestLib1. For accessing TestLib2 i have to add it to Test application as one more Library.
So the dependency is like below:
Test
|_ TestLib1
|_ TestLib2
Is the above possible in case of aar files?
Also in settings.gradle file for TestLib1 i mention to include
include ':app', ':testlib2-debug'
Where app refers to the TestLib1
The build.gradle file doesnt really have any flavors as such and i dont even have any restriction of using them as jar's since its containing only the java piece of code.
Any help on the same is much appreciated.
BR,
Jayshil
Update 1:
I tried below as well in build.gradle of TestLib1 and Test.
Still no luck.
dependencies {
compile (name:'testlib2-debug', ext:'aar') {
transitive = true;
}
}
And for Test App
compile (name:'testlib1-debug', ext:'aar') {
transitive = true;
}

So i finally figured out a solution for this.
It works for 2 level dependency mentioned above.
Create a jar file for Test Lib 2.
task clearJar(type: Delete) {
delete 'build/outputs/loggingSDK.jar'
}
task makeJar(type: Copy) {
from('build/intermediates/bundles/release/')
into('build/outputs/')
include('classes.jar')
rename ('classes.jar', 'testlib2.jar')
}
makeJar.dependsOn(clearJar, build)
By using a the command
gradle makeJar
You would have got a testlib2.jar
Copy this into your TestLib1
Use command
gradle assemble
This would create debug and release version
Take the debug version and copy it in Test you would be able to call functions of TestLib1 which in turn calls function of TestLib2
Hope this may help someone looking for such solution

Related

javascript as target in kotlin multiplatform library

I'm building a Kotlin multiplatform library. One of the targets in this project is javascript. In the source set I have added a dependency like this:
val jsMain by getting {
dependencies {
implementation(npm("libphonenumber-js", "1.10.13"))
}
}
The gradle sync was successful, now I want to import the files in jsMain directory. How can I achieve this?
Add npm dependency with generateExternals as you already did
implementation(npm("libphonenumber-js", "1.10.13", generateExternals = true))
generateExternals = true triggers a tool called Dukat that generates Kotlin external declarations from the Typescript definition file of that npm module.
Once your project syncs, it would have externals folder under your shared module's build folder like shown below,
(Ignore kmp-lib-1621 in above image. That would be your module/library name instead)`
Now copy and paste these files in your project (jsMain source set) and remove generateExternal = true from your dependency otherwise it would generate this files everytime. (1) you would lose any manual change (2) if you update the library version then it can potentially break your project
You should be able to call generated external code from Kotlin code, whether you keep it in build folder or you pasted it in your project code.
Important Note: Dukat tool is experiemental and known to create externals that may not work 100% times. So remove all unnecessary code from external generated code so you only end up having few references of classes you want to use from the npm library. Do some trial and error and you would be fine.
Hope this helps!
You have to use js(IR) backend and generate externals
implementation(npm("libphonenumber-js", "1.10.13", generateExternals = true)).

Multi-project Gradle+Kotlin: How to create Jar containing all sub-projects using Kotlin DSL?

I have a Gradle project with two subprojects. The parent does not contain any code; all the Kotlin code is in the two subprojects. All Gradle build files are defined in the Kotlin DSL.
Upon building, Gradle generates two JAR files, one in the build subfolder of each subproject. I believe this is the intended default behavior of Gradle. But this is not what I want.
I want to publish the JAR file of the parent project as a Maven artifact. Therefore, I need both subprojects to be included in one JAR file. How can I achieve this?
Note: On this web page, the author seems to achieve pretty much what I would need in this code snippet:
apply plugin: "java"
subprojects.each { subproject -> evaluationDependsOn(subproject.path)}
task allJar(type: Jar, dependsOn: subprojects.jar) {
baseName = 'multiproject-test'
subprojects.each { subproject ->
from subproject.configurations.archives.allArtifacts.files.collect {
zipTree(it)
}
}
}
artifacts {
archives allJar
}
However, this is defined in Gradle's native Groovy DSL. And I find myself unable to translate it into the Kotlin DSL. I tried to put a Groovy build file (*.gradle) besides the Kotlin build file (*.gradle.kts), but this led to a strange build error. I'm not sure if mixed build file languages are supported. Besides, I would consider it bad practice too. Better only define all build files in just one language.
Also, the example above pertains to the Java programming language. But I do not expect this to be a big problem, as both Java and Kotlin produce JVM bytecode as compile output.
More clarification:
I am not talking about a "fat JAR". Dependencies and the Kotlin library are not supposed to be included in the JAR.
I do not care if the JAR files for the subprojects are still getting built or not. I'm only interested in the integrated JAR that contains both subprojects.
The main point is getting the combined JAR for the binaries. Combined JARs for the sources and JavaDoc would be a nice-to-have, but are not strictly required.
I would use the Gradle guide Creating "uber" or "fat" JARs from the Gradle documentation as a basis. What you want is essentially the same thing. It's also much better than the Groovy example you found, as it doesn't use the discouraged subprojects util, or 'simple sharing' that requires knowing how the other projects are configured.
Create a configuration for resolving other projects.
// build.gradle.kts
val mergedJar by configurations.creating<Configuration> {
// we're going to resolve this config here, in this project
isCanBeResolved = true
// this configuration will not be consumed by other projects
isCanBeConsumed = false
// don't make this visible to other projects
isVisible = false
}
Use the new configuration to add dependencies on the projects we want to add into our combined Jar
dependencies {
mergedJar(project(":my-subproject-alpha"))
mergedJar(project(":my-subproject-beta"))
}
Now copy the guide from the docs, except instead of using configurations.runtimeClasspath we can use the mergedJar configuration, which will only create the subprojects we specified.
However we need to make some modifications.
I've adjusted the example to edit the existing Jar task rather than creating a new 'fatJar' task.
for some reason, setting isTransitive = false causes Gradle to fail resolution. Instead I've added a filter (it.path.contains(rootDir.path)) to make sure the Jars we're consuming are inside the project.
tasks.jar {
dependsOn(mergedJar)
from({
mergedJar
.filter {
it.name.endsWith("jar") && it.path.contains(rootDir.path)
}
.map {
logger.lifecycle("depending on $it")
zipTree(it)
}
})
}

Skeleton for Kotlin/native multiproject with dll library for backend and frontend app using it

I'm trying to create a multiproject using Kotlin/native and gradle in IDEA that consists of:
A backend subproject library. I want to use this library in frontend Kotlin app and also produce a native DLL that can be later used in other software. I doubt I'll need any platform specific behavior -- the most I'll interact with the system is read, write and watch a file for changes.
A frontend jvm app in Kotlin using this library as required dependency. To be more precise I'm going to write a glfw app in Kotlin that will use this lib, but that's a detail you don't have to bother with.
I want to be able to:
build DLL on it's own
build an app that depends on library and rebuilds if needed when the lib changed.
I made a hyperlink trip over gradle docs, JetBrains examples and repos but I don't quite understand how to make a multiproject like that. Can someone provide a minimal working example of such a Hello World project?
Right now this works for me in the initial stage of the project:
Use gradle init with basic type and kotlin DSL to generate a wrapper project
Add 2 modules with New > Module > Gradle > Kotlin/Multiplatform and Kotlin/JVM. That should add include("...") entries to root settings.gradle.kts At this point those modules will be empty with a single build.gradle.kts scripts
Root build.gradle.kts can be deleted - both library and app use their own
In the Multiplatform library setup at least one target for example like that:
// rootProject/library/build.gradle.kts
// ...
kotlin {
jvm() // used by jvm app
sourceSets { /*...*/ }
}
Now there should be no gradle errors and IDEA will detect the project properly - refresh gradle configuration (CTRL+SHIFT+O)
Create source directories for each module (because the modules rn): IDEA should hint the names of corresponding source sets (src/<target>/<kotlin|resources> etc.)
So now just to link the app and library together in the the app's buildscript add the implementation(project(":library")) dependency
Of course don't forget to configure the library target for example using linuxX64("native") { binaries { sharedLib {/*...*/ } } } block in kotlin plugin when trying to generate a DLL
Now it should mostly work. The structure of a project I'm working on rn looks like that:

Intellij: Define default task to be used for all new Java projects

For almost every Java project I have, I define a new Gradle task to build a jar with the javadocs. Specifically, I add the following to almost every build.gradle:
task jarJavadoc(type: Jar, dependsOn: ['javadoc']) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives jarJavadoc
}
Is there a way to configure Intellij so that it automatically adds these lines to every new Gradle Java project?
I think you could explore couple of options:
First is creating a gradle file (e.g. init.gradle) in your GRADLE_HOME directory (e.g ~/.gradle/) and define the common parts there. Gradle always applies those files first while processing your build scripts. Note, everything you configure there is going to be available in
every Gradle project on your machine. Which means e.g. if you depend
on Java plugin (like you do in an example you provided) and you create
other project which doesn't depend on Java, this approach may produce
configuration errors so use it with caution.
You could write a simple Gradle plugin which adds common tasks you require to a project. With this approach you will still need to duplicate the apply plugin: 'your plugin'
You could leverage File and Code templates and update Gradle build script template to include the common code.
You can also mix the last 2 examples and write a plugin which configures the common tasks and modify Gradle build script template to include your plugin.
You could apply the nebula.javadoc-jar plugin.
Eg:
plugins {
id 'nebula.javadoc-jar' version '5.1.0'
}

Is There A Way To Create A Joint Intellij Project Spanning Multiple Gradle Projects As Modules

So it actually seems to mostly work, with both projects as sub-modules of the overall project. But the major annoyance is that when I debug in one of the modules, if code calls something in the other module it picks up the dependency from the Gradle cache instead of the other project/module's code and steps into a decompiled .class file from its cache instead of the actual source code.
I'd like to find a way so Intellij recognizes one module is using the other and uses the source code from the module itself which is of course checked out and available in the local filesystem.
See gradle documentation here about setting up multiple projects as "sub-modules", though gradle lingo usually refers to them as sub-projects.
Basically, if you have some projects that are sub projects of a root project, you would setup the folder structure like this:
root
├───build.gradle
├───settings.gradle
│
├───subA
│ └───build.gradle
├───subB
│ └───build.gradle
└───subC
└───build.gradle
In your root settings.gradle, you include your sub projects by adding:
include 'subA', 'subB', 'subC'
From this point on, you can refer to any project in your setup from any other project by its name: project(':subB')
so If you want to add subC as a compile time dependency of subA, in subA's build.gradle, you would have:
dependencies{
compile project(':subC')
}
Declared this way, the dependency is on the current files of subC instead of the last built/installed binaries from the repository. You could also have root project just a holder project with no code of its own.
I've had some success using dependency substitution in a development mode kinda like this:
if (project.has("devMode")) {
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute module("foo.group:bar") with project(":bar")
}
}
}
Hopefully something like that may work for you, too.
EDIT: note that you'll also have to conditionally add the :bar project in settings.gradle as well