Skip to content

Commit 3f96ac4

Browse files
authored
update: add manual shared module creation (JetBrains#285)
1 parent fb74094 commit 3f96ac4

File tree

2 files changed

+151
-39
lines changed

2 files changed

+151
-39
lines changed
Loading

topics/multiplatform-integrate-in-existing-app.md

Lines changed: 151 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -62,34 +62,151 @@ Your future iOS application will use the same logic, so you should make it cross
6262

6363
### Create a shared module for cross-platform code
6464

65+
> You can find the sample project with the shared module already added
66+
> in the [shared_module](https://github.com/Kotlin/kmp-integration-sample/tree/shared_module) branch of the GitHub repository.
67+
>
68+
{style="tip"}
69+
6570
The cross-platform code that is used for both iOS and Android will be stored in a shared module.
6671
The Kotlin Multiplatform plugin for Android Studio provides a wizard for creating such modules.
6772

6873
Create a shared module and connect it to both the existing Android application and your future iOS application:
6974

7075
1. In Android Studio settings, select the **Advanced Settings** section and turn on the **Enable experimental Multiplatform IDE features** option.
71-
2. Restart Android Studio for the changes to take effect.
72-
3. Add the following lines to the `plugins {}` block of the root `build.gradle.kts` file:
76+
2. Restart Android Studio for the changes to take effect.
77+
3. Select **File** | **New** | **New Module** from the main menu.
78+
4. In the list of templates, select **Java or Kotlin Library**.
79+
Enter the library name `shared` and the package name `com.jetbrains.simplelogin.shared`.
80+
5. Click **Finish**.
81+
The wizard creates a base module that you'll expand into a Kotlin Multiplatform module.
82+
6. In the root `build.gradle.kts` file, replace the contents with the following code to properly apply Gradle plugins:
83+
84+
```kotlin
85+
plugins {
86+
alias(libs.plugins.androidApplication) apply false
87+
alias(libs.plugins.kotlinAndroid) apply false
88+
alias(libs.plugins.kotlinMultiplatform) apply false
89+
alias(libs.plugins.androidLibrary) apply false
90+
}
91+
```
92+
93+
7. In the `shared/build.gradle.kts` file, define the necessary KMP targets.
94+
To do that, replace the contents of the file with the following code:
7395

7496
```kotlin
75-
alias(libs.plugins.kotlinMultiplatform) apply false
76-
alias(libs.plugins.androidLibrary) apply false
97+
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
98+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
99+
100+
plugins {
101+
alias(libs.plugins.kotlinMultiplatform)
102+
alias(libs.plugins.androidLibrary)
103+
}
104+
105+
kotlin {
106+
androidTarget {
107+
@OptIn(ExperimentalKotlinGradlePluginApi::class)
108+
compilerOptions {
109+
jvmTarget.set(JvmTarget.JVM_11)
110+
}
111+
}
112+
113+
listOf(
114+
iosX64(),
115+
iosArm64(),
116+
iosSimulatorArm64()
117+
).forEach { iosTarget ->
118+
iosTarget.binaries.framework {
119+
baseName = "Shared"
120+
isStatic = true
121+
}
122+
}
123+
124+
sourceSets {
125+
commonMain.dependencies {
126+
// Contains your multiplatform dependencies
127+
}
128+
}
129+
}
130+
131+
android {
132+
namespace = "com.jetbrains.simplelogin.shared"
133+
compileSdk = libs.versions.android.compileSdk.get().toInt()
134+
compileOptions {
135+
sourceCompatibility = JavaVersion.VERSION_11
136+
targetCompatibility = JavaVersion.VERSION_11
137+
}
138+
defaultConfig {
139+
minSdk = libs.versions.android.minSdk.get().toInt()
140+
}
141+
}
77142
```
143+
{initial-collapse-state="collapsed" collapsible="true" collapsed-title="kotlin { ... }"}
144+
145+
8. Sync the Gradle files as suggested by the IDE or using the **File** | **Sync Project with Gradle Files** menu item.
146+
147+
9. In the `shared/src` directory, create `androidMain/kotlin`, `commonMain/kotlin`, and `iosMain/kotlin` directories.
148+
10. In the `shared/src` directory, delete the `main` directory.
149+
11. Inside those directories, create packages and files to replicate the following structure:
150+
151+
![Final file structure inside the shared directory](shared-directory-structure.png){width="363"}
152+
153+
12. Add code to the files that you created:
78154

79-
This helps to avoid classloader issues when the Kotlin Multiplatform Gradle plugin is applied in the shared module
80-
that you'll create next.
155+
* For `commonMain/Platform.kt`:
81156

82-
4. Select **File** | **New** | **New Module** from the main menu.
83-
5. In the list of templates, select **Kotlin Multiplatform Shared Module**. Enter the module name `shared` and the package
84-
name `com.jetbrains.simplelogin.shared`.
85-
6. Select **Regular framework** in the **iOS framework distribution** list: this indicates the method you'll use to connect
86-
the shared module to the iOS application.
157+
```kotlin
158+
package com.jetbrains.simplelogin.shared
159+
160+
interface Platform {
161+
val name: String
162+
}
163+
164+
expect fun getPlatform(): Platform
165+
```
166+
* For `commonMain/Greeting.kt`:
167+
168+
```kotlin
169+
package com.jetbrains.simplelogin.shared
170+
171+
class Greeting {
172+
private val platform = getPlatform()
173+
174+
fun greet(): String {
175+
return "Hello, ${platform.name}!"
176+
}
177+
}
178+
```
179+
* For `androidMain/Platform.android.kt`:
180+
181+
```kotlin
182+
package com.jetbrains.simplelogin.shared
183+
184+
import android.os.Build
185+
186+
class AndroidPlatform : Platform {
187+
override val name: String = "Android ${Build.VERSION.SDK_INT}"
188+
}
87189

88-
![Kotlin Multiplatform shared module](multiplatform-mobile-module-wizard.png){width=700}
190+
actual fun getPlatform(): Platform = AndroidPlatform()
191+
```
192+
* For `iosMain/Platform.ios.kt`:
89193

90-
7. Click **Finish**. The wizard creates the Kotlin Multiplatform shared module, updates the configuration files,
91-
and creates sample code that shows the benefits of Kotlin Multiplatform.
92-
8. Check out the newly created `shared` directory to see the code of the generated module.
194+
```kotlin
195+
package com.jetbrains.simplelogin.shared
196+
197+
import platform.UIKit.UIDevice
198+
199+
class IOSPlatform: Platform {
200+
override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
201+
}
202+
203+
actual fun getPlatform(): Platform = IOSPlatform()
204+
```
205+
206+
13. In the `app/build.gradle.kts` file, set the `android.defaultConfig.minSdk` value to 24.
207+
14. Sync the Gradle files as suggested by the IDE or using the **File** | **Sync Project with Gradle Files** menu item.
208+
209+
You can find the resulting state of the project in the [shared_module](https://github.com/Kotlin/kmp-integration-sample/tree/shared_module) branch of the GitHub repository.
93210

94211
If you want to better understand the layout of the resulting project, see [basics of Kotlin Multiplatform project structure](https://kotlinlang.org/docs/multiplatform-discover-project.html).
95212

@@ -98,27 +215,22 @@ If you want to better understand the layout of the resulting project, see [basic
98215
To use cross-platform code in your Android application, connect the shared module to it, move the business logic code
99216
there, and make this code cross-platform.
100217

101-
1. In the `shared/build.gradle.kts` file, ensure that `compileSdk` and `minSdk` are the same as those in
102-
the `app/build.gradle.kts` config of your Android application.
103-
104-
If they're different, update them in the `shared/build.gradle.kts` file. Otherwise, the compiler will report
105-
the version mismatch as an error.
106-
107-
2. Add a dependency on the shared module to the `app/build.gradle.kts` file:
218+
1. Add a dependency on the shared module to the `app/build.gradle.kts` file:
108219

109220
```kotlin
110221
dependencies {
222+
// ...
111223
implementation(project(":shared"))
112224
}
113225
```
114226

115-
3. Synchronize the Gradle files by clicking **Sync Now** in the notification.
227+
2. Sync the Gradle files as suggested by the IDE or using the **File** | **Sync Project with Gradle Files** menu item.
116228

117229
![Synchronize the Gradle files](gradle-sync.png)
118230

119-
4. In the `app/src/main/java/` directory, open the `LoginActivity.kt` file in the `com.jetbrains.simplelogin.androidapp.ui.login`
231+
3. In the `app/src/main/java/` directory, open the `LoginActivity.kt` file in the `com.jetbrains.simplelogin.androidapp.ui.login`
120232
package.
121-
5. To make sure that the shared module is successfully connected to your application, dump the `greet()` function
233+
4. To make sure that the shared module is successfully connected to your application, dump the `greet()` function
122234
result to the log by adding a line to the `onCreate()` method:
123235

124236
```kotlin
@@ -130,12 +242,12 @@ there, and make this code cross-platform.
130242
// ...
131243
}
132244
```
133-
6. Follow Android Studio's suggestions to import missing classes.
134-
7. In the toolbar, select `app` from the dropdown and click **Debug** ![](debug-android.png){width=20}.
245+
5. Follow Android Studio's suggestions to import missing classes.
246+
6. In the toolbar, select `app` from the dropdown and click **Debug** ![](debug-android.png){width=20}.
135247
136248
![App from list to debug](app-list-android.png){width="300"}
137249
138-
8. On the **Logcat** tab, search for `Hello` in the log, and you'll find the greeting from the shared
250+
7. On the **Logcat** tab, search for `Hello` in the log, and you'll find the greeting from the shared
139251
module.
140252

141253
![Greeting from the shared module](shared-module-greeting.png){width="700"}
@@ -358,7 +470,7 @@ Connect your framework to the iOS project manually:
358470
> ```
359471
>
360472
> {style="tip"}
361-
473+
362474
6. Build the project in Xcode. If everything is set up correctly, the project will build successfully.
363475
364476
> If you have a custom build configuration different from the default `Debug` or `Release`, on the **Build Settings**
@@ -387,7 +499,7 @@ Connect your framework to the iOS project manually:
387499
}
388500
}
389501
```
390-
502+
391503
3. Run the app from Xcode to see the result:
392504
393505
![Greeting from the shared module](xcode-iphone-hello.png){width=300}
@@ -413,11 +525,11 @@ Connect your framework to the iOS project manually:
413525
}
414526
}
415527
```
416-
528+
417529
6. Run the Xcode project to see that the iOS app shows the login form. Enter "Jane" for the username and "password" for the password.
418530
The app validates the input using the shared code:
419531
420-
![Simple login application](xcode-iphone-login.png){width=300}
532+
![Simple login application](xcode-iphone-login.png){width=300}
421533
422534
## Enjoy the results – update the logic only once
423535
@@ -445,15 +557,15 @@ and iOS.
445557

446558
2. In Android Studio, add a run configuration for the iOS app:
447559

448-
1. Select **Run | Edit configurations** in the main menu.
560+
1. Select **Run | Edit configurations** in the main menu.
449561

450-
2. To add a new configuration, click the plus sign and choose **iOS Application**.
451-
452-
3. Name the configuration "SimpleLoginIOS".
562+
2. To add a new configuration, click the plus sign and choose **iOS Application**.
453563

454-
4. In the **Xcode project file** field, select the location of the `simpleLoginIOS.xcodeproj` file.
455-
456-
5. Choose a simulation environment in the **Execution target** list and click **OK**.
564+
3. Name the configuration "SimpleLoginIOS".
565+
566+
4. In the **Xcode project file** field, select the location of the `simpleLoginIOS.xcodeproj` file.
567+
568+
5. Choose a simulation environment in the **Execution target** list and click **OK**.
457569

458570
3. Run both the iOS and Android applications from Android Studio to see the changes:
459571

0 commit comments

Comments
 (0)