目前是否可以有一个使用 compose 的 kotlin 多平台项目来同时共享桌面、Web 和移动设备的 ui 代码?我发现的所有示例仅涵盖带有 JS Front + Jvm Backend 或 JVM Android + Desktop + Common Module 的多平台,并且我在同时使用所有这些设置项目时遇到了麻烦。
我尝试这样做:
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose") version "1.0.1-rc2"
id("com.android.library")
}
kotlin {
android()
jvm("desktop") {
...
}
js{
...
}
sourceSets {
val commonMain by getting {
dependencies {
...
}
}
val commonTest by getting {
dependencies {
...
}
}
val androidMain by getting {
dependencies {
...
}
}
val androidTest by getting {
dependencies {
...
}
}
val desktopMain by getting {
dependencies {
...
}
}
val desktopTest by getting
val jsMain by getting{
dependencies{
...
}
}
val jsTest by getting {
dependencies {
...
}
}
}
}
但它会产生错误:
:common:jsMain: Could not resolve org.jetbrains.compose.runtime:runtime:1.0.1-rc2.
Required by:
project :common
如果我评论 JS 相关部分它可以工作,或者如果我评论所有非 js 相关内容它也可以工作
评论所有与撰写相关的内容也有效
问题仅出现在组合所有内容时
简短的回答是:不,目前这是不可能的。
JB 团队正在致力于此类支持,可以在这些示例中进行测试,但目前它还处于实验阶段,不能保证很快就会发布。 Compose JB 版本现已与 Android Compose 同步,因此我预计 1.2.0 将由两者大约在同一时间发布,即使 Web 支持尚未完成。
我无法重现您的错误,但我假设您尚未从公共依赖项中删除
compose.foundation
和 compose.material
。
目前,公共模块只有
compose.runtime
可用,这使得此时几乎不可能进行任何布局:甚至Button
和Text
都不可用。
正如你在JS应用示例中看到的,
Text
不是从androidx.compose.material.Text
导入的,而是从org.jetbrains.compose.web.dom.Text
导入的,这是一个完全不同的元素,所以它不能在公共模块中使用。
在这一点上,我想说 Compose JS 是另一个允许你以 Compose 风格编写 UI 的框架。
Jetbrains 使用一些示例更新了 Github 存储库:
**
这个答案并不是这个问题的准确答案。正确的 这个问题的答案是@PhilipDukhov 的答案。然而,这可能 帮助登陆此页面的其他人找到其他问题的解决方案 问题我只是把它留在这里。 欲了解更多信息,请阅读评论 我和@PhilipDukhov 之间的这个答案。
**
我做了一些解决方法,并设法将所有东西都放在一个项目中,即
进一步之前的建议
尽管下面的代码片段有效,通过阅读您将会 能够真正实现你想要的。我个人推荐你 只需访问 Github 存储库这里。我认为这会节省时间 如果您正在创建一个新项目。但是,如果您要添加网络 当前 KMM 项目的模块继续阅读。
可以通过保持正确的依赖关系来解决问题
所以项目结构应该是这样的
注意:如果您正在创建一个新的 KMM 项目,您将只有通用、桌面和 Android 模块。(如您所知)
第1步:您需要将一个文件夹添加到根目录(android、common、desktop文件夹所在的位置),将其命名为web(应该没关系)
第2步:在这个新创建的目录web中添加几个文件夹 你的网络目录应该是这样的
注意:不要添加构建(其自动生成)仅添加
src/jsMain
-kotlin
-resources
src/jsTest
-kotlin
-resources
并创建一个名为 build.gradle.kts
的文件第3步:将这个新添加的Gradle文件的内容更改为类似这样的内容
import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose") version "1.0.0"
}
group = "com.example"
version = "1.0"
kotlin {
js(IR) {
browser {
testTask {
testLogging.showStandardStreams = true
useKarma {
useChromeHeadless()
useFirefox()
}
}
}
binaries.executable()
}
sourceSets {
val jsMain by getting {
dependencies {
implementation(compose.web.core)
implementation(compose.runtime)
}
}
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
}
}
第4步:并将Main.kt添加到
jsMain/kotlin
,内容如下
renderComposable(rootElementId = "root") {
Div(
attrs = {
// specify attributes here
style {
// specify inline style here
}
}
) {
Text("A text in <div>")
}
}
第4步:将index.html添加到jsMain/resources中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MultiplatformTest Sample</title>
</head>
<body>
<div id="root"></div>
<script src="web.js"></script>
</body>
</html>
注意:上面代码片段中提到的 web.js 文件是敏感文件,项目 生成时你需要确保它只是 web.js 否则 您在步骤 1 中创建的folder_name.js
第5步:最后将Web模块添加到settings.gradle.kts文件中
pluginManagement {
repositories {
google()
jcenter()
gradlePluginPortal()
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}
}
rootProject.name = "MultiplatformTest"
include(":android")
include(":desktop")
include(":common")
include(":web") // Note web module is included here
我已经创建了一个存储库,请检查此存储库,您可以将其用作您的项目的模板
存储库链接:https://github.com/PSPanishetti/ComposeMultiplatform
是的,现在可以了。对 IOS 的支持已移至测试版,而 Web 则处于测试版。对于新项目,您可以使用 KMP 向导 https://kmp.jetbrains.com/。
对于现有项目,您可以按照上述启动项目的结构对当前项目进行更改。但我建议将您的旧代码移至这个新项目。
基本上,您需要在
composeApp(从 shared 重命名)模块的
build.gradle
文件中包含以下内容。请注意,该项目使用 WASM 进行 Web 构建。您可以同时使用 JS 和 WASM。这使用基于画布的实现来进行撰写,而不是基于 HTML 的实现。
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidApplication)
alias(libs.plugins.jetbrainsCompose)
alias(libs.plugins.compose.compiler)
}
kotlin {
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
moduleName = "composeApp"
browser {
commonWebpackConfig {
outputFileName = "composeApp.js"
devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply {
static = (static ?: mutableListOf()).apply {
// Serve sources to debug inside browser
add(project.projectDir.path)
}
}
}
}
binaries.executable()
}
androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}
jvm("desktop")
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "ComposeApp"
isStatic = true
}
}
sourceSets {
val desktopMain by getting
androidMain.dependencies {
implementation(compose.preview)
implementation(libs.androidx.activity.compose)
}
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.components.uiToolingPreview)
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
}
}
}
android {
namespace = "com.shreyashkore.kmpwizard"
compileSdk = libs.versions.android.compileSdk.get().toInt()
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
sourceSets["main"].res.srcDirs("src/androidMain/res")
sourceSets["main"].resources.srcDirs("src/commonMain/resources")
defaultConfig {
applicationId = "com.shreyashkore.kmpwizard"
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 1
versionName = "1.0"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
buildFeatures {
compose = true
}
dependencies {
debugImplementation(compose.uiTooling)
}
}
compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "com.shreyashkore.kmpwizard"
packageVersion = "1.0.0"
}
}
}