I am in the process of migrating buildSrc convention plugins into standalone plugins. There are a lot of examples for creating Gradle plugins for Project objects, but a real dearth for Settings and Gradle. I want to centralize the list of repositories that we use in our gradle.settings.kts files, so I've created a Gradle Settings plugin: RepositoriesPlugin.
It is implemented in the same manner at a Project plugin, however, I am unsure about how to interpret the following quote from Gradle's docs: "A plugin can instead receive a parameter of type Settings, in which case the plugin can be applied in a settings script.", as stated in the documentation at this link: Gradle 7.2 Doc
The following example shows how I've applied my settings plugin in a settings.gradle.kts file. Is this how a settings plugin is applied, as per the documentation?
I've included the basic settings plugin code, below, too.
I'd appreciate your help to clarify that I am doing this properly. I am sure that this posting will help others who stray away from just Project plugins.
Thanks for your time and interest..
// settings.gradle.kts
pluginManagement {
plugins {
id("com.abitofhelp.gradle.plugins.repositoriesplugin") version "1.0.0-1"
}
settings.extensions
getByType(RepositoriesPluginExtension::class).apply {
localRepoName = "local-repo"
localRepositoryPath = "../../local-repo"
}
// Set the plugin repositories for all projects.
//repositories {
// maven { name = "localRepo"; url = uri(file("./local-repo")) }
// gradlePluginPortal()
// mavenCentral()
//}
}
// repositoriesplugin.kt
open class RepositoriesPlugin: Plugin<Settings> {
override fun apply(settings: Settings) {
val extension: RepositoriesPluginExtension =
settings.extensions.create("repositoriesPlugin", RepositoriesPluginExtension::class.java)
val localRepositoryName = extension.localRepositoryName?.let { it }?: "../../localRepo"
val localRepositoryPath = extension.localRepositoryPath?.let { it }?: "../../local-repo"
settings.pluginManagement.repositories.apply {
// Set the PLUGIN REPOSITORIES for all subprojects.
maven { repository ->
repository.name = localRepositoryName
repository.url = URI.create(localRepositoryPath)
}
gradlePluginPortal()
mavenCentral()
}
settings.dependencyResolutionManagement.repositories.apply {
// Set the DEPENDENCY REPOSITORIES for all subprojects.
maven {
it.name = localRepositoryName
it.url = URI.create(localRepositoryPath)
}
mavenCentral()
gradlePluginPortal()
}
}
}
I just had to figure this out myself. You weren't far off with your initial attempt but the plugins block actually has to go after the pluginManagement block. The basic layout of my working implementation looks like this:
// settings.gradle.kts
rootProject.name = "myProject"
pluginManagement {
repositories {
maven {
url = uri("/tmp/maven-local")
gradlePluginPortal()
}
}
}
plugins {
id("com.example.my-plugin") version "1.0-SNAPSHOT"
}
I believe you need to add the plugin to settings.gradle classpath via buildscript closure. pluginManagement.plugins makes the plugin availabile to the root (& sub) project build.gradle classpath, but I think that is a different classpath from the settings.gradle script.
To add to settings gradle, give this a try:
// settings.gradle
buildscript {
repositories {
maven { url "http://repo.where.plugin.is.published" }
}
classpath("complete.maven.coordinates:your-settings-plugin:version")
}
pluginManager.apply(your.settings.plugin.id)
As Justin Warkentin already noted, you first need to add your repo in the pluginManagement section and then you can apply your plugin like any other.
If you want to bypass the repository, you can also add the plugin project as composite build via includeBuild in the pluginManagement section.
In my example I have combined both methods. If the plugin project exists locally, this one is used, otherwise the version from the repo is used. This way you can (temporarily) add your plugin project to develop on it and test it directly in including projects.
pluginManagement {
repositories {
// your plugin repo; maybe...
mavenLocal()
}
// use local copy of your plugin if available,
// otherwise load plugin from repo
def name = 'your_plugin_project'
if (file(name).isDirectory()) {
includeBuild(name)
}
}
plugins {
// apply your plugin
id 'your.plugin.id'
}
Related
I have recently updated my Android Studio to latest version. But the gradle file here seems bit different.
here is the gradle code :
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.3.1' apply false
id 'com.android.library' version '7.3.1' apply false
id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
}
I want to add these below jitsi lines in the project gradle file. how should I paste it so that it syncs properly without any errors.
here is the jitsi code :
allprojects {
repositories {
maven {
url "https://github.com/jitsi/jitsi-maven-repository/raw/master/releases"
}
google()
mavenCentral()
maven { url 'https://www.jitpack.io' }
}
}
I have tried changing the gradle file by adding or replacing the above lines, Nothing changes. It is throwing an error.
As you appear to be using the recently revised build configuration scripts, you should be able to declare your repositories under the settings.gradle file:
pluginManagement {
// Plugin repositories go here
}
// ...
dependencyResolutionManagement {
/**
* The dependencyResolutionManagement {repositories {...}}
* block is where you configure the repositories and dependencies used by
* all modules in your project, such as libraries that you are using to
* create your application. However, you should configure module-specific
* dependencies in each module-level build.gradle file. For new projects,
* Android Studio includes Google's Maven repository and the Maven Central
* Repository by default, but it does not configure any dependencies (unless
* you select a template that requires some).
*/
// The following line makes it so that project modules (such as your
// "app" module) can't declare their own repositories {} block
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
// Add your repositories here...
maven {
url "https://github.com/jitsi/jitsi-maven-repository/raw/master/releases"
}
maven { url 'https://www.jitpack.io' }
}
}
only buildscript {}, pluginManagement {} and other plugins {} script blocks are allowed before plugins {} blocks, no other statements are allowed
As for this error, this is because plugins blocks are always resolved first, and so any other code must be declared after that block:
// There shouldn't be any code before this!
plugins {
}
// Okay to have build script code here...
Android studio latest version you move the jitsi repository in the project's settings.gradle file
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
mavenLocal()
}
}
I'm trying to develop a gradle plugin to use it for generating some objects and methods for our api using some scheme.
I have followed some tutorials but they all seem not to work, atleast for me.
Some of these tutorials were:
https://musings.animus.design/kotlin-poet-building-a-gradle-plugin/
https://medium.com/#magicbluepenguin/how-to-create-your-first-custom-gradle-plugin-efc1333d4419
I have not used the buildSrc module because I'm already using it for Kotlin DSL, so I decided to create a new module and create my plugin there.
My plugin's module build.gradle.kts looks like this:
plugins {
id("java-gradle-plugin")
id("kotlin")
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath(config.ClassPaths.androidBuildTools)
classpath(config.ClassPaths.kotlinGradlePlugin)
}
}
repositories {
google()
jcenter()
}
dependencies {
implementation(config.ClassPaths.androidBuildTools)
implementation(config.ClassPaths.kotlinGradlePlugin)
}
gradlePlugin {
plugins {
create("Generator") {
id = "Generator"
implementationClass = "Generator"
}
}
}
My projects settings.gradle.kts looks like this:
include(":SampleProject", ":scheme-generator")
And in my application module's build.gradle.kts I'm applying this plugin like this:
apply(plugin = "Generator")
The build script stops here with an error: plugin 'Generator' not found
My Generator class looks like this:
class Generator : Plugin<Project> {
override fun apply(target: Project) {
target.android().variants().all { variant ->
// Make a task for each combination of build type and product flavor
val myTask = "myFirstTask${variant.name.capitalize()}"
// Register a simple task as a lambda. We can later move this to its own
// class to make our code cleaner and also add some niceties.
target.tasks.create(myTask){task ->
// Group all our plugin's tasks together
task.group = "MyPluginTasks"
task.doLast {
File("${target.projectDir.path}/myFirstGeneratedFile.txt").apply {
writeText("Hello Gradle!\nPrinted at: ${SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(Date())}")
}
}
}
}
}
}
The android and variants methods are declared in a utils file, they look like this:
object GeneratorUtils {
fun Project.android(): BaseExtension {
val android = project.extensions.findByType(BaseExtension::class.java)
if (android != null) {
return android
} else {
throw GradleException("Project $name is not an Android project")
}
}
fun BaseExtension.variants(): DomainObjectSet<out BaseVariant> {
return when (this) {
is AppExtension -> {
applicationVariants
}
is LibraryExtension -> {
libraryVariants
}
else -> throw GradleException("Unsupported BaseExtension type!")
}
}
}
I have tried many things, but I seem not to get this right.
EDIT:
Using the buildSrc module for my plugin works totally fine, the plugin is applied and the gradle tasks are visible. However, buildSrc is reserved for other purposes, and we would like our plugin to be in a separate module, so we will be able to use it in other projects.
EDIT 13/04/2021
I have managed to see the tasks that are added by my plugin in my app tasks list by including this module as a composite build.
My settings.gradle now looks like this:
pluginManagement {
includeBuild("generator")
}
include(":SampleProject")
build.gradle of my plugin looks like this:
apply plugin: 'java-gradle-plugin' // Allows us to create and configure custom plugins
apply plugin: 'kotlin' //Needed as we'll write our plugin in Kotlin
buildscript {
ext {
kotlin_version = '1.4.31'
gradle_version = '4.1.2'
}
repositories {
google()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.android.tools.build:gradle:$gradle_version"
}
}
repositories {
google()
jcenter()
}
dependencies {
// Android gradle plugin will allow us to access Android specific features
}
gradlePlugin {
plugins {
create("Generator") {
id = "Generator"
implementationClass = "com.example.Generator"
}
}
}
And my generator class now looks like this:
class Generator : Plugin<Project> {
override fun apply(project: Project) {
project.tasks.register("generationTask") { task ->
task.apply {
group = "generation"
actions.add(Action {
print("Hello from generation task!")
})
}
}
}
}
I can see generationTask in my tasks list and I can execute it normally. It prints the text without any problems.
The problem now is to include com.android.tools.build:gradle:4.1.2 in my dependecies to use it to access build types and flavors and their paths to save my generated code there. When I add it to my dependencies block, gradle fails with this error: Could not find com.android.tools.build:gradle:4.1.2.
How can I solve this problem?
Gradle build goes through specific set of phases, and the Configuration phase comes before the Execution phase. So you cannot use a plugin, which is built in the same build process, because by the time gradle tries to use it on Configuration phase, the plugin has not been built yet.
buildSrc directory is a special one, it's built not as part of the same build process, but in a separate build, before the main build process starts. This feature is called included or composite build. buildSrc is just a pre-defined way to set up a composite build and you can define your own included builds. So to make your plugin visible to the main build, you need to put it into a separate build and include this build into a composite build as described in the doc above. Here is an article describing how to transform a plugin defined in buildSrc into a composite build.
I have a sdk and a client app. The client app is using the sdk. When I build the sdk, it generates multiple aar files which I can add it in libs folder in my client project.
Now if I modify the sdk, every time I need to build the sdk code using gradlew and then add the aar in client code. This is becoming a lengthy process.
My top level build.gradle file looks like below:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.3'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.2'
classpath 'com.google.gms:google-services:3.1.1'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
Is there a way to link the sdk code with client code. So the sdk changes will be automatically picked by the client code. I am using Android Studio 3.6.
Thanks,
Arindam.
you can use the maven, or maven-publish to publish to your own maven repositories, it can be local. the config like that in build.gradle
uploadArchives {
repositories {
configuration = configurations.archives
mavenDeployer {
// the local repo address
repository(url: uri('../repo'))
pom.project {
version '1.0.1'
artifactId 'artifactId'
groupId 'groupId'
packaging 'aar'
description 'version 1.0.1'
}
}
}
}
then add this repository in project build.gradle
maven {
url "file://Users.../yourProject/repo/"
}
after that, you can use that as the third library. after you change it, you only need to execute it, then build the current project.
if you also want to look at the source code about SDK in the current project.
you can change to use maven-publish plugin.
I uploaded my lib to bintray to the custom private repo (myRepoName), then tried to use it in another project.
But I need to upload it somehow to dsl methods, otherwise it says Gradle method not found myRepoName
How to do it?
buildscript {
repositories {
myRepoName { url "https://bintray.com/myRepo/sdk/repo" }
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
}
}
At the moment you are using a custom name for the repository you are declaring. Instead you will have to call an existing method on RepositoryHandler, the underlying domain object for the repositories method. To fix the error message, you will have to use the method maven for a Maven-based repository.
buildscript {
repositories {
maven {
name 'myRepoName'
url 'https://bintray.com/myRepo/sdk/repo'
}
}
}
Please also keep in mind that there's a difference between the repositories you define within the buildscript block and for repositories defined on the top-level of the build script. Please refer to the Gradle user guide for more information.
What is the preferred way to share some code (E.g. a Utils class) between two projects when building two apps using Gradle to build?
Can I do this without creating extra jar files? I just want my code to sit outside the app projects, be imported/compiled into both app projects. Or is this simply not possible?
I'm familiar with the approach that uses jars or Android library projects, but both seem a bit unwieldy.
My favorite way of doing this is by keeping it in a local Maven repo. The repo can even live in your SCM so it's the same across workspaces.
Create a new Android Studio project and then set it as a maven project your build.gradle config:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
apply plugin: 'android-library'
apply plugin: 'maven'
repositories {
mavenCentral()
}
configurations {
archives {
extendsFrom configurations.default
}
}
group = 'com.mypackage.mylibrary'
version = '1.0.0'
uploadArchives {
configuration = configurations.archives
repositories {
mavenDeployer {
repository(url: uri("relative/path/to/localrepo"))
pom.project {
artifactId 'mylibrary'
name 'My Library'
packaging 'aar'
}
}
}
}
android {
// copy old android config here
}
You'll need to deploy the library before you can use it. Do this by using the uploadArchives task [./gradlew uploadArchives]
Now you should be able to use this library in any project by doing this:
repositories {
maven { url 'relative/path/to/localrepo' }
}
dependencies {
compile ('com.mypackage.mylibrary:1.0.0')
}
When you make changes to your library, you'll have to re-deploy (uploadArchives) with a new version, then update the dependency reference in whatever project needs the new version.