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
}
}
}
}
}
Related
I'm using easylaucher library Easylaucher library to add a ribbon on the app icon. I'm using kotlin DSL but when I apply the easy laucher configurations it throws EasyLauncherConfig with name 'debug' not found.
Here is my configuration
plugins {
id("kotlin-android")
id(BuildPlugins.androidApplication)
id("com.starter.easylauncher") version "5.1.2"
}
android {
//...
}
dependencies {
//...
}
easylauncher {
buildTypes{
getByName("debug") {
filters(
customRibbon(label = "Debug", ribbonColor = "#FF0000")
)
}
getByName("release") {
filters(
customRibbon(label = "BETA", ribbonColor = "#F18357")
)
}
}
}
Anyone with a good solution to this?
I found the solution. Instead of using getByName(...) I used register(...)
easylauncher {
buildTypes{
register("debug") {
filters(
customRibbon(label = "Debug", ribbonColor = "#FF0000")
)
}
register("release") {
filters(
customRibbon(label = "BETA", ribbonColor = "#F18357")
)
}
}
}
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
In my application, I manage all Gradle stuff in buildSrc. One of them is buildTypes. I am able to access all the properties that buildTypes provide. However, I cannot access applicationVariants in buildSrc. Is there any way to do so?
Sample code block in buildSrc/BuildTypes.kt
internal object Debug : BuildTypeCreator {
override val name = InternalBuildType.DEBUG
override fun create(
namedDomainObjectContainer: NamedDomainObjectContainer<BuildType>,
project: Project,
isLibrary: Boolean,
closure: BuildType.() -> Unit
): BuildType {
return namedDomainObjectContainer.maybeCreate(name).apply {
if (isLibrary) {
versionNameSuffix = "-dev-${project.gitSha}"
} else {
applicationIdSuffix = ".dev"
}
isTestCoverageEnabled = true
isMinifyEnabled = false
isDebuggable = true
closure.invoke(this)
}
}
}
Sample code block in app.gradle.kts(which I want to achieve the same
in buildSrc)
applicationVariants.all { -> **This is not accessible in buildSrc**
if (buildType.name == getByName("release").name) {
outputs.all { output: BaseVariantOutput ->
val outputImpl = output as BaseVariantOutputImpl
outputImpl.outputFileName = "calendar-view.apk"
true
}
}
}
Thanks in advance.
OK, I solved it passing an argument domainObjectSet: DomainObjectSet<ApplicationVariant>
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)
}
}
I have a task that comes from a plugin i am using and i want to overwrite it only when compiling for debug buildType.
I tried overwriting in the debug scope:
buildTypes {
debug {
task newRelicInstrumentTask(overwrite: true) << {}
task newRelicDeinstrumentTask(overwrite: true) << {}
}
}
but it also overridden it for the release buildType.
I also tried doing the following:
buildTypes.all{ theBuildType ->
print(theBuildType.name)
if (theBuildType.name == "debug")
{
task newRelicInstrumentTask(overwrite: true) << {}
task newRelicDeinstrumentTask(overwrite: true) << {}
}
}
But it also overides it when i am executing assembleRelease.
So how can i override it only when i am running assembleDebug?
Something like:
gradle.taskGraph.whenReady { TaskExecutionGraph teg ->
if (teg.hasTask('assembleDebug')) {
tasks.getByPath('newRelicInstrumentTask').enabled = false
tasks.getByPath('newRelicDeinstrumentTask').enabled = false
}
}
See TaskExecutionGraph
This what worked best eventually:
if ((gradle.startParameter.taskNames.size() == 1) && (gradle.startParameter.taskNames.get(0).contains(
"assembleDebug"))) {
task newRelicInstrumentTask(overwrite: true) << {
}
task newRelicDeinstrumentTask(overwrite: true) << {
}
}