During migration build script from groovy to kotlin I met problem with excluding build variants.
In groovy it's pretty easy:
android {
variantFilter { variant ->
if (variant.name == "lorempisum") {
setIgnore(true)
}
}
}
but in kotlin similar thing does not work. It seems to be ok in android studio, but during compilation it throws Unresolved reference: isIgnore
android {
variantFilter {
if (buildType.name == "lorempisum") {
isIgnore = true
}
}
}
from the other side this reports Unresolved reference: setIgnore, but works during compilation
android {
variantFilter {
if (buildType.name == "lorempisum") {
this.setIgnore(true)
}
}
}
Anybody has idea how do it in right way?
I'm using kotlin 1.3.72, android studio 4.0.1 and gradle 6.5.1
---- EDIT ----
I fix example ignore -> isIgnore in second block, it also not works
Soultion is ignore = true with a little deatil.
This works if you keep in top-level build.gradle.kts this line:
classpath("com.android.tools.build:gradle:4.0.1")
and not really only on buildSrc on this:
implementation("com.android.tools.build:gradle:4.0.1")
Use the beforeVariants block:
androidComponents {
beforeVariants { variantBuilder ->
// To check for a certain build type, use variantBuilder.buildType == "<buildType>"
if (variantBuilder.productFlavors.containsAll(listOf("api" to "minApi21", "mode" to "demo"))) {
// Gradle ignores any variants that satisfy the conditions above.
variantBuilder.enabled = false
}
}
}
You should first update to the last version of android studio and the plugins.
And try this
variantFilter {
this.ignore = name == "lorempisum"
}
Related
I'm trying to build my android application which contains two libraries. In one library, a newer version of ffmpeg is being used. In another library, a dependency of that library is using an older version of ffmpeg. Trying to use pickFirst in the package options picks the WRONG libary. Is there ANY possible way to fix this, or is this just a limitation of Gradle?
Here is the error I am getting
Execution failed for task ':app:mergeDebugNativeLibs'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.MergeNativeLibsTask$MergeNativeLibsTaskWorkAction
> 2 files found with path 'lib/arm64-v8a/libavcodec.so' from inputs:
I was actually able to solve this issue myself.
Essentially, what I needed to do was to add a task to my gradle file that would intercept the merge libs task before it runs and delete the unwanted libraries:
tasks.whenTaskAdded((tas -> {
if (tas.name.contains("mergeDebugNativeLibs")) {
tasks.named("mergeDebugNativeLibs") {it
doFirst {
java.nio.file.Path notNeededDirectory = it.externalLibNativeLibs
.getFiles()
.stream()
.filter(file -> file.toString().contains("Metadata"))
.findAny()
.orElse(null)
.toPath();
Files.walk(notNeededDirectory).forEach(file -> {
if (file.toString().contains("libav") || file.toString().contains("libsw")) {
Files.delete(file);
}
});
}
}
}
if (tas.name.contains("mergeReleaseNativeLibs")) {
tasks.named("mergeReleaseNativeLibs") {it
doFirst {
java.nio.file.Path notNeededDirectory = it.externalLibNativeLibs
.getFiles()
.stream()
.filter(file -> file.toString().contains("Metadata"))
.findAny()
.orElse(null)
.toPath();
Files.walk(notNeededDirectory).forEach(file -> {
if (file.toString().contains("libav") || file.toString().contains("libsw")) {
Files.delete(file);
}
});
}
}
}
}))
In this case, the unwanted libraries are in the FFmpegMetadataMediaRetriever folder/library.
You can exclude the library from the dependency that has the "wrong" version.
dependencies {
implementation("some-library") {
exclude(group = "com.example.imgtools", module = "native")
}
}
I am trying to use Android logs in my shared code so wanted to make use of the 'expected/actual' functionality in order to make the android side use logs to be read in log cat. However I cannot get the android module(not app module) to import the android.util.Log.
I have seen this answer but it did not work for me. I cannot get the import to resolve.
I think I need to implement a specific dependency in order to have access to the import but I'm not sure what that is.
Here is my build.gradle.kts
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
kotlin("multiplatform")
}
kotlin {
//select iOS target platform depending on the Xcode environment variables
val iOSTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget =
if (System.getenv("SDK_NAME")?.startsWith("iphoneos") == true)
::iosArm64
else
::iosX64
iOSTarget("ios") {
binaries {
framework {
baseName = "SharedCode"
}
}
}
jvm("android")
sourceSets["commonMain"].dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-common")
implementation("io.ktor:ktor-client:1.0.0-beta-3")
implementation ("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.3.2")
// implementation ("org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:0.14.0")
}
sourceSets["androidMain"].dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib") //Allows _androidMain to have java imports
implementation("io.ktor:ktor-client-android:1.0.0-beta-3")
api("org.jetbrains.kotlin:kotlin-stdlib:1.3.61")
api("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61")
}
}
val packForXcode by tasks.creating(Sync::class) {
val targetDir = File(buildDir, "xcode-frameworks")
/// selecting the right configuration for the iOS
/// framework depending on the environment
/// variables set by Xcode build
val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
val framework = kotlin.targets
.getByName<KotlinNativeTarget>("ios")
.binaries.getFramework(mode)
inputs.property("mode", mode)
dependsOn(framework.linkTask)
from({ framework.outputDirectory })
into(targetDir)
/// generate a helpful ./gradlew wrapper with embedded Java path
doLast {
val gradlew = File(targetDir, "gradlew")
gradlew.writeText("#!/bin/bash\n"
+ "export 'JAVA_HOME=${System.getProperty("java.home")}'\n"
+ "cd '${rootProject.rootDir}'\n"
+ "./gradlew \$#\n")
gradlew.setExecutable(true)
}
}
tasks.getByName("build").dependsOn(packForXcode)
Here you got JVM target with the name "android" instead of actually Android target. The same problem occurred in the linked question. Can you tell, what's going on when you use the script from the answer? It seems like that one should work correctly.
As described in the documentation, one has to use an Android-specific Gradle plugin to make the Android target available. If you want to see how it can be done, consider having a look at this sample.
I had the same problem. Try using android() instead of only the jvm("android").
Also I've added my dependencies to android with android.sourceSets.foreach{ _ ->
dependencies{ ... }
}
Just fixed same issue, finally used this tutorial https://medium.com/icerock/how-to-start-use-kotlin-multiplatform-for-mobile-development-1d3022742178
so my build.gradle looks like:
apply plugin: 'com.android.library'
apply plugin: 'org.jetbrains.kotlin.multiplatform'
android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 14
targetSdkVersion 29
}
}
kotlin {
targets {
android()
iosArm64()
iosX64()
}
sourceSets {
commonMain {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version"
}
}
androidMain {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
}
}
}
To disable generating BuildConfig with the Groovy DSL, one could do the following:
afterEvaluate {
generateReleaseBuildConfig.enabled = false
generateDebugBuildConfig.enabled = false
}
I am trying to find the equivalent when using Gradle's Kotlin DSL (build.gradle.kts). Anyone have any luck with this?
If you have Android Studio 4.1 or greater you can use the Build Features Field to disable it per module.
android {
...
buildFeatures {
buildConfig = false
resValues = false
}
}
I ended up finding this to work as well:
android { ... }
tasks.withType<GenerateBuildConfig> {
isEnabled = false
}
You can remove BuildConfig from all variants by adding the following:
For library
android {
...
// TODO replace with https://issuetracker.google.com/issues/72050365 once released.
libraryVariants.all {
generateBuildConfigProvider?.get()?.enabled = false
}
}
For application
android {
...
// TODO replace with https://issuetracker.google.com/issues/72050365 once released.
applicationVariants.all {
generateBuildConfigProvider?.get()?.enabled = false
}
}
If you want to specify a build type , then:
libraryVariants
.matching { it.buildType.name == "release"}
.all {
generateBuildConfigProvider?.get()?.enabled = false
}
}
Here is my build.gradle.kts :
import org.jetbrains.kotlin.config.KotlinCompilerVersion
plugins {
...
}
android {
compileSdkVersion(27)
defaultConfig {
...
}
buildTypes {
...
}
sourceSets {
getByName("main").java.srcDirs("src/main/java", "src/main/kotlin")
getByName("test").java.srcDirs("src/test/java", "src/test/kotlin")
getByName("androidTest").java.srcDirs("src/androidTest/java", "src/androidTest/kotlin")
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
dependencies {
implementation(kotlin("stdlib-jdk7", KotlinCompilerVersion.VERSION))
implementation("com.android.support:appcompat-v7:27.1.1")
...
//Test
testImplementation("org.junit.jupiter:junit-jupiter-api:5.1.1")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.1.1")
androidTestImplementation("com.android.support.test:runner:1.0.2")
androidTestImplementation("com.android.support.test.espresso:espresso-core:3.0.2")
androidTestImplementation("android.arch.core:core-testing:1.1.1")
testImplementation("io.kotlintest:kotlintest-runner-junit5:3.1.10")
testImplementation("io.mockk:mockk:1.8.7")
}
When building it with ./gradlew build no error occurs but if I use the specified codefrom the doc :
val test by tasks.getting(Test::class) {
useJUnitPlatform { }
}
I get the following error : Task with name 'test' not found in project ':app'.
My settings.gradle.kts:
include(":app")
Does anyone know what's going on here? It's weird AS can suggest me autocompletion and all but while compiling, I get this unresolved reference.
Looks like your issue is with this block,
tasks.withType<Test> {
useJUnitPlatform()
}
If you're not using test task then you can simply remove that
code and that error will be gone !
Edit:
If you want to use test task. try like this in project level build.gradle,
tasks.register("test", Test::class) {
useJUnitPlatform()
}
My Question is very direct and easy to understand.
Question
In Gradle, is there any way I can get the current build type at runtime. For example, when running an assembleDebug task, can tasks within the build.gradle file make decisions based on the fact that this task is related to the debug build variant?
Sample Code
apply plugin: 'com.android.library'
ext.buildInProgress = ""
buildscript {
repositories {
maven {
url = url_here
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}
configurations {
//get current build in progress here e.g buildInProgress = this.getBuildType()
}
android {
//Android build settings here
}
buildTypes {
release {
//release type details here
}
debug {
//debug type details here
}
anotherBuildType{
//another build type details here
}
}
}
dependencies {
//dependency list here
}
repositories{
maven(url=url2_here)
}
task myTask{
if(buildInProgress=='release'){
//do something this way
}
else if(buildInProgress=='debug'){
//do something this way
}
else if(buildInProgress=='anotherBuildType'){
//do it another way
}
}
In Summary
Is there a way for me to get exactly the build type in progress within myTask{}?
You can get the exact build type by parsing your applicationVariants:
applicationVariants.all { variant ->
buildType = variant.buildType.name // sets the current build type
}
A implementation could look like the following:
def buildType // Your variable
android {
applicationVariants.all { variant ->
buildType = variant.buildType.name // Sets the current build type
}
}
task myTask{
// Compare buildType here
}
Also you can check this and this similar answers.
Update
This answer by this question helped the questioner to settle the problem.
This worked for me
applicationVariants.all { variant ->
def variantType = variant.buildType.name
println "Variant type: $variantType"
if (variantType == "debug") {
// do stuff
}
}
You should getBuildConfigFields().get("MY_BUILD_TYPE").getValue())
https://stackoverflow.com/a/59994937/5279996
GL
If you want to suffix the buildtype name to the versionname (like me) just add this line to the version name:
debug {
versionNameSuffix "-debug"
}
This way you can identify the build type in the build name. And it works without declaring anything else.
Correct way for getting the current buildType being used during build in Kotlin programming language for android platform (logic is the same for Java)
project.afterEvaluate {
this.android().variants().all {
this.assembleProvider.configure {
this.doLast{
val variant = this#all
variant.outputs
.map
.forEach{
//do something with current buildType, or build flavor or whatever
println(variant.flavorName)
println(variant.buildType)
}
}
}
}
}
I'm getting build type in this way:
BuildConfig.BUILD_TYPE
If you need to check what is the current build type, create an enum class in your utils package and use it in your if statement:
enum class Environment(val value: String) {
RELEASE("release"),
LOCAL("local"),
STAGING("staging"),
DEBUG("debug")
}
Your if/when statement:
if (BuildConfig.BUILD_TYPE == Environment.RELEASE.value) {
//TODO
} else if(...)
or through when:
when(BuildConfig.BUILD_TYPE) {
Environment.RELEASE.value -> { //TODO }
Environment.LOCAL.value -> { // TODO }
// etc.
}
I checked other answers, nothing works.
What's below will help.
In your build.gradle (:app):
tasks.all { Task task ->
if (task.name == "preDebugBuild") {
doFirst {
//for debug build
}
} else if (task.name == "preReleaseBuild") {
doFirst {
//for release build
}
}
}
dependencies {
...
}
Be aware, the code that you put inside will not be executed when you change the build variant, but when you build app.
Try like this in your gradle : It works fine for me
//get current build all params as string
def buildParams = getGradle().getStartParameter().toString().toLowerCase();
applicationVariants.all { variant ->
variant.outputs.all {
def typename = variant.buildType.name.toLowerCase();
//and check build state in all variants
if(buildParams.contains(typename)) {
// finally, you get what you want.
}
}
}
You can get the exact build type by parsing your applicationVariants:
applicationVariants.all { variant ->
buildType = variant.buildType.name // sets the current build type
}
Here's the approach I used to detect the runtime build type without declaring any variables at build time.
def isCurrentBuildType(buildType) {
return gradle.getStartParameter().taskNames.find({ it.endsWith(buildType) }) != null
}
print(isCurrentBuildType("Release")) //prints true if the current build type is release.
Note that the first letter should be capital (e.g. assembleRelease, bundleRelease)