了解移动端项目结构

The purpose of the Kotlin Multiplatform technology is unifying the development of applications with common logic for Android and iOS platforms. To make this possible, it uses a mobile-specific structure of Kotlin Multiplatform projects.

This page describes the structure and components of a basic cross-platform mobile project: shared module, Android app, and an iOS app.

This structure isn’t the only possible way to organize your project; however, we recommend it as a starting point.

了解移动端项目结构 - 图1

To view the complete structure of your mobile multiplatform project, switch the view from Android to Project.

Select the Project view

Root project

The root project is a Gradle project that holds the shared module and the Android application as its subprojects. They are linked together via the Gradle multi-project mechanism.

Basic Multiplatform Mobile project structure

【Kotlin】

  1. // settings.gradle.kts
  2. include(":shared")
  3. include(":androidApp")

【Groovy】

  1. // settings.gradle
  2. include ':shared'
  3. include ':androidApp'

The iOS application is produced from an Xcode project. It’s stored in a separate directory within the root project. Xcode uses its own build system; thus, the iOS application project isn’t connected with other parts of the Multiplatform Mobile project via Gradle. Instead, it uses the shared module as an external artifact – framework. For details on integration between the shared module and the iOS application, see iOS application.

This is a basic structure of a cross-platform mobile project:

Basic Multiplatform Mobile project directories

The root project does not hold source code. You can use it to store global configuration in its build.gradle(.kts) or gradle.properties, for example, add repositories or define global configuration variables.

For more complex projects, you can add more modules into the root project by creating them in the IDE and linking via include declarations in the Gradle settings.

Shared module

Shared module contains the core application logic used in both Android and iOS target platforms: classes, functions, and so on. This is a Kotlin Multiplatform module that compiles into an Android library and an iOS framework. It uses the Gradle build system with the Kotlin Multiplatform plugin applied and has targets for Android and iOS.

【Kotlin】

  1. plugins {
  2. kotlin("multiplatform") version "1.9.10"
  3. // ..
  4. }
  5. kotlin {
  6. android()
  7. ios()
  8. }

【Groovy】

  1. plugins {
  2. id 'org.jetbrains.kotlin.multiplatform' version '1.9.10'
  3. //..
  4. }
  5. kotlin {
  6. android()
  7. ios()
  8. }

Source sets

The shared module contains the code that is common for Android and iOS applications. However, to implement the same logic on Android and iOS, you sometimes need to write two platform-specific versions of it. To handle such cases, Kotlin offers the expect/actual mechanism. The source code of the shared module is organized in three source sets accordingly:

  • commonMain stores the code that works on both platforms, including the expect declarations
  • androidMain stores Android-specific parts, including actual implementations
  • iosMain stores iOS-specific parts, including actual implementations

Each source set has its own dependencies. Kotlin standard library is added automatically to all source sets, you don’t need to declare it in the build script.

【Kotlin】

  1. kotlin {
  2. sourceSets {
  3. val commonMain by getting
  4. val androidMain by getting {
  5. dependencies {
  6. implementation("androidx.core:core-ktx:1.2.0")
  7. }
  8. }
  9. val iosMain by getting
  10. // ...
  11. }
  12. }

【Groovy】

  1. kotlin {
  2. sourceSets {
  3. commonMain {
  4. }
  5. androidMain {
  6. dependencies {
  7. implementation 'androidx.core:core-ktx:1.2.0'
  8. }
  9. }
  10. iosMain {
  11. }
  12. // ...
  13. }
  14. }

When you write your code, add the dependencies you need to the corresponding source sets. Read Multiplatform documentation on adding dependencies for more information.

Along with *Main source sets, there are three matching test source sets:

  • commonTest
  • androidUnitTest
  • iosTest

Use them to store unit tests for common and platform-specific source sets accordingly. By default, they have dependencies on Kotlin test library, providing you with means for Kotlin unit testing: annotations, assertion functions and other. You can add dependencies on other test libraries you need.

【Kotlin】

  1. kotlin {
  2. sourceSets {
  3. // ...
  4. val commonTest by getting {
  5. dependencies {
  6. implementation(kotlin("test"))
  7. }
  8. }
  9. val androidUnitTest by getting
  10. val iosTest by getting
  11. }
  12. }

【Groovy】

  1. kotlin {
  2. sourceSets {
  3. //...
  4. commonTest {
  5. dependencies {
  6. implementation kotlin('test')
  7. }
  8. }
  9. androidUnitTest {
  10. }
  11. iosTest {
  12. }
  13. }
  14. }

The main and test source sets described above are default. The Kotlin Multiplatform plugin generates them automatically upon target creation. In your project, you can add more source sets for specific purposes. For more information, see Multiplatform DSL reference.

Android library

The configuration of the Android library produced from the shared module is typical for Android projects. To learn about Android libraries creation, see Create an Android library in the Android developer documentation.

To produce the Android library, a separate Gradle plugin is used in addition to Kotlin Multiplatform:

【Kotlin】

  1. plugins {
  2. // ...
  3. id("com.android.library")
  4. }

【Groovy】

  1. plugins {
  2. // ...
  3. id 'com.android.library'
  4. }

The configuration of Android library is stored in the android {} top-level block of the shared module’s build script:

【Kotlin】

  1. android {
  2. // A typical Android configuration, see https://developer.android.com/build for details.
  3. // For example:
  4. namespace = "com.example.kotlinmultiplatformsandbox"
  5. compileSdk = 33
  6. defaultConfig {
  7. minSdk = 24
  8. }
  9. }

【Groovy】

  1. android {
  2. // A typical Android configuration, see https://developer.android.com/build for details.
  3. // For example:
  4. namespace "com.example.kotlinmultiplatformsandbox"
  5. compileSdk 33
  6. defaultConfig {
  7. minSdk 24
  8. }
  9. }

It’s typical for any Android project. You can edit it to suit your needs. To learn more, see the Android developer documentation.

iOS framework

For using in iOS applications, the shared module compiles into a framework – a kind of hierarchical directory with shared resources used on the Apple platforms. This framework connects to the Xcode project that builds into an iOS application.

The framework is produced via the Kotlin/Native compiler. The framework configuration is stored in the ios {} block of the build script within kotlin {}. It defines the output type framework and the string identifier baseName that is used to form the name of the output artifact. Its default value matches the Gradle module name. For a real project, it’s likely that you’ll need a more complex configuration of the framework production. For details, see Multiplatform documentation.

【Kotlin】

  1. kotlin {
  2. // ...
  3. ios {
  4. binaries {
  5. framework {
  6. baseName = "shared"
  7. }
  8. }
  9. }
  10. }

【Groovy】

  1. kotlin {
  2. // ...
  3. ios {
  4. binaries {
  5. framework {
  6. baseName = 'shared'
  7. }
  8. }
  9. }
  10. }

Additionally, there is a Gradle task embedAndSignAppleFrameworkForXcode, that exposes the framework to the Xcode project the iOS application is built from. It uses the iOS application’s project configuration to define the build mode (debug or release) and provide the appropriate framework version to the specified location.

The task is built into the multiplatform plugin. It executes upon each build of the Xcode project to provide the latest version of the framework for the iOS application. For details, see iOS application.

Use the embedAndSignAppleFrameworkForXcode Gradle task with Xcode project builds only; otherwise, you’ll get an error.

了解移动端项目结构 - 图5

Android application

The Android application part of a Multiplatform Mobile project is a typical Android application written in Kotlin. In a basic cross-platform mobile project, it uses two Gradle plugins:

  • Kotlin Android
  • Android Application

【Kotlin】

  1. plugins {
  2. id("com.android.application")
  3. kotlin("android")
  4. }

【Groovy】

  1. plugins {
  2. id 'com.android.application'
  3. id 'org.jetbrains.kotlin.android'
  4. }

To access the shared module code, the Android application uses it as a project dependency.

【Kotlin】

  1. dependencies {
  2. implementation(project(":shared"))
  3. //..
  4. }

【Groovy】

  1. dependencies {
  2. implementation project(':shared')
  3. //..
  4. }

Besides this dependency, the Android application uses the Kotlin standard library (which is added automatically) and some common Android dependencies:

【Kotlin】

  1. dependencies {
  2. //..
  3. implementation("androidx.core:core-ktx:1.2.0")
  4. implementation("androidx.appcompat:appcompat:1.1.0")
  5. implementation("androidx.constraintlayout:constraintlayout:1.1.3")
  6. }

【Groovy】

  1. dependencies {
  2. //..
  3. implementation 'androidx.core:core-ktx:1.2.0'
  4. implementation 'androidx.appcompat:appcompat:1.1.0'
  5. implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
  6. }

Add your project’s Android-specific dependencies to this block. The build configuration of the Android application is located in the android {} top-level block of the build script:

【Kotlin】

  1. android {
  2. compileSdk = 29
  3. defaultConfig {
  4. applicationId = "org.example.androidApp"
  5. minSdk = 24
  6. versionCode = 1
  7. versionName = "1.0"
  8. }
  9. buildTypes {
  10. getByName("release") {
  11. isMinifyEnabled = false
  12. }
  13. }
  14. }

【Groovy】

  1. android {
  2. compileSdk 29
  3. defaultConfig {
  4. applicationId 'org.example.androidApp'
  5. minSdk 24
  6. versionCode 1
  7. versionName '1.0'
  8. }
  9. buildTypes {
  10. 'release' {
  11. minifyEnabled false
  12. }
  13. }
  14. }

It’s typical for any Android project. You can edit it to suit your needs. To learn more, see the Android developer documentation.

iOS application

The iOS application is produced from an Xcode project generated automatically by the New Project wizard. It resides in a separate directory within the root project.

Basic Kotlin Multiplatform Xcode project

For each build of the iOS application, the project obtains the latest version of the framework. To do this, it uses a Run Script build phase that executes the embedAndSignAppleFrameworkForXcode Gradle task from the shared module. This task generates the .framework with the required configuration, depending on the Xcode environment settings, and puts the artifact into the DerivedData Xcode directory.

  • If you have a custom name for the Apple framework, use embedAndSign<Custom-name>AppleFrameworkForXcode as the name for this Gradle task.
  • If you have a custom build configuration that is different from the default Debug or Release, on the Build Settings tab, add the KOTLIN_FRAMEWORK_BUILD_TYPE setting under User-Defined and set it to Debug or Release.

Use the embedAndSignAppleFrameworkForXcode Gradle task with Xcode project builds only; otherwise, you’ll get an error.

了解移动端项目结构 - 图7

Execution of `embedAndSignAppleFrameworkForXcode` in the Xcode project settings

To embed framework into the application and make the declarations from the shared module available in the source code of the iOS application, the following build settings should be configured properly:

  1. Other Linker flags under the Linking section:

    1. $(inherited) -framework shared

    Configuring **Other linker flags** in the Xcode project settings

  2. Framework Search Paths under the Search Paths section:

    1. $(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)

    Configuring **Framework Search Paths** in the Xcode project settings

In other aspects, the Xcode part of a cross-platform mobile project is a typical iOS application project. To learn more about creating iOS application, see the Xcode documentation.