From c43b64d43a20d155a52bf376c22a34182d583c7a Mon Sep 17 00:00:00 2001 From: Konstantin Date: Tue, 19 Mar 2024 16:27:36 +0100 Subject: [PATCH] [resources] Fix android fonts in APKs (#4509) Steps to reproduce: 1) Add a 'font-en' directory with a font to an android app with compose resources 2) build the app with `assembleDebug` and check that a corresponding dir is presented in the final APK 3) rename a qualifier of the dir to `font-de` 4) re-build the app with the same command `assembleDebug` Expected: the new APK will contain the new font dir Actual: the new APK doesn't have the new font dir but has old one 'font-en' The PR fixes that --- .../compose/resources/ResourcesGenerator.kt | 2 +- .../test/tests/integration/ResourcesTest.kt | 111 ++++++++++++++---- .../misc/commonResources/expected/Font0.kt | 15 ++- .../composeResources/font-en/emptyFont.otf | Bin 0 -> 1308 bytes 4 files changed, 96 insertions(+), 32 deletions(-) create mode 100644 gradle-plugins/compose/src/test/test-projects/misc/commonResources/src/commonMain/composeResources/font-en/emptyFont.otf diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ResourcesGenerator.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ResourcesGenerator.kt index c6cf34daa3..4156068400 100644 --- a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ResourcesGenerator.kt +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ResourcesGenerator.kt @@ -308,7 +308,7 @@ internal abstract class CopyAndroidFontsToAssetsTask : DefaultTask() { @get:Inject abstract val fileSystem: FileSystemOperations - @get:Input + @get:InputDirectory abstract val from: Property @get:OutputDirectory diff --git a/gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/ResourcesTest.kt b/gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/ResourcesTest.kt index 8e029710e6..50a9fe813e 100644 --- a/gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/ResourcesTest.kt +++ b/gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/ResourcesTest.kt @@ -292,21 +292,41 @@ class ResourcesTest : GradlePluginTestBase() { check.taskSuccessful(":copyFullDebugFontsToAndroidAssets") check.taskSuccessful(":copyFullReleaseFontsToAndroidAssets") - checkAndroidApk("demo", "debug", commonResourcesFiles) - checkAndroidApk("demo", "release", commonResourcesFiles) - checkAndroidApk("full", "debug", commonResourcesFiles) - checkAndroidApk("full", "release", commonResourcesFiles) - - val desktopJar = file("build/libs/Resources-Test-desktop.jar") - assertTrue(desktopJar.exists()) - ZipFile(desktopJar).use { zip -> - commonResourcesFiles.forEach { res -> - assertNotNull(zip.getEntry(res)) - } - val platformTxt = zip.getEntry("files/platform.txt") - assertNotNull(platformTxt) - val text = zip.getInputStream(platformTxt).readBytes().decodeToString() - assertEquals("desktop", text) + getAndroidApk("demo", "debug", "Resources-Test").let { apk -> + checkResourcesInZip(apk, commonResourcesFiles, true) + assertEquals( + "android demo-debug", + readFileInZip(apk, "files/platform.txt").decodeToString() + ) + } + getAndroidApk("demo", "release", "Resources-Test").let { apk -> + checkResourcesInZip(apk, commonResourcesFiles, true) + assertEquals( + "android demo-release", + readFileInZip(apk, "files/platform.txt").decodeToString() + ) + } + getAndroidApk("full", "debug", "Resources-Test").let { apk -> + checkResourcesInZip(apk, commonResourcesFiles, true) + assertEquals( + "android full-debug", + readFileInZip(apk, "files/platform.txt").decodeToString() + ) + } + getAndroidApk("full", "release", "Resources-Test").let { apk -> + checkResourcesInZip(apk, commonResourcesFiles, true) + assertEquals( + "android full-release", + readFileInZip(apk, "files/platform.txt").decodeToString() + ) + } + + file("build/libs/Resources-Test-desktop.jar").let { jar -> + checkResourcesInZip(jar, commonResourcesFiles, false) + assertEquals( + "desktop", + readFileInZip(jar, "files/platform.txt").decodeToString() + ) } val jsBuildDir = file("build/dist/js/productionExecutable") @@ -317,32 +337,73 @@ class ResourcesTest : GradlePluginTestBase() { } } + @Test + fun testAndroidFonts(): Unit = with(testProject("misc/commonResources")) { + val commonResourcesDir = file("src/commonMain/composeResources") + val commonResourcesFiles = commonResourcesDir.walkTopDown() + .filter { !it.isDirectory && !it.isHidden } + .map { it.relativeTo(commonResourcesDir).invariantSeparatorsPath } + + gradle("assembleDebug").checks { + check.taskSuccessful(":copyDebugFontsToAndroidAssets") + + getAndroidApk("", "debug", "Resources-Test").let { apk -> + checkResourcesInZip(apk, commonResourcesFiles, true) + } + } + + file("src/commonMain/composeResources/font-en").renameTo( + file("src/commonMain/composeResources/font-mdpi") + ) + val newCommonResourcesFiles = commonResourcesDir.walkTopDown() + .filter { !it.isDirectory && !it.isHidden } + .map { it.relativeTo(commonResourcesDir).invariantSeparatorsPath } + gradle("assembleDebug").checks { + check.taskSuccessful(":copyDebugFontsToAndroidAssets") + + getAndroidApk("", "debug", "Resources-Test").let { apk -> + checkResourcesInZip(apk, newCommonResourcesFiles, true) + } + } + } + private fun File.writeNewFile(text: String) { parentFile.mkdirs() createNewFile() writeText(text) } - private fun TestProject.checkAndroidApk(flavor: String, type: String, commonResourcesFiles: Sequence) { - val apk = file("build/outputs/apk/$flavor/$type/Resources-Test-$flavor-$type.apk") - assertTrue(apk.exists()) - ZipFile(apk).use { zip -> + private fun TestProject.getAndroidApk(flavor: String, type: String, name: String): File { + return if (flavor.isNotEmpty()) { + file("build/outputs/apk/$flavor/$type/$name-$flavor-$type.apk") + } else { + file("build/outputs/apk/$type/$name-$type.apk") + } + } + + private fun checkResourcesInZip(file: File, commonResourcesFiles: Sequence, isAndroid: Boolean) { + println("check ZIP: '${file.path}'") + assertTrue(file.exists()) + ZipFile(file).use { zip -> commonResourcesFiles.forEach { res -> - if (res == "font/emptyFont.otf") { + println("check '$res' file") + if (isAndroid && res.startsWith("font")) { //android fonts should be only in assets assertNull(zip.getEntry(res), "file = '$res'") + assertNotNull(zip.getEntry("assets/$res"), "file = 'assets/$res'") } else { assertNotNull(zip.getEntry(res), "file = '$res'") } } - assertNotNull(zip.getEntry("assets/font/emptyFont.otf"), "file = 'assets/font/emptyFont.otf'") - val platformTxt = zip.getEntry("files/platform.txt") - assertNotNull(platformTxt, "file = 'files/platform.txt'") - val text = zip.getInputStream(platformTxt).readBytes().decodeToString() - assertEquals("android $flavor-$type", text) } } + private fun readFileInZip(file: File, path: String): ByteArray = ZipFile(file).use { zip -> + val platformTxt = zip.getEntry(path) + assertNotNull(platformTxt, "file = '$path'") + zip.getInputStream(platformTxt).readBytes() + } + @Test fun testUpToDateChecks(): Unit = with(testProject("misc/commonResources")) { gradle("prepareKotlinIdeaImport").checks { diff --git a/gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected/Font0.kt b/gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected/Font0.kt index 660d2deca8..2530f99e84 100644 --- a/gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected/Font0.kt +++ b/gradle-plugins/compose/src/test/test-projects/misc/commonResources/expected/Font0.kt @@ -8,8 +8,8 @@ import org.jetbrains.compose.resources.FontResource @ExperimentalResourceApi private object Font0 { - public val emptyFont: FontResource by - lazy { init_emptyFont() } + public val emptyFont: FontResource by + lazy { init_emptyFont() } } @ExperimentalResourceApi @@ -19,7 +19,10 @@ internal val Res.font.emptyFont: FontResource @ExperimentalResourceApi private fun init_emptyFont(): FontResource = org.jetbrains.compose.resources.FontResource( "font:emptyFont", - setOf( - org.jetbrains.compose.resources.ResourceItem(setOf(), "font/emptyFont.otf"), - ) -) + setOf( + + org.jetbrains.compose.resources.ResourceItem(setOf(org.jetbrains.compose.resources.LanguageQualifier("en"), + ), "font-en/emptyFont.otf"), + org.jetbrains.compose.resources.ResourceItem(setOf(), "font/emptyFont.otf"), + ) +) \ No newline at end of file diff --git a/gradle-plugins/compose/src/test/test-projects/misc/commonResources/src/commonMain/composeResources/font-en/emptyFont.otf b/gradle-plugins/compose/src/test/test-projects/misc/commonResources/src/commonMain/composeResources/font-en/emptyFont.otf new file mode 100644 index 0000000000000000000000000000000000000000..883bb179cba10eca883bd5a830905f5156406a24 GIT binary patch literal 1308 zcmZXU&ubGw6vw}_yJ>zjzbYzXZCSKf1&xWQl`3LUdQnM#QN7f3X}3+G`9YFOi#-Tl zq+7w0C$R_h;NQ?92wuEbya*EL!9PIhhPK8xv$Hxev&_8Dn|brzcV{QbPE2GG#uMmB z-Wnb@AHNuV0~luj>}1C;T%60~5&$C?(=!FDj4!wk=%2{Howu#oQ>jst_!adld798Z z;56|z^}c+ewyfVELLf>*vS2NjVT|wzmwHFhD%h7Ez2B$&(|~4`OVt|bpk{<sn4>*ow999B4@aHqmig<}fG6;3KTyM#_1%m|Zq4cF-OI5R{j z%3}?29F?r27w;q+IF5|u0P(8i4jiK!>NUnv3R%HfA0K1%PF+HshYc5wr1?1rQ$4|*-WWoQx@j1b@rTuu)EpOad&E?F>u6j zoPz