Set gradle.ext in settings.gradle.kts with Gradle Kotlin DSL - android

Here's code snippet from google/exoplayer - which is written in Groovy buildscript.
// settings.gradle
gradle.ext.exoplayerRoot = 'path/to/exoplayer'
gradle.ext.exoplayerModulePrefix = 'exoplayer-'
apply from: new File(gradle.ext.exoplayerRoot, 'core_settings.gradle')
How can I achieve this using Kotlin DSL?
I couldn't find any useful resources or documents. Any help would be appreciated.

Found a solution after digging a while.
In Groovy, there's dynamic implementation of traits - So even if class A does not implement interface B in the class definition, it may implement it later in the future.
I didn't see Gradle internals so I can't properly explain this, but it seems to work. Hope this helps.
if (gradle is ExtensionAware) {
val extension = gradle as ExtensionAware
extension.extra["exoplayerRoot"] = "path/to/exoplayer"
extension.extra["exoplayerModulePrefix"] = "exoplayer-"
apply(from = File(extension.extra["exoplayerRoot"].toString(), "core_settings.gradle"))
}
For those who uses ExoPlayer, I created an issue for requesting some documents for Kotlin DSL users.

Related

Android: Add maven-publish configuration in a separate kotlin dsl script

I've written a .gradle script named publish.gradle which configures publishing {} for releasing my artifact.
Why on a separate script? I have multiple modules and by doing this every releasable module simply defines some variables.
Module build.gradle.kts:
// Module's blah blah
apply(from = "../publish.gradle")
publish.gradle:
apply plugin: 'maven-publish'
publishing {
publications {
// configure release process
}
}
I've recently decided to migrate to Gradle Kotlin DSL. However, there's an issue:
Adding publication {} like this:
plugins {
`maven-publish`
}
publication {
}
Lead to this error:
Expression 'publishing' cannot be invoked as a function. The function 'invoke()' is not found
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val PluginDependenciesSpec.publishing: PluginDependencySpec defined in org.gradle.kotlin.ds
Which is summarized to
PluginDependenciesSpec is not present as a receiver
What is the difference?
TL; DR
I've added publishing {} config to a separate script which works when in .gradle groovy format but I can not convert to .gradle.kts kotlin format. The publishing is extension of PluginDependenciesSpec class which is not present in the script.
Here's what worked for me:
plugins {
id("maven-publish")
}
configure<PublishingExtension> {
publications.create<MavenPublication>("myPlugin") {
groupId = "com.myCompany.android"
artifactId = "MyPlugin"
version = "1.0.0"
pom.packaging = "jar"
artifact("$buildDir/libs/MyPlugin.jar")
}
repositories {
mavenLocal()
}
}
I understand where you're coming from, converting from groovy to kotlin script is not a simple one to one translation, and most of us, including myself, code by example. In other words, you just need to see a simple example and you can figure out the rest. This works great when examples are readily available. What you need to do when you don't find an example is to turn to the API document. For example, https://docs.gradle.org/current/dsl/org.gradle.api.publish.PublishingExtension.html shows you the available properties for the PublishingExtension and you can keep drilling in to see what properties you have at the next level. This is especially important when examples may be working with an older version and may no longer be applicable. I will say that it wasn't as obvious is that for accessing extensions in kotlin script, requires the configure block. That's a big difference, but I like that approach, because it makes it clearer what the extension properties are a part of. And by the way, kotlin wants double quote, single quotes are no longer acceptable.

Kotlin DSL add new sourceSet

On Gradle 6.1.1, how to go around adding sourceSets for android project?
The answer on other questions doesn't work anymore, getByName("name") returns error with SourceSet with name 'main' not found.
The official document said to use
sourceSets {
main {
java {
srcDir("thirdParty/src/main/java")
}
}
}
However, there are over 20 main that has to be imported and I'm not sure which one is correct.
I'm using gradle 6.5.1, however documentation suggest, that is should also work for you, try:
sourceSets {
named("main") {
java.srcDir("../buildSrc/src/main/java")
}
}
It's also works for build types (debug/release), flavours etc.
Reason for this is that groovy can somehow interpret itself and knows main etc., but on gradle kts, you have call it using named for already existing, or getByName, create etc. base on need.
Similiar situation is for implement and api in groovy you can just use implementationDebug to attach it only for debug version, but in kotlin dsl you have to call it as a string "implementationDebug", because there is no such function
----- PS -----
If named, getByName not works for you, then try to experiment with findByName and create

How to generate OpenAPI sources from gradle when building Android app

What I'm trying to achieve
I'm trying to generate my REST API client for Android using OpenAPI Generator from the build.gradle script. That way, I wouldn't have to run the generator command line every time the specs change. Ideally, this would be generated when I build/assemble my app, and the sources would end up in the java (generated) folder, where generated sources are then accessible from the code (this is what happens with the BuildConfig.java file for example).
What I've tried so far
Following this link from their official GitHub, here's the build.gradle file I ended up with:
apply plugin: 'com.android.application'
apply plugin: 'org.openapi.generator'
...
openApiValidate {
inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
recommend = true
}
openApiGenerate {
generatorName = "java"
inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
outputDir = "$buildDir/generated/openapi"
groupId = "$project.group"
id = "$project.name-openapi"
version = "$project.version"
apiPackage = "com.example.mypackage.api"
invokerPackage = "com.example.mypackage.invoker"
modelPackage = "com.example.mypackage.model"
configOptions = [
java8 : "true",
dateLibrary : "java8",
library : "retrofit2"
]
}
...
First, I've never managed to get the API generated with the build/assemble task, even when I tried adding:
compileJava.dependsOn tasks.openApiGenerate
or
assemble.dependsOn tasks.openApiGenerate
The only way I could generate the sources was by manually triggering the openApiGenerate task:
Then, when I do generate my sources this way, they end up in the build folder but aren't accessible from my code, and aren't visible in the java (generated) folder:
I then have to manually copy/paste the generated source files to my project sources in order to use the API.
Even though I'm able to work around these issues by adding manual procedures, it would be way more maintainable if the whole process was simply automatic. I was able to achieve a similar result with another tool, Protobuf. Indeed, my gradle task gets triggered every time I build the app, and the sources end up in the java (generated) folder, so I don't have to do any additional work. The task is much simpler though, so I assume the main work that I'm not able to replicate with OpenAPI Generator is handled by the Protobuf plugin itself.
You have to specify path to the generated sources as a custom source set for your Gradle module, which is app in this case, as described here – https://developer.android.com/studio/build/build-variants#configure-sourcesets. That way Gradle will treat your sources as accessible from your code.
Something like this:
android {
...
sourceSets {
main {
java.srcDirs = ['build/generated/openapi/src/main/java']
}
}
...
}
I solved the issue you described like this, I'm using gradle.kts however.
See my build.gradle.kts
plugins {
// Your other plugins
id("org.openapi.generator") version "5.3.0"
}
openApiGenerate {
generatorName.set("kotlin")
inputSpec.set("$rootDir/app/src/main/openapi/my-api.yaml")
outputDir.set("$buildDir/generated/api")
// Your other specification
}
application {
// Your other code
sourceSets {
main {
java {
// TODO: Set this path according to what was generated for you
srcDir("$buildDir/generated/api/src/main/kotlin")
}
}
}
}
tasks.compileKotlin {
dependsOn(tasks.openApiGenerate)
}
You need to build the application at least once for the IDE to detect the library (at least this is the case for me in Intellij)
Your build should automatically generate the open api classes , to refer the generated classes in your java project you should add the generated class path to your source directory like it was mentioned in the other answers
https://developer.android.com/studio/build/build-variants#configure-sourcesets
As far as the task dependency goes , in android tasks are generated after configuration thus for gradle to recognize the task , wrap it inside afterEvaluate block like
afterEvaluate {
tasks.compileDebugJavaWithJavac.dependsOn(tasks.openApiGenerate)
}
I had this issue, and this answer https://stackoverflow.com/a/55646891/14111809 led me to a more informative error:
error: incompatible types: Object cannot be converted to Annotation
#java.lang.Object()
Taking a look at the generated files that were causing this error, noticed:
import com.squareup.moshi.Json;
After including a Moshi in the app build.gradle, the build succeeded and the generated code was accessible.
implementation("com.squareup.moshi:moshi-kotlin:1.13.0")

How to configure Firebase Performance Monitoring plugin extension in Gradle Kotlin DSL

I have an Android app using Gradle with Kotlin DSL. I'm adding Firebase Performance Monitoring, but I would like for it to be enabled only for a specific build type.
I've been following the instructions provided at Firebase - Disable Firebase Performance Monitoring. Unfortunately the provided snippets are in Groovy.
I've tried to get a reference to the Firebase Performance Monitoring extension in my app level Gradle script by doing the following:
plugins {
...
id("com.google.firebase.firebase-perf")
kotlin("android")
kotlin("android.extensions")
kotlin("kapt")
}
buildTypes {
getByName(BuildTypes.DEBUG) {
configure<com.google.firebase.perf.plugin.FirebasePerfExtension> {
setInstrumentationEnabled(false)
}
}
...
}
...
dependencies {
val firebaseVersion = "17.2.1"
implementation("com.google.firebase:firebase-core:$firebaseVersion")
implementation("com.google.firebase:firebase-analytics:$firebaseVersion")
implementation("com.google.firebase:firebase-perf:19.0.5")
}
Android Studio doesn't see any problem in this and auto-completes FirebasePerfExtension.
Unfortunately upon running a Gradle sync I get the following:
Extension of type 'FirebasePerfExtension' does not exist.
Currently registered extension types: [ExtraPropertiesExtension, DefaultArtifactPublicationSet, ReportingExtension, SourceSetContainer, JavaPluginExtension, NamedDomainObjectContainer<BaseVariantOutput>, BaseAppModuleExtension, CrashlyticsExtension, KotlinAndroidProjectExtension, KotlinTestsRegistry, AndroidExtensionsExtension, KaptExtension]
There's no plugin extension related to Firebase Performance Monitoring.
This is in my project level build.gradle file dependencies block:
classpath("com.google.firebase:perf-plugin:1.3.1")
Any help is appreciated!
Update 1
As recommended on the Gradle - Migrating build logic from Groovy to Kotlin guide at "Knowing what plugin-provided extensions are available" I've ran the kotlinDslAccessorsReport task. None of the resulting extensions seems to be related to Firebase.
Had the same issue and was going to apply from groovy file, but seems i found the solution in here: https://docs.gradle.org/5.0/userguide/kotlin_dsl.html#sec:interoperability
withGroovyBuilder {
"FirebasePerformance" {
invokeMethod("setInstrumentationEnabled", false)
}
}
We used this answer, util we discovered a better working way in the team
check(this is ExtensionAware)
configure<com.google.firebase.perf.plugin.FirebasePerfExtension> { setInstrumentationEnabled(false) }

Cannot resolve symbol FirebaseVisionTextDetector

I get Cannot resolve symbol FirebaseVisionTextDetector error when I put in my module:
import com.google.firebase.ml.vision.text.FirebaseVisionTextDetector;
I can't understand why because in gradle I have the correct implementation:
implementation 'com.google.firebase:firebase-ml-vision:18.0.1'
SOLVED
I have solved by downgrading to 16.0.0. Still don't know the reason why.
implementation 'com.google.firebase:firebase-ml-vision:16.0.0'
Downgrade is not really a solution. There are many bug fixes and upgrades which you should ship with your app.
FirebaseVisionTextDetector class was removed in
firebase-ml-vision:17.0.0 , it was last available in firebase-ml-vision:16.0.0 they have changed it to FirebaseVisionTextRecognizer.
There are not much difference between both classes. So go ahead and do changes.
Changes to make:
Before (v-16.0.0):
FirebaseVisionTextDetector
FirebaseVisionTextDetector.detectInImage(image)
List<FirebaseVisionText.Block> resultsBlocks = results.getBlocks();
for (FirebaseVisionText.Block block : resultsBlocks) {
for (FirebaseVisionText.Line line : block.getLines()) {
//...
}
}
After (v-18.0.1):
FirebaseVisionTextRecognizer
FirebaseVisionTextDetector.processImage(image)
List<FirebaseVisionText.TextBlock> blocks = results.getTextBlocks();
for (FirebaseVisionText.TextBlock block : blocks) {
// ...
}
}
You can clone Official ML kit sample project to see complete code implementation.
Please check link for list of class and interface which ML kit provide in vision.text package. so I guess you need to take help from FirebaseVisionTextRecognizer class.
Here is the example how you can use 'FirebaseVisionTextRecognizer' class.

Categories

Resources