moko-resources icon indicating copy to clipboard operation
moko-resources copied to clipboard

#535 kotlin 1.9.0, compose multiplatform 1.5.0 support

Open Alex009 opened this issue 2 years ago • 87 comments

Include changes from:

  • #565
  • #561
  • #547
  • #541

plugin reworked to Provider gradle's api to support dynamic changes of projects configuration.


If you have some not standard usecase - send PR with new sample project please. every sample project is our test case


This request contains breaking changes to better support dynamic changes of configurations and support new features in future (for example - configuration cache #311 ).

At first - resources directory moved from src/<resourceSourceSetName>/resources/MR to src/<sourceSetName>/moko-resources. I have multiple reasons for this:

  1. Kotlin improve own resources directory management and Compose Multiplatform at now use content of resources directory. Our resources in MR directory was not ready for directly usage as resource - our resources if "source" for generation of platform resources. For example - for iOS all resources should be packed in bundle, for android svg should be converted to vector-xml. in resources source set in future we can put output of our generators, but "source" resources should not be copied into result app.
  2. at gradle configuration stage we can't correctly decide what source set should be used for generation with current logic resourceSourceSetName that configured in plugin's extension - source sets can change at any time, and resourceSourceSetName in plugin extension can be changed in any time. So we should generate MR tasks for all sourcesets and decide what to do at EXECUTION stage. Also it allow to put resources in any sourceSet in hierarchy. For example in commonMain will be common resources and in iosMain will be ios specific resources added. It's was requested in #357

Second - MR object will be generated not only expect + actuals, but also for middle layer expects in different source sets. For example if we have next sourceSets hierarchy:

commonMain // here we have string common_hello
- androidMain // here no any additional strings
- appleMain  // here we have string apple_hello
-- iosMain  // here we have string ios_hello
--- iosX64Main  // here we have string iosx64_hello
--- iosSimulatorArm64Main // here no any additional strings
--- iosArm64Main // here no any additional strings

We can put resources in each source set. And as result we got this sources: commonMain/MR.common.kt:

expect object MR {
    object strings: AppleMainStrings, IosMainStrings {
        val commonHello: StringResource
    }
}

expect interface AppleMainStrings // this naming not final. if you have idea about better name - please write comment
expect interface IosMainStrings // this naming not final. if you have idea about better name - please write comment

androidMain/MR.android.kt:

actual interface AppleMainStrings
actual interface IosMainStrings

actual object MR {
    actual object strings : AppleMainStrings, IosMainStrings {
        actual val commonHello: StringResource get() = TODO()
    }
}

appleMain/MR.apple.kt:

actual interface AppleMainStrings {
    val appleHello: StringResource
}

iosMain/MR.ios.kt:

actual interface IosMainStrings {
    val iosHello: StringResource
}

iosX64Main/MR.iosX64.kt:

actual object MR {
    actual object strings : AppleMainStrings, IosMainStrings {
        actual val commonHello: StringResource get() = TODO()
        override val appleHello: StringResource get() = TODO()
        override val iosHello: StringResource get() = TODO()
        val iosX64Hello: StringResource get() = TODO()
    }
}

iosArm64Main/MR.iosArm64.kt, iosSimulatorArm64Main/MR.iosSimulatorArm64.kt:

actual object MR {
    actual object strings : AppleMainStrings, IosMainStrings {
        actual val commonHello: StringResource get() = TODO()
        override val appleHello: StringResource get() = TODO()
        override val iosHello: StringResource get() = TODO()
    }
}

To decide what exactly should be generated each generateMR task will check own moko-resources directory and dependencies. expect object MR will be located at lowest level of hierarchy (for example if we have not resources in commonMain but have in iosMain - expect will be in iosMain and commonMain will be empty. With this change we can remove resourcesSourceSet property from extension.


Current progress:

  • [x] Common generator
  • [x] Target generator
  • [x] Android MR generator
  • [x] JVM MR generator
  • [x] JS MR generator
  • [x] Apple MR generator
  • [x] Define generated resources as sourceSet, assets, resources**
  • [x] Copy resources of Apple and JS targets in KLibs**
  • [x] Metadata:
    • [x] Base
    • [x] All generators work with metadata
  • [x] Move resources from resources/MR to moko-resources
  • [x] Strings generator: - Success run on sample
    • [x] Common target
    • [x] Android target
    • [x] Jvm target
    • [x] Js target
    • [x] Apple target
  • [x] Plurals generator: - Success run on sample
    • [x] Common target
    • [x] Android target
    • [x] Jvm target
    • [x] Js target
    • [x] Apple target
  • [x] Files generator:
    • [x] Common target
    • [x] Android target
    • [x] Jvm target
    • [x] Js target
    • [x] Apple target
  • [x] Fonts generator:
    • [x] Common target
    • [x] Android target
    • [x] Jvm target
    • [x] Js target
    • [x] Apple target
  • [x] Assets generator:
    • [x] Common target
    • [x] Android target
    • [x] Jvm target
    • [x] Js target
    • [x] Apple target
  • [x] Colors generator:
    • [x] Common target
    • [x] Android target
    • [x] Jvm target
    • [x] Js target
    • [x] Apple target
  • [x] Images generator:
    • [x] Common target
    • [x] Android target
    • [x] Jvm target
    • [x] Js target
    • [x] Apple target
  • [x] Testing on samples
  • [ ] Testing on real IceRock projects

known issues:

  • [ ] gradle task cache not invalidates when add resources in target sourceset, when project already compiled with resources exist on lower levels (when have resources in commonMain, compile, then create resources in desktopMain)
  • [ ] fonts generated object is changed (in past we have additional object with font family name and inside have properties with styles. now we have only properties like fontfamily-style) - i think we can not fix this at all
  • [ ] assets generated object is changed (in past was generated also inner objects like directory tree. now generated only flat properties and you can't see directory structure) - want to fix, but can't decide how (when we should generate interface for intermediate resources - we can't generated inner objects)
  • [x] in some cases actual for iOS target not generated

todo:

  • [x] research usage of Android Gradle Plugin Variants API to fix issues like #628
  • [ ] try to implement integrational junit tests with testrun various kotlin, android gradle plugin versions - help required here
  • [ ] check Action implementations - move all that can be moved to separated gradle tasks
  • [ ] remove expect/actual interfaces at all (Parcelable usage, ResourceContainer, generated interfaces) - https://youtrack.jetbrains.com/issue/KT-59739
  • [ ] fix assets bug - https://github.com/icerockdev/moko-resources/pull/575#issuecomment-1928053225
  • [ ] build failed with mockmp - https://github.com/icerockdev/moko-resources/pull/575#issuecomment-1927402089
  • [ ] js build failed - https://github.com/icerockdev/moko-resources/discussions/625#discussioncomment-8130422
  • [ ] copyFrameworkResourcesToApp missed (when framework prefix is empty) - https://github.com/icerockdev/moko-resources/discussions/625#discussioncomment-8424427
  • [ ] android R class missed - https://github.com/icerockdev/moko-resources/discussions/625#discussioncomment-8390982
  • [ ] fix compatibility with compose resources - https://kotlinlang.slack.com/archives/CMC5LN42W/p1707978856036959?thread_ts=1705913203.842639&cid=CMC5LN42W
  • [ ] check assets changes - https://kotlinlang.slack.com/archives/CMC5LN42W/p1707653155054129

Alex009 avatar Sep 11 '23 07:09 Alex009

@Pschsch hi. can you also test your project with this branch? and if you got some issues - please submit small test project for samples directory, i use samples as test cases for plugin

Alex009 avatar Sep 11 '23 09:09 Alex009

@illarionov hi. can you also test your project with this branch? and if you got some issues - please submit small test project for samples directory, i use samples as test cases for plugin

Alex009 avatar Sep 11 '23 09:09 Alex009

@Pschsch hi. can you also test your project with this branch? and if you got some issues - please submit small test project for samples directory, i use samples as test cases for plugin

Hi @Alex009, i ll try to test today. Wait for feedback)

Pschsch avatar Sep 11 '23 10:09 Pschsch

@illarionov hi. can you also test your project with this branch? and if you got some issues - please submit small test project for samples directory, i use samples as test cases for plugin

I don't have my own project yet, just checking if I can use this library in the future. I used samples from this repository for my own testing.

illarionov avatar Sep 11 '23 11:09 illarionov

This branch still has issue with implicit task dependencies. Shouldn't it be resolved here?

Task 'kspKotlinIosArm64' uses this output of task 'generateMRiosArm64Main' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are **executed.**

In Gradle 8, this leads to build failure

Pschsch avatar Sep 12 '23 15:09 Pschsch

In total, this branch breaks the main functional - resources generating. MR objects generating with no resources fields Screenshot_170 But there must be tons of strings, colors and images Assume that it's because of new lazy plugin configuration

Pschsch avatar Sep 12 '23 16:09 Pschsch

Reverting branch to my commit with hash 316f2a66559e510f2be8302a87331437bc9238b5 fixes the issue with generation. So suppose that plugin has broken after this commit

Pschsch avatar Sep 12 '23 16:09 Pschsch

@Pschsch did you move all the resources from resources/MR/* to moko-resources/*?

illarionov avatar Sep 12 '23 22:09 illarionov

@illarionov i've cloned my project from scratch for test. Why i should manually move resources? Plugin's tasks should generate resources in appropriate way as they do it on 316f2a66559e510f2be8302a87331437bc9238b5 commit and before)

Pschsch avatar Sep 13 '23 06:09 Pschsch

As I've already said, the problem exists on commits after 316f2a66559e510f2be8302a87331437bc9238b5

Pschsch avatar Sep 13 '23 06:09 Pschsch

@Pschsch no. With this release we move resources to moko-resources from resources/MR to prevent conflicts with kotlin own resources management

Alex009 avatar Sep 13 '23 06:09 Alex009

Oh, sorry, my fail, i got it. No, I've not done it

Pschsch avatar Sep 13 '23 06:09 Pschsch

I'll test today one more time and will give a fedback

Pschsch avatar Sep 13 '23 06:09 Pschsch

Tried to move res in one module from resources/MR to moko-resources. Got: Screenshot_175

Pschsch avatar Sep 13 '23 15:09 Pschsch

Replaced mkdir() to mkdirs(), the problem has disappeared. The new problem - images not generating. Strings, plurals and colors exist

Pschsch avatar Sep 13 '23 15:09 Pschsch

Any news here? Eagerly waiting for the next update with this fix to be finally able to update to Kotlin 1.9. 😅

ubuntudroid avatar Oct 02 '23 12:10 ubuntudroid

any news?

juhaodong avatar Oct 20 '23 07:10 juhaodong

When can we expect this to be merged ? @Alex009 @illarionov @Pschsch

umesh0492 avatar Nov 01 '23 12:11 umesh0492

When can we expect this to be merged ? @Alex009 @illarionov @Pschsch

here not completed changes. at first i should complete all changes in plugin and then we can merge and publish

Alex009 avatar Nov 01 '23 15:11 Alex009

For those waiting for this pr. You can update to kotlin 1.9 and use the code below:

sourceSets {
            //val commonMain by getting

      androidMain {
          dependsOn(commonMain.get())
      }

      iosMain {
          dependsOn(commonMain.get())
      }
}

It will avoid the new default hierarchy, BUT you can update to Kotlin 1.9.20 It can be removed after this PR is merged.

jcaiqueoliveira avatar Nov 04 '23 17:11 jcaiqueoliveira

For those waiting for this pr. You can update to kotlin 1.9 and use the code below:

sourceSets {
            //val commonMain by getting

      androidMain {
          dependsOn(commonMain.get())
      }

      iosMain {
          dependsOn(commonMain.get())
      }
}

It will avoid the new default hierarchy, BUT you can update to Kotlin 1.9.20 It can be removed after this PR is merged.

I have a question, I need to use the current version or compile in maven local this PR and put this changes ?

carlosgub avatar Nov 04 '23 19:11 carlosgub

I have a question, I need to use the current version or compile in maven local this PR and put this changes ?

I did it using the 0.23.0 version and it worked. My config is something like this:

fun Project.setupKMP() {
    plugins.withType<org.jetbrains.kotlin.gradle.plugin.KotlinBasePluginWrapper> {
        extensions.configure<KotlinMultiplatformExtension> {
            explicitApi()

//https://kotlinlang.org/docs/whatsnew-eap.html#see-the-full-hierarchy-template
            androidTarget()
            iosArm64()
            iosSimulatorArm64()
            // Apply the default hierarchy explicitly. It'll create, for example, the iosMain source set:
            applyDefaultHierarchyTemplate()
            sourceSets {
                androidMain {
                    dependsOn(commonMain.get())
                }
            }
        }

        findAndroidExtension().apply {
            setupAndroid()
            sourceSets["main"].apply {
                res.srcDirs("src/androidMain/resources")
                manifest.srcFile("src/androidMain/AndroidManifest.xml")
            }
        }

    }

    configure<KotlinMultiplatformExtension> {
        jvmToolchain(17)
    }

    configure<JavaPluginExtension> {
        toolchain {
            languageVersion.set(JavaLanguageVersion.of(17))
        }
    }
}

jcaiqueoliveira avatar Nov 04 '23 19:11 jcaiqueoliveira

I have a question, I need to use the current version or compile in maven local this PR and put this changes ?

I did it using the 0.23.0 version and it worked. My config is something like this:

fun Project.setupKMP() {
    plugins.withType<org.jetbrains.kotlin.gradle.plugin.KotlinBasePluginWrapper> {
        extensions.configure<KotlinMultiplatformExtension> {
            explicitApi()

//https://kotlinlang.org/docs/whatsnew-eap.html#see-the-full-hierarchy-template
            androidTarget()
            iosArm64()
            iosSimulatorArm64()
            // Apply the default hierarchy explicitly. It'll create, for example, the iosMain source set:
            applyDefaultHierarchyTemplate()
            sourceSets {
                androidMain {
                    dependsOn(commonMain.get())
                }
            }
        }

        findAndroidExtension().apply {
            setupAndroid()
            sourceSets["main"].apply {
                res.srcDirs("src/androidMain/resources")
                manifest.srcFile("src/androidMain/AndroidManifest.xml")
            }
        }

    }

    configure<KotlinMultiplatformExtension> {
        jvmToolchain(17)
    }

    configure<JavaPluginExtension> {
        toolchain {
            languageVersion.set(JavaLanguageVersion.of(17))
        }
    }
}

Thanks, I will try to try this because my problem was in the iOS side :D

carlosgub avatar Nov 04 '23 20:11 carlosgub

What is the status of this pull request? @Alex009

estivensh avatar Nov 06 '23 20:11 estivensh

@Alex009 ok I see that you sent me two issues, effectively those are already closed? if you need any help, let me know

estivensh avatar Nov 08 '23 18:11 estivensh

Any update folks?

ashu-jar avatar Nov 11 '23 05:11 ashu-jar

At bow my colleague @ExNDY continue work on this changes

Alex009 avatar Nov 11 '23 06:11 Alex009

@Alex009 was it not supported until 1.9.20?

estivensh avatar Nov 22 '23 05:11 estivensh

Any estimate on when this will be done? This is a major blocker for the migration to Compose 1.5 (which was released 3 months ago) and Kotlin 1.9. For now, I don't see any other solution other than to write a custom solution for string localization.

artsmvch avatar Dec 04 '23 09:12 artsmvch

Any estimate on when this will be done? This is a major blocker for the migration to Compose 1.5 (which was released 3 months ago) and Kotlin 1.9. For now, I don't see any other solution other than to write a custom solution for string localization.

It is true, they are hindering a lot to make this migration are launching many changes I would say, and would have done the main thing that was the version upgrade

estivensh avatar Dec 05 '23 02:12 estivensh