How to remove composeResources before packaging th...
# compose
t
How to remove composeResources before packaging the app which are used for previews only? I am using previews images to see how a composable would look like. In Android only project this files would be stripped during optimization because they are not referenced. In Compose Multiplatform this is not working. I came up with a solution but it does not work reliable. Details in the thread:
So i put all preview images into a folder: composeResources/files/preview/... And than i use this task to remove them during preparation task:
Copy code
tasks.named("prepareComposeResourcesTaskForCommonMain") {
    val resDir = layout.buildDirectory.dir("generated/compose/resourceGenerator/preparedResources/commonMain/composeResources/files/preview").get().asFile

    doLast {
        println("=== Resource stripping starting ===")
        // Delete specific preview files from the generated Kotlin sources
        val files = resDir.list() ?: emptyArray<String>()
        files.map { resDir.resolve(it) }
            .forEach { generatedFile ->
            if (generatedFile.exists()) {
                generatedFile.delete()
                println("Stripped preview file: ${generatedFile.absolutePath}")
            } else {
                println("Stripped preview file: ${generatedFile.absolutePath} does not exists")
            }
        }
    }
}
w
Is there a reason you're using a real resource value for previews? You could just use hardcoded strings which would get stripped.
t
Actually i put the images into the files folder for now. So no reference is created to it. Strings are not my problem currently. Just images. Because the preview system cannot do any downloads. So i do load the images from this files folder using
Copy code
Res.readBytes("files/preview/$url.webp")
    .decodeToImageBitmap()
The complete code is:
Copy code
@OptIn(markerClass = [ExperimentalCoilApi::class])
@Composable
actual fun PreviewWrapper(content: @Composable (() -> Unit)) {
    PreviewContextConfigurationEffect()
    val previewHandler = AsyncImagePreviewHandler { request ->
        val model = request.data
        val url = model as? String
        Res.readBytes("files/preview/$url.webp")
            .decodeToImageBitmap()
            .asAndroidBitmap()
            .asImage()
    }

    CompositionLocalProvider(LocalAsyncImagePreviewHandler provides previewHandler) {
        content()
    }
}
It is working very well
w
Ah, I see. I generally just use seeded solid colors derived from the URI rather than real images. I'm not sure if your doLast solution would work. Would that break up to date checking because it edits the output files?
t
Yes it is a littlebit dirty for sure. But i do not have any other solution. And the preview images must not be in the released apk files.
And it will break maybe in future versions.
w
If you have a distinct release task where you can pass a property, the Gradle resources config actually lets you specify a custom resource dir, so you could toggle which dir that pulls from in release builds to an empty dir.
t
Sounds promising. I do have a custom dedicated release task. Can you maybe point me to some documentation how this could work?
The images are inside of the assets folder in the apk. It looks like the compose multiplatform resource system puts everything into the assets folder
w
https://github.com/JetBrains/compose-multiplatform/blob/e72205a03bc2c6c970f98c7c500a899e8895a21d/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/resources/ResourcesDSL.kt#L55 It's this field. You can try pointing to an empty dir. I don't know if the Res class would cause the code to fail to compile though, since the extension fields won't be generated anymore.
If you want to get fancy with it, you could have a task which generates the resources, and in the release build generate empty files with the same names, but that feels overly complex and your delete after would be better.
t
Thank you. I will try to get it working. But not sure. The thing is that the IDE (AndroidStudio/IntelliJ) preview system needs to be able to find the ressources but i want than later strip them out of the release.
Generated kotlin code is not my problem because i do not use Res.drawable references
w
Oh right, because you just look up by path. I do something similar for my site where my debug task is
gradlew -PwasmDebug=true :app:webRelease
. You'd need to invert that and pass
-PisRelease
where you can check
project.getProperty
in the preview files module and conditionally call
customDirectory
. Looking at my code, seems you can just pass
"commonMain"
as the source set and it'll apply to all variants. That should allow Studio to work just fine because it won't set the Gradle property.