diff --git a/client-mpp/README.md b/client-mpp/README.md index 4add8e96..78aec071 100644 --- a/client-mpp/README.md +++ b/client-mpp/README.md @@ -2,7 +2,7 @@ A sample project showing how to use a Ktor client in a [multiplatform application](https://ktor.io/docs/getting-started-ktor-client-multiplatform-mobile.html). ## Running -An application works on the following platforms: `Android`, `iOS`, `JavaScript`, and `macosX64`. To run the application, open it in IntelliJ IDEA and do one of the following: +An application works on the following platforms: `Android`, `iOS`, `JavaScript`, and `macosArm64`. To run the application, open it in IntelliJ IDEA and do one of the following: * To run the Android application, use the `client-mpp.androidApp` [run configuration](https://www.jetbrains.com/help/idea/run-debug-configuration.html) created by IntelliJ IDEA automatically. * To run the iOS application, open the [iosApp](iosApp) directory in Xcode and run it. @@ -10,7 +10,7 @@ An application works on the following platforms: `Android`, `iOS`, `JavaScript`, ``` ./gradlew :jsApp:run ``` -* To run `macosX64`, execute the following command in a project's root directory: +* To run `macosArm64`, execute the following command in a project's root directory: ``` - ./gradlew :macApp:runDebugExecutableNative + ./gradlew :desktopApp:runDebugExecutableDesktop ``` \ No newline at end of file diff --git a/client-mpp/androidApp/build.gradle b/client-mpp/androidApp/build.gradle deleted file mode 100644 index 5bd5da2e..00000000 --- a/client-mpp/androidApp/build.gradle +++ /dev/null @@ -1,34 +0,0 @@ -plugins { - id 'com.android.application' - id 'org.jetbrains.kotlin.android' -} - -dependencies { - implementation project(':shared') - implementation 'com.google.android.material:material:1.4.0' - implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' -} - -android { - compileSdkVersion 31 - defaultConfig { - applicationId "io.ktor.samples.mpp.client" - minSdkVersion 14 - targetSdkVersion 30 - versionCode 1 - versionName "1.0" - } - buildTypes { - release { - minifyEnabled false - } - } - packagingOptions { - exclude 'META-INF/*.kotlin_module' - } - compileOptions { - sourceCompatibility 1.8 - targetCompatibility 1.8 - } -} diff --git a/client-mpp/androidApp/build.gradle.kts b/client-mpp/androidApp/build.gradle.kts new file mode 100644 index 00000000..12e5dc62 --- /dev/null +++ b/client-mpp/androidApp/build.gradle.kts @@ -0,0 +1,35 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") +} + +dependencies { + implementation(project(":shared")) + implementation("com.google.android.material:material:1.12.0") + implementation("androidx.appcompat:appcompat:1.7.0") + implementation("androidx.constraintlayout:constraintlayout:2.2.0") +} + +android { + compileSdk = 34 + defaultConfig { + applicationId = "io.ktor.samples.mpp.client" + minSdk = 21 + targetSdk = 33 + versionCode = 1 + versionName = "1.0" + } + buildTypes { + release { + isMinifyEnabled = false + } + } + packaging { + resources.excludes.add("META-INF/*.kotlin_module") + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + namespace = "io.ktor.samples.mpp.client" +} diff --git a/client-mpp/androidApp/src/main/AndroidManifest.xml b/client-mpp/androidApp/src/main/AndroidManifest.xml index 0a50451c..32bfc032 100644 --- a/client-mpp/androidApp/src/main/AndroidManifest.xml +++ b/client-mpp/androidApp/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ +> @@ -8,7 +8,7 @@ android:allowBackup="true" android:supportsRtl="true" android:theme="@style/AppTheme"> - + diff --git a/client-mpp/build.gradle b/client-mpp/build.gradle.kts similarity index 62% rename from client-mpp/build.gradle rename to client-mpp/build.gradle.kts index 1e99a9d3..5cb6f199 100644 --- a/client-mpp/build.gradle +++ b/client-mpp/build.gradle.kts @@ -5,8 +5,8 @@ buildscript { gradlePluginPortal() } dependencies { - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.20") - classpath("com.android.tools.build:gradle:7.0.4") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0") + classpath("com.android.tools.build:gradle:8.6.1") } } diff --git a/client-mpp/desktopApp/build.gradle.kts b/client-mpp/desktopApp/build.gradle.kts new file mode 100644 index 00000000..888c807e --- /dev/null +++ b/client-mpp/desktopApp/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + id("org.jetbrains.kotlin.multiplatform") +} + +kotlin { + // on Linux X64 + // linuxX64("desktop") + // on Windows x64 + // mingwX64("desktop") + // on MacOs X64 + // macosX64("desktop") + // on MacOS Arm64 + macosArm64("desktop") { + binaries { + executable() + } + } + sourceSets { + nativeMain { + dependencies { + implementation(project(":shared")) + } + } + } +} diff --git a/client-mpp/macApp/src/nativeMain/kotlin/MacMain.kt b/client-mpp/desktopApp/src/nativeMain/kotlin/DesktopMain.kt similarity index 83% rename from client-mpp/macApp/src/nativeMain/kotlin/MacMain.kt rename to client-mpp/desktopApp/src/nativeMain/kotlin/DesktopMain.kt index 7844fd41..a4207d9c 100644 --- a/client-mpp/macApp/src/nativeMain/kotlin/MacMain.kt +++ b/client-mpp/desktopApp/src/nativeMain/kotlin/DesktopMain.kt @@ -4,7 +4,7 @@ import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine fun main() = runBlocking { - val result = suspendCoroutine { continuation -> + val result = suspendCoroutine { continuation -> ApplicationApi().about { continuation.resume(it) } diff --git a/client-mpp/gradle.properties b/client-mpp/gradle.properties index 33467dcd..964007c5 100644 --- a/client-mpp/gradle.properties +++ b/client-mpp/gradle.properties @@ -1,2 +1,10 @@ -android.useAndroidX=true -kotlin.native.binary.memoryModel=experimental \ No newline at end of file +#Kotlin +kotlin.code.style=official +kotlin.daemon.jvmargs=-Xmx2048M + +#Gradle +org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 + +#Android +android.nonTransitiveRClass=true +android.useAndroidX=true \ No newline at end of file diff --git a/client-mpp/gradle/wrapper/gradle-wrapper.properties b/client-mpp/gradle/wrapper/gradle-wrapper.properties index 0d184210..19cfad96 100644 --- a/client-mpp/gradle/wrapper/gradle-wrapper.properties +++ b/client-mpp/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/client-mpp/iosApp/iosApp.xcodeproj/project.pbxproj b/client-mpp/iosApp/iosApp.xcodeproj/project.pbxproj index fe7d12ab..0b19bb93 100644 --- a/client-mpp/iosApp/iosApp.xcodeproj/project.pbxproj +++ b/client-mpp/iosApp/iosApp.xcodeproj/project.pbxproj @@ -15,8 +15,6 @@ 7555FF8B242A565B00829871 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7555FF89242A565B00829871 /* LaunchScreen.storyboard */; }; 7555FF96242A565B00829871 /* iosAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF95242A565B00829871 /* iosAppTests.swift */; }; 7555FFA1242A565B00829871 /* iosAppUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FFA0242A565B00829871 /* iosAppUITests.swift */; }; - 7555FFB2242A642300829871 /* shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7555FFB1242A642300829871 /* shared.framework */; }; - 7555FFB3242A642300829871 /* shared.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7555FFB1242A642300829871 /* shared.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -36,20 +34,6 @@ }; /* End PBXContainerItemProxy section */ -/* Begin PBXCopyFilesBuildPhase section */ - 7555FFB4242A642300829871 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 7555FFB3242A642300829871 /* shared.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ 7555FF7B242A565900829871 /* iosApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iosApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7555FF7E242A565900829871 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -73,7 +57,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7555FFB2242A642300829871 /* shared.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -170,11 +153,10 @@ isa = PBXNativeTarget; buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */; buildPhases = ( - 7555FFB5242A651A00829871 /* ShellScript */, + 7555FFB5242A651A00829871 /* Compile Kotlin Framework */, 7555FF77242A565900829871 /* Sources */, 7555FF78242A565900829871 /* Frameworks */, 7555FF79242A565900829871 /* Resources */, - 7555FFB4242A642300829871 /* Embed Frameworks */, ); buildRules = ( ); @@ -292,7 +274,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 7555FFB5242A651A00829871 /* ShellScript */ = { + 7555FFB5242A651A00829871 /* Compile Kotlin Framework */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -301,13 +283,14 @@ ); inputPaths = ( ); + name = "Compile Kotlin Framework"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "cd \"$SRCROOT/..\"\n./gradlew :shared:packForXCode -PXCODE_CONFIGURATION=${CONFIGURATION}\n"; + shellScript = "if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \\\"YES\\\"\"\n exit 0\nfi\ncd \"$SRCROOT/..\"\n./gradlew :shared:embedAndSignAppleFrameworkForXcode\n"; }; /* End PBXShellScriptBuildPhase section */ diff --git a/client-mpp/jsApp/build.gradle b/client-mpp/jsApp/build.gradle deleted file mode 100644 index 08414c4c..00000000 --- a/client-mpp/jsApp/build.gradle +++ /dev/null @@ -1,15 +0,0 @@ -plugins { - id 'org.jetbrains.kotlin.js' -} - -kotlin { - js(IR) { - browser { - } - binaries.executable() - } -} - -dependencies { - implementation project(':shared') -} diff --git a/client-mpp/jsApp/build.gradle.kts b/client-mpp/jsApp/build.gradle.kts new file mode 100644 index 00000000..a74a82e6 --- /dev/null +++ b/client-mpp/jsApp/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("org.jetbrains.kotlin.multiplatform") +} + +kotlin { + js(IR) { + browser { + } + binaries.executable() + } + + sourceSets { + val jsMain by getting { + dependencies { + implementation(project(":shared")) + } + } + } +} diff --git a/client-mpp/jsApp/src/main/kotlin/JsMain.kt b/client-mpp/jsApp/src/jsMain/kotlin/JsMain.kt similarity index 100% rename from client-mpp/jsApp/src/main/kotlin/JsMain.kt rename to client-mpp/jsApp/src/jsMain/kotlin/JsMain.kt diff --git a/client-mpp/jsApp/src/main/resources/index.html b/client-mpp/jsApp/src/jsMain/resources/index.html similarity index 100% rename from client-mpp/jsApp/src/main/resources/index.html rename to client-mpp/jsApp/src/jsMain/resources/index.html diff --git a/client-mpp/jsApp/src/main/resources/require.min.js b/client-mpp/jsApp/src/jsMain/resources/require.min.js similarity index 100% rename from client-mpp/jsApp/src/main/resources/require.min.js rename to client-mpp/jsApp/src/jsMain/resources/require.min.js diff --git a/client-mpp/macApp/build.gradle b/client-mpp/macApp/build.gradle deleted file mode 100644 index 500be981..00000000 --- a/client-mpp/macApp/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget - -plugins { - id 'org.jetbrains.kotlin.multiplatform' -} - -kotlin { - macosX64('native') { // on macOS - // linuxX64('native') // on Linux - // mingwX64('native') // on Windows - binaries { - executable() - } - } - sourceSets { - nativeMain { - dependencies { - implementation project(':shared') - } - } - } -} diff --git a/client-mpp/settings.gradle b/client-mpp/settings.gradle.kts similarity index 50% rename from client-mpp/settings.gradle rename to client-mpp/settings.gradle.kts index 91910465..185e8900 100644 --- a/client-mpp/settings.gradle +++ b/client-mpp/settings.gradle.kts @@ -4,12 +4,11 @@ pluginManagement { gradlePluginPortal() mavenCentral() } - } -rootProject.name = 'client-mpp' +rootProject.name = "client-mpp" -include(':androidApp') -include(':macApp') -include(':jsApp') -include(':shared') +include(":androidApp") +include(":desktopApp") +include(":jsApp") +include(":shared") diff --git a/client-mpp/shared/build.gradle b/client-mpp/shared/build.gradle deleted file mode 100644 index dea9fb36..00000000 --- a/client-mpp/shared/build.gradle +++ /dev/null @@ -1,106 +0,0 @@ -plugins { - id 'org.jetbrains.kotlin.multiplatform' - id 'com.android.library' -} - -kotlin { - android() - ios { - binaries { - framework { - baseName = 'shared' - } - } - } - macosX64() - js(IR) { - browser() - } - - sourceSets.each { - it.dependencies { - implementation(project.dependencies.enforcedPlatform("io.ktor:ktor-bom:3.0.3")) - } - } - - sourceSets { - commonMain { - dependencies { - implementation "io.ktor:ktor-client-core" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4" - } - } - commonTest { - dependencies { - implementation kotlin('test-common') - implementation kotlin('test-annotations-common') - } - } - androidMain { - dependencies { - implementation 'com.google.android.material:material:1.6.4' - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4" - implementation "io.ktor:ktor-client-android" - } - } - androidTest { - dependencies { - implementation kotlin('test-junit') - implementation 'junit:junit:4.13.2' - } - } - iosMain { - dependencies { - implementation "io.ktor:ktor-client-ios" - } - } - iosTest { - - } - jsMain { - dependencies { - implementation "io.ktor:ktor-client-js" - } - } - macosX64Main { - dependencies { - implementation "io.ktor:ktor-client-core" - implementation "io.ktor:ktor-client-curl" - } - } - } -} - -android { - compileSdkVersion 30 - sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") - defaultConfig { - minSdkVersion 14 - targetSdkVersion 30 - versionCode 1 - versionName "1.0" - } - buildTypes { - release { - minifyEnabled false - } - } - packagingOptions { - exclude 'META-INF/*.kotlin_module' - } -} - -task(packForXcode, type: Sync) { - group = 'build' - def mode = System.getenv('CONFIGURATION') ?: 'DEBUG' - def sdkName = System.getenv('SDK_NAME') ?: 'iphonesimulator' - def targetName = 'ios' + (sdkName.startsWith('iphoneos') ? 'Arm64' : 'X64') - def framework = kotlin.targets[targetName].binaries.getFramework(mode) - inputs.property('mode', mode) - dependsOn(framework.linkTask) - def targetDir = new File(buildDir, 'xcode-frameworks') - from({ framework.outputDirectory }) - into(targetDir) -} - -tasks.getByName('build').dependsOn(packForXcode) diff --git a/client-mpp/shared/build.gradle.kts b/client-mpp/shared/build.gradle.kts new file mode 100644 index 00000000..d4a28ee2 --- /dev/null +++ b/client-mpp/shared/build.gradle.kts @@ -0,0 +1,99 @@ +plugins { + id("org.jetbrains.kotlin.multiplatform") + id("com.android.library") +} + +kotlin { + androidTarget() + + listOf( + iosX64(), + iosArm64(), + iosSimulatorArm64(), + macosX64(), + macosArm64() + ).forEach { iosTarget -> + iosTarget.binaries.framework { + baseName = "shared" + isStatic = true + } + } + + js(IR) { + browser() + } + + sourceSets.forEach { + it.dependencies { + implementation(project.dependencies.enforcedPlatform("io.ktor:ktor-bom:3.0.3")) + } + } + + sourceSets { + commonMain { + dependencies { + implementation("io.ktor:ktor-client-core") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") + } + } + commonTest { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + } + } + androidMain { + dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0") + implementation("io.ktor:ktor-client-android") + } + } + androidUnitTest { + dependencies { + implementation(kotlin("test-junit")) + implementation("junit:junit:4.13.2") + } + } + iosMain { + dependencies { + implementation("io.ktor:ktor-client-ios") + } + } + iosTest { + + } + jsMain { + dependencies { + implementation("io.ktor:ktor-client-js") + } + } + macosArm64Main { + dependencies { + implementation("io.ktor:ktor-client-core") + implementation("io.ktor:ktor-client-curl") + } + } + } +} + +android { + compileSdk = 34 + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + defaultConfig { + minSdk = 19 + lint.targetSdk = 33 + } + buildTypes { + release { + isMinifyEnabled = false + } + } + packaging { + resources.excludes.add("META-INF/*.kotlin_module") + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + namespace = "o.ktor.samples.mpp.client.shared" +} diff --git a/client-mpp/shared/src/androidMain/AndroidManifest.xml b/client-mpp/shared/src/androidMain/AndroidManifest.xml index 1120e180..10728cc7 100644 --- a/client-mpp/shared/src/androidMain/AndroidManifest.xml +++ b/client-mpp/shared/src/androidMain/AndroidManifest.xml @@ -1,2 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/client-mpp/shared/src/commonMain/kotlin/io/ktor/samples/mpp/client/Api.kt b/client-mpp/shared/src/commonMain/kotlin/io/ktor/samples/mpp/client/Api.kt index f15c6e85..ee496aac 100644 --- a/client-mpp/shared/src/commonMain/kotlin/io/ktor/samples/mpp/client/Api.kt +++ b/client-mpp/shared/src/commonMain/kotlin/io/ktor/samples/mpp/client/Api.kt @@ -5,9 +5,7 @@ import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* import kotlinx.coroutines.* -import kotlin.native.concurrent.SharedImmutable -@SharedImmutable internal expect val ApplicationDispatcher: CoroutineDispatcher class ApplicationApi { diff --git a/client-mpp/shared/src/macosX64Main/kotlin/io.ktor/samples.mpp.client/ApplicationDispatcher.kt b/client-mpp/shared/src/macosArm64Main/kotlin/io.ktor/samples.mpp.client/ApplicationDispatcher.kt similarity index 100% rename from client-mpp/shared/src/macosX64Main/kotlin/io.ktor/samples.mpp.client/ApplicationDispatcher.kt rename to client-mpp/shared/src/macosArm64Main/kotlin/io.ktor/samples.mpp.client/ApplicationDispatcher.kt diff --git a/client-mpp/shared/src/macosX64Main/kotlin/io/ktor/samples/mpp/client/ApplicationDispatcher.kt b/client-mpp/shared/src/macosX64Main/kotlin/io/ktor/samples/mpp/client/ApplicationDispatcher.kt new file mode 100644 index 00000000..c71f1fa3 --- /dev/null +++ b/client-mpp/shared/src/macosX64Main/kotlin/io/ktor/samples/mpp/client/ApplicationDispatcher.kt @@ -0,0 +1,5 @@ +package io.ktor.samples.mpp.client + +import kotlinx.coroutines.* + +internal actual val ApplicationDispatcher: CoroutineDispatcher = Dispatchers.Unconfined \ No newline at end of file