Originally written by Aman Bansal
Create Hello World App with KMM 📱- Android & IOS
Translator: Bingxin said
In mobile development, Android and iOS versions of apps often have a lot in common, and the business logic behind them is basically the same. Download files, read and write databases, get data from remote servers, parse remote data, and so on. So why don’t we just write the business logic code once and share it across different platforms?
With this in mind, Jetbrains came up with the Kotlin Multiplatform Project.
➡️ What is Kotlin Multiplatform Mobile?
Kotlin Multiplatform Mobile (KMM) is a cross-platform Mobile development SDK provided by Jetbrains. With Kotlin’s cross-platform capabilities, you can compile for multiple platforms using a single project.
With KMM, you have flexibility while retaining the benefits of native programming. Use a single code base for business logic code for Android/iOS applications and write platform-specific code only when needed, such as implementing native UI, using platform-specific apis, and so on.
KMM can be seamlessly integrated into your project. Shared code, written in Kotlin, compiled into JVM bytecode using Kotlin/JVM, and compiled into binary using Kotlin/Native, so you can use the KMM business logic module just as you would any other generic class library.
At the time of writing this blog, KMM is still in Alpha and you can start experimenting with sharing business logic code in your applications.
KMM is currently unknown to the general public in mobile development. Jetbrains has developed the KMM plugin for Android Studio to help you quickly set up your KMM project. Plug-ins can also help you write, run, and test shared code.
➡️ Build the HELLO WORLD KMM application step by step
- Install the Kotlin Multiplatform Mobile plug-in on Android Studio. Open Android Studio -> click Configure -> select Plugins
- Select Marketplace in the Plugins section, search for KMM, install and restart Android Studio.
- On the Android Studio homepage, select “Start a New Android Studio Project”.
- On the Select a Project Template page, Select KMM Application.
- Set the project name, minimum SDK, file directory, package name, etc.
Now, you need to wait for the first build of the project, which takes some time to download and set up the necessary components.
Note: The KMM plugin requires you to have at least version 4.0 of the Kotlin plugin
➡️ Run your program
Select the platform you want to Run on from the menu bar, select the device, and click Run
To run iOS apps, you need to install Xcode and emulator.
➡️ Take a look at the code
Android developer? Look familiar? 😎
IOS developer? Looks like an alien? 👽
➡ ️ module
-
Shared module — The Kotlin module, which houses the Common Android/iOS business logic code, is compiled into the Android Library and iOS framework. Build with Gradle.
-
AndroidApp module — The Kotlin module for Android apps. Build with Gradle.
-
IosApp module — Xcode project for building iOS apps.
Project build.gradle. KTS file:
buildscript {
repositories {
gradlePluginPortal()
jcenter()
google()
mavenCentral()
}
dependencies {
classpath("Org. Jetbrains. Kotlin: kotlin - gradle - plugin: 1.4.10")
classpath("Com. Android. Tools. Build: gradle: 4.0.1." ")
}
}
group = "com.aman.helloworldkmm"
version = "1.0 the SNAPSHOT"
repositories {
mavenCentral()
}
Copy the code
➡ ️ Shared module
The shared module contains common code for Android and iOS. However, in order to implement the same logic on Android/iOS, sometimes you have to write two versions of version specific code, such as Bluetooth, Wifi, etc. To handle this, Kotlin provides an Expect /actual mechanism. The source code for the shared module is sorted into three source sets:
commonMain
Stores code that works for all platforms, includingexpect
The statementandroidMain
Stores Android specific code, includingactual
implementationiosMain
Store iOS specific code, includingactual
implementation
Each source set has its own dependencies. The Kotlin library dependencies are automatically added to all source sets and you do not need to declare them in compiled scripts.
build.gradle.kts
The build.gradle. KTS file contains the shared module’s configuration for Android/iOS.
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
kotlin("multiplatform")
id("com.android.library")
id("kotlin-android-extensions")
}
group = "com.aman.helloworldkmm"
version = "1.0 the SNAPSHOT"
repositories {
gradlePluginPortal()
google()
jcenter()
mavenCentral()
}
kotlin {
android()
ios {
binaries {
framework {
baseName = "shared"
}
}
}
sourceSets {
val commonMain by getting
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))}}val androidMain by getting {
dependencies {
implementation("Com. Google. Android. Material: material: 1.2.0")}}val androidTest by getting {
dependencies {
implementation(kotlin("test-junit"))
implementation("Junit: junit: 4.12")}}val iosMain by getting
val iosTest by getting
}
}
android {
compileSdkVersion(29)
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdkVersion(24)
targetSdkVersion(29)
versionCode = 1
versionName = "1.0"
}
buildTypes {
getByName("release") {
isMinifyEnabled = false}}}val packForXcode by tasks.creating(Sync::class) {
group = "build"
val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
val sdkName = System.getenv("SDK_NAME") ?: "iphonesimulator"
val targetName = "ios" + if (sdkName.startsWith("iphoneos")) "Arm64" else "X64"
val framework = kotlin.targets.getByName<KotlinNativeTarget>(targetName).binaries.getFramework(mode)
inputs.property("mode", mode)
dependsOn(framework.linkTask)
val targetDir = File(buildDir, "xcode-frameworks")
from({ framework.outputDirectory })
into(targetDir)
}
tasks.getByName("build").dependsOn(packForXcode)
Copy the code
AndroidApp module build.gradle. KTS file
plugins {
id("com.android.application")
kotlin("android")
id("kotlin-android-extensions")
}
group = "com.aman.helloworldkmm"
version = "1.0 the SNAPSHOT"
repositories {
gradlePluginPortal()
google()
jcenter()
mavenCentral()
}
dependencies {
implementation(project(":shared"))
implementation("Com. Google. Android. Material: material: 1.2.0")
implementation("Androidx. Appcompat: appcompat: 1.2.0")
implementation("Androidx. Constraintlayout: constraintlayout: 1.1.3.")
}
android {
compileSdkVersion(29)
defaultConfig {
applicationId = "com.aman.helloworldkmm.androidApp"
minSdkVersion(24)
targetSdkVersion(29)
versionCode = 1
versionName = "1.0"
}
buildTypes {
getByName("release") {
isMinifyEnabled = false}}}Copy the code
➡️ use the Expect/Actual keyword
Version-specific code is common for cross-platform applications. For example, you might want to know if your app is running on an Android or iOS device and get the device model. To do this, you need to use the Expect /actual keyword.
First, declare an empty class or function in the Common module using the Expect keyword, just as you would create an interface or abstract class. Platform-specific code is then written in all the other modules to implement the corresponding classes or functions, decorated with actual.
Note that if you use Expect, you must provide an actual implementation for the name.
Otherwise, you will get the following error:
➡️ use of Expect/Actual
commonMain
expect class Platform() {
val platform: String
}
Copy the code
androidMain
actual class Platform actual constructor() {
actual val platform: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}
Copy the code
iosMain
import platform.UIKit.UIDevice
actual class Platform {
actual val platform: String = UIDevice.currentDevice.systemName() + "" + UIDevice.currentDevice.systemVersion
}
Copy the code
MainActivity.kt (Android)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val tv: TextView = findViewById(R.id.text_view)
tv.text = "Hello World, ${Platform().platform}!"}}Copy the code
ContentView.swift (iOS)
struct ContentView: View {
var body: some View {
Text("Hello World, "+ Platform().platform)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Copy the code
Congratulations!!!!! You have completed your first KMM app.
➡️ Open source KMM application
- JetBrains/kotlinconf-app
- saket/press
- jarroyoesp/KotlinMultiPlatform
➡️ Available KMM class libraries
AAkira/Kotlin-Multiplatform-Libraries
The translator said
Kotlin’s approach to cross-platform mobile development, which is already a sea of success, allows you to continue to use the platform’s native approach to UI development and “Write once, run everywhere” business logic. Maybe even give yourself a break. Could Flutter one day be used for UIS and Kotlin for business logic?
At the end of the day, developers have to buy it. Don’t know what you think of KMM, leave your thoughts in the comments!
Finally, I would like to advertise a wave of my small column, Android review notes for interviews, so far I have output six articles, interested can give a subscription.
Android review Notes directory
- Chatter task stack, back stack and start mode
- The life cycle of chatter activities
- Grilled steak a Context
- Why not display Dialog using Application Context?
- Can OOM be tried catch?
- OnDestroy () 10 seconds after activity.Finish ()?