JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
16.01k stars 1.17k forks source link

Cannot access resource under commonMain/res from Platform side #3844

Closed KevinnZou closed 11 months ago

KevinnZou commented 11 months ago

Describe the bug I am developing a Multiplatform WebView project and want to support loading local HTML files. In Android, we just need to put the HTML files under the asset folder and call webView.loadUrl("file:///android_asset/file.html");

Under the multiplatform situation, I want to put the HTML files under commonMain/res folder and use expect/actual to load the files on each platform. However, I cannot find a way to access that file from the Platform side. I am wondering if is there any way to access the file from the platform side.

Affected platforms Select one of the platforms below:

Versions

jbruchanov commented 11 months ago

@KevinnZou Hi, I'll try to answer it. I believe I had similar issue if I understand you correctly, it's not imo bug, it's just misunderstanding of how the resources are being handled in KMP.

The important thing is the android res vs java/kmp resources, these two are different things.

androidMain/res <- that's where android is storing own stuff accessible via android resources and referenced via R class. commonMain/res <- there is nothing like that (unless configured to be part of KMP resources) commonMain/resources <- that's the place what I assume you put the file.html into.

Now, whatever you have in kmp commonMain/resources (not android 'res') can't be simply accessed in standard android way. It must be accesses standard "java" way.

android: https://github.com/JetBrains/compose-multiplatform/blob/master/components/resources/library/src/androidMain/kotlin/org/jetbrains/compose/resources/Resource.android.kt

similarly for iOS or other platforms in related source files https://github.com/JetBrains/compose-multiplatform/blob/master/components/resources/library/src/iosMain/kotlin/org/jetbrains/compose/resources/Resource.ios.kt

Just to check your project setup If you assemble your apk (or jar for jvm), just open the file to look inside it (rename to zip). There should be simply your /file.html (matching commonMain/resources folder structure), if it's not, then the project setup is somehow incorrect.

So for your specific example to have this webView.loadUrl("file:///android_asset/file.html") working. The file must be stored as androidMain/assets/file.html which is being stored in APK as /assets/file.html. Given the difference between in path, there is some url processing under the hood, so I'm not totally sure if simply webView.loadUrl("file:///file.html") can work.

So to "fix" your issue

KevinnZou commented 11 months ago

@jbruchanov Thank you for your reply! You really helped me a lot and I really appreciate it!

For your first solution, It is exactly what I did before. However, it does not support external links to CSS or JS files. As a result, I need to locate the file path and pass it to WebView.

I checked that the files are stored inside the APK. Then, I tried with webView.loadUrl("file:///file.html") and webView.loadUrl("file:///android_asset/../file.html"), but all failed. It is wired and I am unable to find an answer for it.

However, I tried your third solution and it works well! The files under "commonMain/resources/assets" will be packaged to the asset folder of the APK so that I can access it by webView.loadUrl("file:///android_asset/file.html").

You are welcome to review my final work, which can be found here. Thank you once again!

dima-avdeev-jb commented 11 months ago

@jbruchanov Thanks for answer!

okushnikov commented 2 months ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.