Some build.gradle files have different syntax's then others? - android

Started a new job and I can see that the build.gradle files's syntax is a bit different like the one using a = to assign values and the other just without it. Fx. the Google Sunflower demo app has it's implemetation statements without parentheses and my project uses parentheses and will not work otherwise.
I'd like to have all add-on versions in one place as I'm used to, and as it's of-course in the Sunflower app:
ext {
appCompatVersion = '1.1.0'
...
}
but that fails in my project
What is going on?

Gradle is a build automation tool, which can be written in several languages, more importantly when it comes to Android Studio, Gradle files tend to be either written in Gradle's own Groovy DSL language which is heavily based on Apache Groovy's language, which is usually referred to in documentations as just Groovy, or they can be written in Kotlin DSL, which is based on its parent namesake Kotlin language, Gradle's Kotlin DSL support was announced in 2016 which is why you might find legacy projects using Groovy, while others are using Kotlin DSL.
You can tell the difference between Groovy Gradle files and Kotlin DSL Gradle files by looking at the file extension, a settings.gradle is a Groovy script and settings.gradle.kt is a Kotlin DSL script.
Note that Gradle supports interoperability between Groovy and Kotlin DSL files, meaning that, while a settings.gradle must be written in Groovy and a build.gradle.kt must be written in Kotlin DSL, it's OK to have a project that have both settings.gradle and build.gradle.kt, Gradle is smart enough to make them understand each other, although for the sake of consistency, I would recommend sticking with one DSL language for all your Gradle files.
By default when you create an Android project for the first time, the Gradle files generated for you are in Groovy.
For much, much more thorough details on the differences between the two syntaxes I highly recommend reading the Gradle docs, this page in particular which goes into migrating from Groovy to Kotlin DSL, starting from the "Prepare your Groovy scripts" section. It's handy to have it on your side whenever you're copy/pasting a Gradle fix from Stackoverflow which is written in a Gradle syntax that doesn't correspond to your Gradle file extension, although eventually you'll probably end up memorizing the little differences yourself.

Don't confuse build.gradle (Groovy) with build.gradle.kts (Kotlin).

Related

How to organize common gradle tasks and extract common code blocks

I have an android project consisting of 10+ library modules. Each of these modules contains a lot of gradle code common to all modules. For example, I'm using the Javadoc generation task from this answer in all of my build.gradle files.
How would I go about to extract that task creation logic to a function put in a separate gradle file which can be "included" by each module? The code is identical for all my modules, but obviously depends on variant and project. Is it possible to extract a function that takes a project as parameter and returns a task for that project?
I'm probably going around this backwards since I really suck at Gradle but any pointers leading to me avoiding having the same 60 lines of gradle code in 10 different files (lib1/build.gradle, lib2/build.gradle, ...) would be helpful!
In fact, taking it even further, basically my entire build.gradle is identical for all projects except the dependencies section - there's an android block with buildTypes, compileOptions etc, there are some plugins applied (apply plugin: 'com.android.library' etc), and there are some artifact parameters set up. In fact, only my dependencies differ at all. So I'm wondering if it would be possible to extract a common file completely, like this (pseudo code obviously):
<include common.gradle> // includes android block, common tasks, artifact setup etc.
dependencies {
api 'androidx.appcompat:appcompat:1.1.0'
api 'com.google.code.gson:gson:2.8.5'
...
}
You can extract your common settings into a gradle file (lets say common.gradle and then use it as
apply from: '../path/to/common.gradle'
Reference: https://docs.gradle.org/current/userguide/plugins.html#sec:script_plugins
The recommended way of extracting common build logic is to leverage buildSrc and create plugins that are then applied to your projects.
This has a number of benefits of applying a script, as documented.
In addition, I would recommend being explicit through plugin application. While you could develop a single plugin that configures all your projects, with some logic based on project name for example, it is usually better to have different plugins matching the different project types.
That way, when opening a build file you immediately see what kind of project it is.
And of course you can have common code in buildSrc for the common parts.
One more benefit is that moving from a buildSrc plugin to a published plugin is much easier ... just in case your configuration patterns start to appear in different projects.

ReactNative add Gradle Dependency using Android Studio

I am very new to Mobile Development especially with the use of Android Studio and Java (but i'm familiar with the language already as i came from C#). But the challenge is i don't yet how to configure the project itself unlike what i can do in VS.
Basically i am trying to include a downloaded SDK, the package looked like it is the same as my project (contains Gradle, etc, etc, so i've thought this is Gradle Project).
What i have tried
is going to file -> Project Structure -> Dependencies -> Add Dependency. Which is basically including a Gradle Project from the options.
It went a-okay but i'm not aware yet it this was right? I checked the Docs from android studio and included the dependency in my Gradle.
It goes like this: implementation project(":MyDownloadedProject")
I know this is pretty simple but i've been checking out stuffs for a long time already but unable to find any useful resource.
Thanks a lot!
Add build dependencies with autolinking or by manually adding to build.gradle
see https://developer.android.com/studio/build/dependencies

Kotlin common library to reuse in multiple MPP

I'm setting up a Kotlin multiplatform project so I can reuse common code in multiple platforms for a single app. While building the common code for the app, I've extracted some base classes that I'd like to be able to reuse as a library in multiple multiplatform projects. I'm trying to add the library as a dependency in commonMain. There are a couple of things I don't understand.
First of all: is this currently possible?
If yes:
The default stdlib-common is a jar file, correct? How come a jar can be referenced as a dependency in commonMain if no Java can be used there? Or is it okay to use a jar compiled from pure Kotlin, as long as it only has Kotlin dependencies?
How do I compile a pure Kotlin jar that can be used in commonMain the same way as stdlib-common is used? Are there any sample build.gradle projects or guides for how this should be packaged?
If no:
What options do I otherwise have to reuse code over multiple multiplatform projects, if I want to avoid duplication? Do I actually need to keep all source within the actual commonMain source folder? Can it be linked from another folder if so? I tried adding additional content roots but it didn't seem to work since Gradle controls the configuration and I'm not sure how to add additional content roots in commonMain through Gradle.
Thanks in advance.
I got it working, mainly from looking through this thread and looking at this example. Although some of it might be dated by now, it helped me understand the following:
MPP1 can have another MPP2 as a dependency. Here is a list of MPP libraries for reference.
MPP2 needs to generate artifacts for the same set of platforms as it is used in by MPP1.
MPP2 generates platform artifacts along with a module file where they are described. MPP1 can then use the below configuration. Thanks to the module file, it's not required to explicitly add each platform's corresponding dependency, the dependency only needs to be declared in commonMain.
commonMain {
dependencies {
implementation kotlin('stdlib-common')
implementation 'com.company:mpp2:1.0'
}
}

Can I use Android data-binding with Maven?

There's a beta release of a data-binding library by Google. According to the docs
To use data binding, Android Plugin for Gradle 1.3.0-beta1 or higher is required.
In my project I need to use Maven instead. I'm trying to set up a minimal initial project. The problem is that the new data-binding library somehow mangles processing of the XML layout file that generates the R class and probably requires a gradle plugin: android/databinding/tool/DataBinderPlugin
There is no information on how to handle this without Gradle. Does anyone know what needs to be done to make this run with Maven as well?
There hasn't been a lot of effort put into this since most developers use gradle. That said, I did a quick bit of development to try to enable make builds that you could try out. There is a class android.databinding.tool.MakeCopy that you can try to run. It is a command line interface that copies resources from one or more directories to a target directory, modifies the layout files, and generates some artifacts that are required by the annotation processor (xml files, source files).
It should be included in the library with the annotation processor. You'll have to work out the full class path requirements to get it to work. As I said, I didn't spend a lot of time getting it going because we didn't have any clients for it.

Android Studio Gradle External Library Project

Ok, I realize that Gradle and Android Studio seem to think that all Library Applications are built for one project and one project only, but that is not the case. I have many shared Library Applications with common purposes that are shared throughout the organization. Gradle does not seem to be very accomodating to this desired solution. Can someone offer any insight?
My current Structure at a very rudimentary level is like this:
|--Directory
| |--PROJECT A
| |---Module 1
| |--Project B
| |---Module 2
| |--Project c
| |--Module 3
/////////////////////////////////////////////
My Current dependency structure is like this:
/////////////////////////////////////////////
Project A: (FYI, Builds Just Fine)
Project A's settings.gradle
include ':Module 1', ':Module 2'
project(':Module 2').projectDir = new File('../Project B/Module 2')
Module 1's build.gradle
dependencies {
compile project(':Module 2')
}
Project C: (FYI, BROKEN)
Project C's settings.gradle
include ':Module 3', ':Module 1'
project(':Module 1').projectDir = new File('../Project A/Module 1')
Module 3's build.gradle
dependencies {
compile project(':Module 1')
}
Breaks: Cannot resolve Module 2 inside of Module 1's build.gradle file.
This is because the directory structure for Module 2 is established inside Project A's settings.gradle so Project B has no idea where to render this from.
I understand that I can add
project(':Module 2').projectDir = new File('../Project B/Module 2')
to Project C and everything will work just fine. However Project C doesn't use or know about Module 2. I want other developers to have the freedom to use my common shared library project without having to dig in and see what library projects I used and include those in their settings as well. How can I specify my own dependency directory structure in the build.gradle instead of the settings.gradle to make it accessible to all that use it?
On a second note, but similar topic. I'm having the exact same issue with JAR files. If i specify a REPO in a Library Project's build.gradle like: myRepo1 and have a myJar1. Then when that library project is used in a parent project that doesn't define the repo that contains the jar in the library projects dependeny section, it fails to resolve the jar file from the library project when compile project(':libproject') is used. I have to duplicate the repo pointers in the parent's build.gradle file as well so that the libproject will build from the parent app. Any help on this one would be appreciated as well. As not every repo is used in every app so this can become redundant.
Ok this is a really old post, but still gets traction so let me update 3 years later since I originally wrote it lol.
Shout out to CommonWare who had the right best practice idea right from the start, but didn't provide an answer to mark up.
Let me start by saying that using project references like I was doing above should be limited to development stages only and should only be if the library project is also in development stage at the same time as the main project. Otherwise a dependency management server like Nexus, Apache Archiva, or S3 with Maven directory structure or equivalent would be preferred. I have learned many ways to manage dependencies since this, including transitive dependency management.
My preferred method is to deploy artifacts with POM files to Apache Archiva and then use these dependencies within the parent project instead of using relative paths to reference code projects now. This is the first choice.
However, if you are too new to dependency management and choose not to have a server for this purpose, you may package your AAR files or JAR files and put them in one centralized repo like artifact_repo and have everyone include that repo at the same folder structure and reference them relatively, but this is not good practice so I would steer clear if you can.
You can also take the artifacts and nest them in you libs directory and bring them in that way if you would like, but it becomes more of a manual update process which some people like and others do not.
Now this opens a whole different set of issues that you need to handle.
Transitive Dependencies and Child Repo pointers.
For example, if you wrapped your own Crash Reporting Library around Fabric or Hockey or other hoping to make it easy to trade libraries later, then you have found that the repo pointer has to live in the parent build.gradle files or the transitive dependencies are not found.
You could of course use one of those hacky Fat_AAR or Fat_JAR scripts that works "sometimes" until updated gradle then they break again until someone hacks it back together, but this is also poor practice as you are creating potential mismatch dependencies on support or other important child libraries and the "exclude transitives" only works if you are using pom files to control the transitives and not making the AAR or JAR file fat. So you are limiting your ability to control the dependencies.
So what i have finally come to terms with is that transitive dependencies should be managed through POM files to allow excluding or including without nesting into children libraries. Also libraries that require repo pointers inside of them, should probably not exist as they require parent boiler plate, introduce room for human error and typically don't save much time on wrapping analytics or crash libraries for example or you start getting into json configs that need to live in parent files for PUSH or other reasons. Just avoid it.
So long story short lol. Stick to dependency management tools they way they were intended to be used and you will be fine. It is when you are new to it or start getting hacky that you run into ugly code and ugly problems. Hope this encourages someone to do it the right way :)
One last thing :). I have recently started writing Gradle Plugins to manage my versions and dependencies as a separate file so that I can use intellisense to pull in dependencies and make sure all support, gms, and tool versions are the same across all projects. You can even copy down live templates with your plugin to enable intellisense for Gradle to work with your stuff. It's not too bad to do. Best of luck and happy Gradling :).

Categories

Resources