diff --git a/CHANGELOG.md b/CHANGELOG.md index 665803ee..6f7f30ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## Unreleased + +- Support Splits/Multi-APKs and universal APK modes. + ## 1.3.2 ### Changed diff --git a/build.gradle.kts b/build.gradle.kts index 545e3dc7..730fb73b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -93,6 +93,7 @@ dependencies { compileOnly(libs.agp.common) testImplementation(libs.junit) testImplementation(libs.truth) + testImplementation(libs.testParameterInjector) fixtureClasspath(libs.agp.build.flatMap { dependency -> fixtureAgpVersion.map { version -> "${dependency.group}:${dependency.name}:$version" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c9f58e6a..2be936e0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,7 @@ detekt = "1.23.7" mavenPublish = "0.29.0" junit = "4.13.2" truth = "1.1.3" +testParameterInjector = "1.18" toolchainsResolver = "0.9.0" [libraries] @@ -16,6 +17,7 @@ agp-build = { module = "com.android.tools.build:gradle", version.ref = "agp" } agp-common = { module = "com.android.tools:common", version.ref = "agp-common" } junit = { module = "junit:junit", version.ref = "junit" } truth = { module = "com.google.truth:truth", version.ref = "truth" } +testParameterInjector = { group = "com.google.testparameterinjector", name = "test-parameter-injector", version.ref = "testParameterInjector" } [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } diff --git a/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/AppVersioningPluginIntegrationTest.kt b/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/AppVersioningPluginIntegrationTest.kt index 459ccc86..4267eb51 100644 --- a/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/AppVersioningPluginIntegrationTest.kt +++ b/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/AppVersioningPluginIntegrationTest.kt @@ -3,6 +3,8 @@ package io.github.reactivecircus.appversioning import com.google.common.truth.Truth.assertThat +import com.google.testing.junit.testparameterinjector.TestParameter +import com.google.testing.junit.testparameterinjector.TestParameterInjector import io.github.reactivecircus.appversioning.fixtures.AppProjectTemplate import io.github.reactivecircus.appversioning.fixtures.LibraryProjectTemplate import io.github.reactivecircus.appversioning.fixtures.withFixtureRunner @@ -13,8 +15,10 @@ import org.gradle.testkit.runner.TaskOutcome import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import org.junit.runner.RunWith import java.io.File +@RunWith(TestParameterInjector::class) class AppVersioningPluginIntegrationTest { @get:Rule @@ -65,13 +69,15 @@ class AppVersioningPluginIntegrationTest { } @Test - fun `plugin tasks are registered for Android App project with product flavors`() { + fun `plugin tasks are registered for Android App project with product flavors`( + @TestParameter useKts: Boolean + ) { GitClient.initialize(fixtureDir.root) val flavors = listOf("mock", "prod") withFixtureRunner( fixtureDir = fixtureDir, - subprojects = listOf(AppProjectTemplate(flavors = flavors)) + subprojects = listOf(AppProjectTemplate(useKts = useKts, flavors = flavors)) ).runAndCheckResult( "tasks", "--group=versioning" @@ -199,7 +205,9 @@ class AppVersioningPluginIntegrationTest { } @Test - fun `plugin generates versionCode and versionName for the assembled APK when assemble task is run`() { + fun `plugin generates versionCode and versionName for the assembled APK when assemble task is run`( + @TestParameter useKts: Boolean + ) { GitClient.initialize(fixtureDir.root).apply { val commitId = commit(message = "1st commit.") tag(name = "1.2.3", message = "1st tag", commitId = commitId) @@ -207,7 +215,77 @@ class AppVersioningPluginIntegrationTest { withFixtureRunner( fixtureDir = fixtureDir, - subprojects = listOf(AppProjectTemplate()) + subprojects = listOf(AppProjectTemplate(useKts = useKts)) + ).runAndCheckResult( + "assembleRelease" + ) { + val versionCodeFileContent = File( + fixtureDir.root, + "app/build/outputs/app_versioning/release/version_code.txt" + ).readText() + val versionNameFileContent = File( + fixtureDir.root, + "app/build/outputs/app_versioning/release/version_name.txt" + ).readText() + + assertThat(task(":app:generateAppVersionInfoForRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + assertThat(task(":app:assembleRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + + assertThat(output).contains("Generated app version code: 10203.") + assertThat(output).contains("Generated app version name: \"1.2.3\".") + + assertThat(versionCodeFileContent).isEqualTo("10203") + assertThat(versionNameFileContent).isEqualTo("1.2.3") + } + } + + @Test + fun `plugin generates versionCode and versionName for the assembled APKs when splits-APKs is enabled`( + @TestParameter useKts: Boolean + ) { + GitClient.initialize(fixtureDir.root).apply { + val commitId = commit(message = "1st commit.") + tag(name = "1.2.3", message = "1st tag", commitId = commitId) + } + + withFixtureRunner( + fixtureDir = fixtureDir, + subprojects = listOf(AppProjectTemplate(useKts = useKts, splitsApks = true)) + ).runAndCheckResult( + "assembleRelease" + ) { + val versionCodeFileContent = File( + fixtureDir.root, + "app/build/outputs/app_versioning/release/version_code.txt" + ).readText() + val versionNameFileContent = File( + fixtureDir.root, + "app/build/outputs/app_versioning/release/version_name.txt" + ).readText() + + assertThat(task(":app:generateAppVersionInfoForRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + assertThat(task(":app:assembleRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + + assertThat(output).contains("Generated app version code: 10203.") + assertThat(output).contains("Generated app version name: \"1.2.3\".") + + assertThat(versionCodeFileContent).isEqualTo("10203") + assertThat(versionNameFileContent).isEqualTo("1.2.3") + } + } + + @Test + fun `plugin generates versionCode and versionName for the assembled APKs when splits-APKs is enabled and universal mode is on`( + @TestParameter useKts: Boolean + ) { + GitClient.initialize(fixtureDir.root).apply { + val commitId = commit(message = "1st commit.") + tag(name = "1.2.3", message = "1st tag", commitId = commitId) + } + + withFixtureRunner( + fixtureDir = fixtureDir, + subprojects = listOf(AppProjectTemplate(useKts = useKts, splitsApks = true, universalApk = true)) ).runAndCheckResult( "assembleRelease" ) { diff --git a/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/fixtures/ProjectTemplates.kt b/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/fixtures/ProjectTemplates.kt index 57661cbd..db3c3058 100644 --- a/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/fixtures/ProjectTemplates.kt +++ b/src/functionalTest/kotlin/io/github/reactivecircus/appversioning/fixtures/ProjectTemplates.kt @@ -43,15 +43,16 @@ fun gradlePropertiesFileContent(enableConfigurationCache: Boolean): String { """.trimIndent() } -abstract class AndroidProjectTemplate { +sealed class AndroidProjectTemplate { abstract val projectName: String abstract val pluginExtension: String? abstract val useKts: Boolean abstract val flavors: List - abstract val isAppProject: Boolean val buildFileContent: String get() = if (useKts) ktsBuildFileContent else groovyBuildFileContent + private val isAppProject = this is AppProjectTemplate + private val ktsBuildFileContent: String get() { val flavorConfigs = if (flavors.isNotEmpty()) { @@ -64,6 +65,24 @@ abstract class AndroidProjectTemplate { } else { "" } + val abiConfigs = if (this is AppProjectTemplate) { + if (splitsApks) { + """ + splits { + abi { + isEnable = true + reset() + include("armeabi-v7a", "arm64-v8a", "x86", "x86_64") + isUniversalApk = $universalApk + } + } + """.trimIndent() + } else { + "" + } + } else { + "" + } return """ plugins { id("com.android.${if (isAppProject) "application" else "library"}") @@ -84,6 +103,8 @@ abstract class AndroidProjectTemplate { lintOptions.isCheckReleaseBuilds = false $flavorConfigs + + $abiConfigs } """.trimIndent() } @@ -100,6 +121,24 @@ abstract class AndroidProjectTemplate { } else { "" } + val abiConfigs = if (this is AppProjectTemplate) { + if (splitsApks) { + """ + splits { + abi { + enable true + reset() + include "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + universalApk $universalApk + } + } + """.trimIndent() + } else { + "" + } + } else { + "" + } return """ plugins { id 'com.android.${if (isAppProject) "application" else "library"}' @@ -122,6 +161,8 @@ abstract class AndroidProjectTemplate { } $flavorConfigs + + $abiConfigs } """.trimIndent() } @@ -141,16 +182,14 @@ class AppProjectTemplate( override val projectName: String = "app", override val pluginExtension: String? = null, override val useKts: Boolean = true, - override val flavors: List = emptyList() -) : AndroidProjectTemplate() { - override val isAppProject: Boolean = true -} + override val flavors: List = emptyList(), + val splitsApks: Boolean = false, + val universalApk: Boolean = false, +) : AndroidProjectTemplate() class LibraryProjectTemplate( override val projectName: String = "library", override val pluginExtension: String? = null, override val useKts: Boolean = true, override val flavors: List = emptyList() -) : AndroidProjectTemplate() { - override val isAppProject: Boolean = false -} +) : AndroidProjectTemplate() diff --git a/src/main/kotlin/io/github/reactivecircus/appversioning/AppVersioningPlugin.kt b/src/main/kotlin/io/github/reactivecircus/appversioning/AppVersioningPlugin.kt index df6206ff..f6fe94d1 100644 --- a/src/main/kotlin/io/github/reactivecircus/appversioning/AppVersioningPlugin.kt +++ b/src/main/kotlin/io/github/reactivecircus/appversioning/AppVersioningPlugin.kt @@ -3,7 +3,6 @@ package io.github.reactivecircus.appversioning import com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION import com.android.build.api.variant.ApplicationAndroidComponentsExtension import com.android.build.api.variant.ApplicationVariant -import com.android.build.api.variant.VariantOutputConfiguration import com.android.build.gradle.AppPlugin import io.github.reactivecircus.appversioning.tasks.GenerateAppVersionInfo import io.github.reactivecircus.appversioning.tasks.PrintAppVersionInfo @@ -60,9 +59,10 @@ class AppVersioningPlugin : Plugin { project.registerPrintAppVersionInfoTask(variantName = variant.name) - val mainOutput = variant.outputs.single { it.outputType == VariantOutputConfiguration.OutputType.SINGLE } - mainOutput.versionCode.set(generatedVersionCode) - mainOutput.versionName.set(generatedVersionName) + variant.outputs.forEach { output -> + output.versionCode.set(generatedVersionCode) + output.versionName.set(generatedVersionName) + } } } }