I have many flavors in my app.gradle. When I exec gradlew assembleRelease I can find all flavors class in dir app/build/intermediates/classes. Now, I want to modify class(do my task) after class generated. How can I do that?
My task name is m.
gradle.projectsEvaluated {
def buildTypes = android.buildTypes.collect { type -> type.name }
def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
// When no product flavors defined, use empty
if (!productFlavors) {
productFlavors.add('')
}
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def flavorNameCapitalized = "${productFlavorName.capitalize()}"
def buildNameCapitalized = "${buildTypeName.capitalize()}"
def targetName = "${flavorNameCapitalized}${buildNameCapitalized}"
def preTaskName = "compile${targetName}JavaWithJavac"
def nextTaskName = "compile${targetName}Ndk"
if (!isDebug(buildNameCapitalized.toString())) {
project.tasks.findByName("generate${targetName}Sources").doLast { //generate${targetName}Sources
println("projectsEvaluated flavorName: " + flavorNameCapitalized.toString())
println("projectsEvaluated buildName: " + buildNameCapitalized.toString())
project.ext.set("flavorName", flavorNameCapitalized.toString());
project.ext.set("buildName", buildNameCapitalized.toString());
}
m.dependsOn project.tasks.findByName(preTaskName)
project.tasks.findByName(nextTaskName).dependsOn m
}
}
}
}
But my task only run once. Help
finally, I solved with dynamic task
String newTaskName = "${targetName}m";
task "$newTaskName"() << {
...
}
def newTask = project.tasks.findByName("$newTaskName")
newTask.dependsOn project.tasks.findByName(preTaskName)
project.tasks.findByName(nextTaskName).dependsOn newTaskName
Related
I want to create a script for publish a library on kotlin.
I am trying to convert this gradle config to gradle-kotlin (kts) following the gradle documentation (https://docs.gradle.org/current/userguide/publishing_maven.html#header) but I have this error when project builds:
FAILURE: Build failed with an exception.
Where:
Script '.../gradle-mvn-push.gradle.kts' line: 18
SourceSet with name 'main' not found.
Here is the script in kts:
Kotlin version : 1.6.10
Kotlin-gradle plugin version : 7.2.1
apply(plugin = "maven-publish")
var gitLabPrivateToken: String? = null
val secretPropertiesFile = rootProject.file("example.properties")
if (secretPropertiesFile.exists()) {
val secretProperties = java.util.Properties().apply {
load(java.io.FileInputStream(secretPropertiesFile))
}
gitLabPrivateToken = secretProperties["token"].toString()
}
val gitlabUrl = "exampleUrl"
lateinit var sourcesArtifact: PublishArtifact
tasks {
val sourcesJar by creating(Jar::class) {
archiveClassifier.set("sources")
from(project.the<SourceSetContainer>()["main"].allSource)
}
artifacts {
sourcesArtifact = add("archives", sourcesJar)
}
}
afterEvaluate {
configure<PublishingExtension> {
publications {
create<MavenPublication>("maven") {
artifact(sourcesArtifact) // Adds source as separate jar.
groupId = "com.example"
artifactId = "lib"
version = "0.1.0"
from(components["release"])
}
}
repositories {
maven {
name = "GitLabPersonal"
url = uri(gitlabUrl)
credentials(HttpHeaderCredentials::class) {
name = "Private-Token"
value = gitLabPrivateToken
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
maven {
name = "GitLabCi"
url = uri(gitlabUrl)
credentials(HttpHeaderCredentials::class) {
name = "Job-Token"
value = System.getenv("CI_JOB_TOKEN")
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}
}
I've tried converting our Android app to use the Kotlin DSL for gradle and I can't get AppDistribution to work in my CI build. This is the error I got:
App Distribution found more than 1 output file for this variant. Please contact firebase-support#google.com for help using APK splits with App Distribution.
This is what was working in groovy:
applicationVariants.all { variant ->
variant.outputs.each { output ->
tasks.findAll {
it.name.startsWith(
"appDistributionUpload${variant.name.capitalize()}")
}.each {
it.doFirst {
it.appDistributionProperties.apkPath = output.outputFile.absolutePath
}
}
}
}
I can't find a way to set appDistributionProperties.apkPath in the kotlin dsl:
applicationVariants.forEach { variant ->
variant.outputs.forEach { output ->
tasks.filter {
it.name.startsWith("appDistributionUpload${variant.name.capitalize()}")
}.forEach {
it.doFirst {
it.setProperty("apkPath", output.outputFile.absolutePath)
}
}
}
}
I'm guessing I need a magic string instead of just "apkPath", because there doesn't seem to exist a strongly typed way of saying this.
Kotlin dsl way:
android.applicationVariants.all {
this.outputs.all {
val output = this
tasks.matching {
it.name.startsWith(
"appDistributionUpload${this.name.capitalize()}"
)
}.forEach {
it.doFirst {
if (it is com.google.firebase.appdistribution.gradle.UploadDistributionTask) {
it.appDistributionProperties.get().apkPath = output.outputFile.absolutePath
}
}
}
}
}
I am trying to get https://github.com/Kotlin/kotlinx.serialization to work with my android library I am building using kotlin mpp. This is my gradle file
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.multiplatform")
kotlin("plugin.serialization") version "1.3.61"
}
group = "org.greeting"
version = 1.0
android {
compileSdkVersion(27)
defaultConfig {
minSdkVersion(15)
}
buildTypes {
getByName("release") {
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}
dependencies {
// Specify Kotlin/JVM stdlib dependency.
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7")
implementation(kotlin("stdlib", org.jetbrains.kotlin.config.KotlinCompilerVersion.VERSION)) // or "stdlib-jdk8"
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0") // JVM dependency
testImplementation("junit:junit:4.12")
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
androidTestImplementation("junit:junit:4.12")
androidTestImplementation("org.jetbrains.kotlin:kotlin-test")
androidTestImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}
kotlin {
android("androidLib")
val buildForDevice = project.findProperty("device") as? Boolean ?: false
val iosTarget = if (buildForDevice) iosArm64("ios") else iosX64("ios")
iosTarget.binaries {
framework {
// Disable bitcode embedding for the simulator build.
if (!buildForDevice) {
embedBitcode("disable")
}
}
}
sourceSets["androidLibMain"].dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0")
}
sourceSets {
commonMain {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-common")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:0.14.0")
}
}
commonTest {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-test-common")
implementation("org.jetbrains.kotlin:kotlin-test-annotations-common")
}
}
}
}
tasks.register("copyFramework") {
val buildType = project.findProperty("kotlin.build.type") as? String ?: "DEBUG"
dependsOn("link${buildType.toLowerCase().capitalize()}FrameworkIos")
doLast {
val srcFile = (kotlin.targets["ios"] as KotlinNativeTarget).binaries.getFramework(buildType).outputFile
val targetDir = project.property("configuration.build.dir")!!
copy {
from(srcFile.parent)
into(targetDir)
include("greeting.framework/**")
include("greeting.framework.dSYM")
}
}
}
tasks.register("iosTest") {
val device = project.findProperty("iosDevice") as? String ?: "iPhone 8"
dependsOn("linkDebugTestIos")
group = JavaBasePlugin.VERIFICATION_GROUP
description = "Runs tests for target 'ios' on an iOS simulator"
doLast {
val binary = (kotlin.targets["ios"] as KotlinNativeTarget).binaries.getTest("DEBUG").outputFile
exec {
commandLine("xcrun", "simctl", "spawn", "--standalone", device, binary.absolutePath)
}
}
}
When I try to run build i get Unresolved reference: serialization on line import kotlinx.serialization.ImplicitReflectionSerializer; But if compile the androidTests the linking works fine. Strangely i have to do sourceSets["androidLibMain"] and can't include it in the sourceSet{} block not sure if this is related. Any ideas on why the build task is not linking my serialization library? Thanks
I wrote a library with Kotlin MultiPlatform (link)
I can add the library as a jar file to the project
But now I want to do this with bintray
I went ahead with the Link, but I had a problem
My problem was that the value of publicationName variable I was giving Gradle was wrong for me :
val publicationName = "MySharedCode"
publishing {
publications.invoke {
publicationName(MavenPublication::class) {
artifactId = artifactID
artifact(shadowJar)
pom.addDependencies()
}
}
}
Gradle Sync Error : Publication with name 'MySharedCode' not found.
My Kotlin Gradle DSL File :
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.jfrog.bintray.gradle.BintrayExtension
import org.gradle.api.publish.maven.MavenPom
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("multiplatform")
`maven-publish`
id("com.jfrog.bintray") version "1.8.4"
id ("com.github.johnrengelman.shadow") version "5.2.0"
java
}
val ktorVersion = "1.3.0-rc2"
val serialization = "0.11.0"
val coroutines = "1.2.1"
project.group = "com.my.domain"
project.version = "0.0.3"
val artifactID = "my-shared-lib"
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 = "MySharedCode"
}
}
}
jvm("android")
sourceSets["commonMain"].dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-common")
// HTTP
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-json:$ktorVersion")
implementation("io.ktor:ktor-client-serialization:$ktorVersion")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutines")
}
sourceSets["androidMain"].dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
// HTTP
implementation("io.ktor:ktor-client-android:$ktorVersion")
implementation("io.ktor:ktor-client-json-jvm:$ktorVersion")
implementation("io.ktor:ktor-client-serialization-jvm:$ktorVersion")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines")
}
sourceSets["iosMain"].dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
// HTTP
implementation("io.ktor:ktor-client-ios:$ktorVersion")
implementation("io.ktor:ktor-client-json-native:$ktorVersion")
implementation("io.ktor:ktor-client-serialization-iosx64:$ktorVersion")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$coroutines")
}
}
val packForXcode by tasks.creating(Sync::class) {
group = "build"
val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
val framework = kotlin.targets.getByName<KotlinNativeTarget>("ios").binaries.getFramework(mode)
inputs.property("mode", mode)
dependsOn(framework.linkTask)
val targetDir = File(buildDir, "xcode-frameworks")
from({ framework.outputDirectory })
into(targetDir)
doLast {
val gradlew = File(targetDir, "gradlew")
gradlew.writeText("#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$#\n")
gradlew.setExecutable(true)
}
}
tasks.getByName("build").dependsOn(packForXcode)
val shadowJar: ShadowJar by tasks
shadowJar.apply {
baseName = artifactID
classifier = null
}
fun MavenPom.addDependencies() = withXml {
asNode().appendNode("dependencies").let { depNode ->
configurations.commonMainImplementation.allDependencies.forEach {
depNode.appendNode("dependency").apply {
appendNode("groupId", it.group)
appendNode("artifactId", it.name)
appendNode("version", it.version)
}
}
}
}
val publicationName = "MySharedCode"
publishing {
publications.invoke {
publicationName(MavenPublication::class) {
artifactId = artifactID
artifact(shadowJar)
pom.addDependencies()
}
}
}
fun findProperty(s: String) = project.findProperty(s) as String?
bintray {
user = "xxxx"
key = "xxxx"
publish = true
setPublications(publicationName)
pkg(delegateClosureOf<BintrayExtension.PackageConfig> {
repo = "lib"
name = "my repo name"
userOrg = "my user org"
websiteUrl = "https://my-domain.com/"
githubRepo = "myRepo"
vcsUrl = "myRepo url"
description = "my repo description"
setLabels("kotlin")
setLicenses("MIT")
desc = description
})
}
tasks {
withType(GradleBuild::class.java) {
dependsOn(shadowJar)
}
withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
withType(Test::class.java) {
testLogging.showStandardStreams = true
}
withType<GenerateMavenPom> {
destination = file("$buildDir/libs/${shadowJar.name}.pom")
}
}
You should create a gradle script for publishing mechanism by bintray and apply that into build.gradle.kts of MMP project scope.
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.multiplatform")
}
apply(from = rootProject.file("publishSystem/publish.gradle"))
//
//
//
//
In the following put that it publishLibraryVariants in android extension into kotlin extension
kotlin {
android { publishLibraryVariants("release") }
//
//
//
//
}
This my first time seeing the "bintray" in Kotlin DSL.
But as per their documentation
bintray {
user = "xxxx"
key = "xxxx"
publish = true
publications = [publicationName] // this is an array
pkg {
repo = "lib"
name = "my repo name"
vcsUrl = "myRepo url"
licenses = ["MIT"]
version {
name = "1.0.0"
desc = "Release one Woraay ^_^"
released = new Date()
}
}
}
Personally, I'm using something else on my end. Why don't you try this one out?
publishing {
repositories.maven("https://api.bintray.com/maven/THE REST OF THE URL;publish=1") {
name = "bintray"
credentials {
username = "ADMIN"
password = "ADMIN"
}
}
publications {
register("plugin", MavenPublication::class) {
groupId = "com.example.MySharedCode"
artifactId = "MySharedCode"
version = "1.0.0"
from(components["java"])
}
}
}
gradlePlugin {
plugins {
create("Gradle-Plugin") {
this.id = "com.example.MySharedCode"
this.implementationClass = "com.example.MySharedCode.gradle.MainClassNameHere"
}
}
}
I want to split my project to multiple sourceSets, so I want use multiple AndroidManifest.xml to declare current sourceSets's component,util build apk merge the main AndroidManifest.xml, but there only support one main AndroidManifest.xml setup, so how can I do it?
Why I want to use multiple sourceSets? Because if using multiple modules it compile so slow.
This is my project settings
def moduleDirs = project.projectDir.listFiles()
.findAll {
def name = it.name
// filter all inner's module
it.isDirectory() && msExtension.modulePrefix.any { name.startsWith(it) }
}
Set<File> manifestSet = new HashSet<>()
Set<String> modules = new HashSet<>()
def sourceSetConf = { AndroidSourceSet sourceSet ->
moduleDirs.each {
def moduleName = it.name
def dir = sourceSet.name
sourceSet.assets.srcDirs "${moduleName}/src/${dir}/assets"
sourceSet.java.srcDirs "${moduleName}/src/${dir}/java"
sourceSet.res.srcDirs "${moduleName}/src/${dir}/res"
sourceSet.aidl.srcDirs "${moduleName}/src/${dir}/aidl"
// each AndroidManifest.xml
def manifestFile = project.file("${moduleName}/AndroidManifest.xml")
if (manifestFile != null && manifestFile.exists()) {
manifestSet.add(manifestFile)
}
modules.add(moduleName)
}
}
// for default main sources
sourceSetConf(android.sourceSets.main)
// for buildType sources
android.buildTypes.each {
def buildType = it.name
android.sourceSets.getByName(buildType) {
sourceSetConf(it)
}
}
// for flavor sources
android.productFlavors.each {
def flavor = it.name
android.sourceSets.getByName(flavor) {
sourceSetConf(it)
}
}
I see some code from gradle what multiple modules merge, but still no idea how to
ManifestMerger2
ProcessManifest
Use multiple modules via Android Studio. Create dependencies between modules. To make ModuleA depend on ModuleB, put the following inside build.gradle of ModuleA:
dependencies {
// ...
compile project(':ModuleB')
// ...
}
This should merge AndroiManifest.xml from both modules when buiding ModuleA
I just use ManifestMerger2 to do it.
private static void merge(File reportFile, File mainManifest, File... libraryManifests) {
if (libraryManifests == null || libraryManifests.length == 0) {
return
}
ILogger logger = new StdLogger(Level.VERBOSE)
Invoker manifestMergerInvoker = ManifestMerger2.newMerger(mainManifest, logger, MergeType.APPLICATION)
manifestMergerInvoker.setMergeReportFile(reportFile)
manifestMergerInvoker.addLibraryManifests(libraryManifests)
println "start merge..."
MergingReport mergingReport = manifestMergerInvoker.merge()
println "end merge..."
if (MergingReport.Result.SUCCESS) {
XmlDocument xmlDocument = mergingReport.getMergedXmlDocument(MergingReport.MergedManifestKind.MERGED)
try {
String annotatedDocument = mergingReport.getActions().blame(xmlDocument)
logger.verbose(annotatedDocument)
} catch (Exception e) {
logger.error(e, "cannot print resulting xml")
}
save(xmlDocument, mainManifest)
}
}
private static void save(XmlDocument xmlDocument, File out) {
try {
Files.write(xmlDocument.prettyPrint(), out, Charsets.UTF_8)
} catch (IOException e) {
throw new RuntimeException(e)
}
}