gradle withJavadocJar() and withSourcesJar() for android library - android

Is there a way to leverage the new functions withSourcesJar() and withJavadocJar() for Android library projects? Currently when I try to use it I get:
> SourceSet with name 'main' not found.

With the latest Gradle version 6.0.1, there seems to be no way to use these new methods in Android library projects. Here’s why I believe that’s the case:
The two methods withJavadocJar() and withSourcesJar() on the java extension have the default main source set hardcoded, see here and here.
There are two methods with the same names (withJavadocJar() and withSourcesJar()) which can be used in feature variant declarations. However, it seems that Android Gradle builds don’t use feature variants, i.e., these methods can’t be used either.

The documentation states, that these come from the JavaPluginExtension - but not from Android DSL. So they can only be used in conjunction with apply plugin: "java" or apply plugin: "java-library", but not with apply plugin: "com.android.application", apply plugin: "com.android.library" and alike. The name of these tasks also suggest that it's common Java (*.jar) and not Android (*.aar). On Android, this would only make sense for a *.jar library, which uses pure Java features, but no Android features at all (which is limited in functionality).
In short, apply plugin: "java-library" would permit accessing these.

With Gradle 7.2 I "recreated" withJavadocJar and withSourcesJar using Gradle Kotlin DSL:
val sourceFiles = android.sourceSets.getByName("main").java.getSourceFiles()
tasks.register<Javadoc>("withJavadoc") {
isFailOnError = false
dependsOn(tasks.named("compileDebugSources"), tasks.named("compileReleaseSources"))
// add Android runtime classpath
android.bootClasspath.forEach { classpath += project.fileTree(it) }
// add classpath for all dependencies
android.libraryVariants.forEach { variant ->
variant.javaCompileProvider.get().classpath.files.forEach { file ->
classpath += project.fileTree(file)
}
}
source = sourceFiles
}
tasks.register<Jar>("withJavadocJar") {
archiveClassifier.set("javadoc")
dependsOn(tasks.named("withJavadoc"))
val destination = tasks.named<Javadoc>("withJavadoc").get().destinationDir
from(destination)
}
tasks.register<Jar>("withSourcesJar") {
archiveClassifier.set("sources")
from(sourceFiles)
}
Put this into your gradle.build.kts file and then run ./gradlew withJavadocJar and ./gradlew withSourcesJar (or use the tasks to create artifacts for publishing).
android.sourceSets.getByName("main").java.getSourceFiles() is the Android specific part to retrieve the "main" source files.

Related

android.featureVariants get error: Properties not found when migrate from base-feature to dynamic-feature in Gradle

i'm using game engine (Cocos creator) and now I need migrate to Billing v4. When doing, I need support on old device that I need upgrade Gradle Plugin to version 4, then gradle need to migrate from base-feature to dynamic-feature to work, but have some problem need to resolve.
The original Gradle script:
android.featureVariants.all { variant ->
// delete previous files first
delete "${buildDir}/intermediates/merged_assets/"
variant.mergeAssets.doLast {
def sourceDir = "${buildDir}/../../../../.."
copy {
from "${sourceDir}"
include "assets/**"
include "src/**"
include "jsb-adapter/**"
into outputDir
}
copy {
from "${sourceDir}/main.js"
from "${sourceDir}/project.json"
into outputDir
}
}
}
How can I fix the error android.featureVariants properties not found
The build.gradle had migrated from base feature to dymanic feature by
Remove: apply plugin: 'com.android.feature' and change to apply plugin: 'com.android.dynamic-feature' and something at this guide: https://developer.android.com/topic/google-play-instant/feature-module-migration

Apply Kotlin multiplatform plugin via gradle legacy plugin application

I'm doing some in-depth hands-on with Kotlin Multiplatform Mobile and I'm forced to apply Gradle plugins with the legacy way of applying plugins.
I'm using Kotlin DSL for Gradle and I didn't manage to include the kotlin-multiplatform plugin.
Essentially, there are two ways to include a gradle plugin in your project:
via Gradle Plugins DSL (a modern way)
via legacy plugin application (deprecated but more flexible).
I've basically created a very blank gradle project (gradle init), not related to any IDE or any other dependencies, which both are common for KMM projects - to isolate the issue as much as possible.
The build.gradle.kts below works just fine, when run via ./gradlew clean build (via Plugins DSL)
plugins {
id("org.jetbrains.kotlin.multiplatform") version "1.4.10"
}
kotlin {
jvm()
}
repositories {
jcenter()
}
However, this won't work (via legacy plugin application):
buildscript {
repositories {
maven {
url = uri("https://plugins.gradle.org/m2/")
}
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10")
}
}
apply(plugin = "org.jetbrains.kotlin.multiplatform")
kotlin {
jvm()
}
repositories {
jcenter()
}
It fails with this error:
* What went wrong:
Script compilation errors:
Line 12: kotlin {
^ Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public fun DependencyHandler.kotlin(module: String, version: String? = ...): Any defined in org.gradle.kotlin.dsl
public fun PluginDependenciesSpec.kotlin(module: String): PluginDependencySpec defined in org.gradle.kotlin.dsl
Line 13: jvm()
^ Unresolved reference: jvm
2 errors
It can't resolve the kotlin {} block which is essentially the entry point in KMM projects.
Interestingly, using Groovy instead of Kotlin for Gradle - works in both cases.
But I would like to use Kotlin DSL for Gradle and apply the plugins via the legacy way, since this way I can apply plugins dynamically, i.e. under certain conditions.
In general, you can use apply false in the plugins DSL and call apply conditionally. Apply alone will NEVER work with Kotlin DSL, it only works with dynamic Groovy. Kotlin can work like Groovy if you also use the plugins DSL + apply false in it.
Example:
plugins {
kotlin("multiplatform") apply false // Applied conditionally later
}
For more detailed discussion of the problem check this.

SonarQube not finding Kotlin Junit5 tests

I'm trying to set up a sample android studio project in Github which integrates also its CI connected to SonarQube.
I'm having problems with sonarQube due to it says there is no test coverage applied. However there is, in kotlin and with Juni5, but there is no way to set sonar.tests for recognizing it.
this it the sonar-project.properties
test are run fine either locally and in the CI when a branch of the project is build.
Also I've added this
Gradle has been written with Kotlin-DSL.
if you are using gradle there is no need to define the sources and the tests in the sonar-project.properties. The gradle sonarqube task will pick them up automatically based on your sourcesets.
What i think you are missing is a tool to generate the coverage, sonarqube will not generate coverage data for you. SonarQube utilizes in Java eg. JaCoCo so you also need to apply a plugin for that.
so your build gradle (behold this is groovy dsl, but i will provide a link to one in kotlin) will look something like the following code snippet. This will generate everything automatically
plugins {
id 'java'
id 'jacoco'
id 'eclipse' // optional (to generate Eclipse project files)
id 'idea' // optional (to generate IntelliJ IDEA project files)
id "org.sonarqube" version "2.8"
}
repositories {
jcenter()
}
dependencies {
testImplementation('org.junit.jupiter:junit-jupiter:5.6.0')
}
test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}
sonarqube {
properties {
/*
UPDATE SECTION START
Please fill in your data
*/
property "sonar.projectName", "SonarCloud Github Actions with gradle"
property "sonar.projectKey", "aepfli_SonarCloud-GitHubActions-Gradle-example"
property "sonar.organization", "aepfli"
/*
UPDATE SECTION END
*/
property "sonar.host.url", "https://sonarcloud.io"
}
}
jacocoTestReport {
reports {
xml.enabled = true
}
}
Alternatively if you are looking for an example in kotlin DSL, i can recommend this one from JUnit Pioneer.
I am still not sure how good the support for kotlin is with JaCoCo. if there is a different tool like JaCoCo in the Kotlin world, you can also try to generate and XML report and provide this xml report via property sonar.coverage.jacoco.xmlReportPaths base on Sonarqube doc

Using Realm in a Cordova plugin for Android

I am experimenting with using Realm in place of SQLite in my hybrid Android/Cordova app which uses one custom - i.e. written by me - plugin. From the Realm documentation I have figured out that this has to be a two step process
Instructing Gradle to use the Realm plugin which I am doing via my plugin.xml file as io.realm:realm-gradle-plugin:6.0.2
"Applying the plugin" which according to the documentation involves issuing a apply plugin: 'realm-android' from the application levelbuild.gradle`file.
It is not clear to me how I do the latter. I tried putting the "apply plugin" statement in a build-extras.gradle file only to have Gradle complain
plugin with id 'realm-android' not found. Clearly, I am doing something wrong here. I'd be grateful to anyone who might be able to put me on the right path.
Sorry to destroy your delusions, but this assumption is just wrong:
Instructing Gradle to use the Realm plugin which I am doing via my plugin.xml file as io.realm:realm-gradle-plugin:6.0.2
I'd expect that to be required for the root project's build.gradle:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "io.realm:realm-gradle-plugin:6.0.2"
}
}
allprojects {
repositories {
jcenter()
}
}
As well as the module level build.gradle:
apply plugin: "realm-android"
...
dependencies {
// only this one line can be added through plugin.xml
implementation "io.realm:realm-android-library:6.0.2"
}
However, I think that Cordova by default only supports adding Java dependencies through plugin.xml, but no Gradle plugins - therefore you'd likely need to patch both build.gradle on demand, with a script similar to patchAndroidGradle.js, hooked into before_plugin_install. This obviously would then also need to be un-patched again, upon before_plugin_uninstall.
#MartinZeitler's answer is what put me on the right track here. For a Cordova project here is what you need to do:
Step 1
Open the platoforms/android/app/build.gradle file and in the dependencies{..} section add classpath "io.realm:realm-gradle-plugin:6.0.2".
Step 2
Now open the platforms\android\build-extras.gradle file - this is not created by default in Cordova so you might have to create a new one - and enter the following text
ext.postBuildExtras = {apply plugin: 'realm-android'}
Save the two files and perform a full rebuild of your project.
A few words of explanation are in order here. The mistake I had made was thinking that what was being supplied by Realm was a Java library. Not true. What you do in Realm is to model your data in the form of subclassed RealmObjects. Typically you will have multiple sub-classes of this type to fully define your data model. These sub-classes with their annotations are in effect instructions to Realm where you tell it how you are going to manage your data. As noted in the Realm docs
An annotation processor will create a proxy class for your RealmObject subclass.
The plugin you are incorporating into your project here is a Gradle plugin which extends the capabilities of Gradle. In this instance it is allowing the Realm annotation processor to examine your data model classes and create its own proxy classes. You can read up on how Gradle uses plugins here.
Add at the bottom :
apply plugin: 'realm-android' in the file build.gradle which is under the app folder of your project

gradle: set sonarRunner settings for projects applying specific plugin

We use a company-wide gradle configuration which is applied to all our gradle projects.
Projects using this config might apply different types of plugins (specificially the plugins java or android & android-library). In order to get the sonarRunner plugin to automatically check the android projects, additional properties have to be applied which are not available for java projects.
Now to the question: How can additional sonarRunner (or other) properties be applied only to projects applying a specific (in this case "android" or "android-library") plugin?
What I have tried so far, but does not work as the AndroidPlugin property is not know in the preparation phase:
plugins.withType(AndroidPlugin) {
sonarRunner {
sonarProperties {
property "sonar.profile", "Android"
...
}
}
}
Sounds like the code is missing an import for the AndroidPlugin class. Alternatively, plugins.withId("android") can be used for current gradle versions or afterEvaluate { if (plugins.hasPlugin("android")) { ... } } for gradle 1.12 and earlier.

Categories

Resources