Kotlin KMM — Share Code between iOS and Android
The iOS and Android versions of an application have a lot in common, today I will show you how to create a shared library of the business logic for iOS and Android using the git submodule for Android and Cocoa-pods for iOS.
prerequisite :
1- android studio version 4.2
2- KMM plugin (open android studio -> preferences -> plugins -> download Kotlin Multiplatform Mobile plugin)
3- build.gradle should have the following under dependencies:
- classpath “com.android.tools.build:gradle:4.2.0-rc01”
- classpath “org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32”
4- MacBook
5- iOS 11+
1- Create android library :
1. Open android studio and create a new project with empty activity.
2. Open the build.gradle
file.
3. Delete the line for the applicationId
.
4.At the top of the file, you should see the following:
apply plugin: 'com.android.application'
- Change it to the following:
apply plugin: 'com.android.library'
Now you have an Android Library .
2- Create KMM Shared Module :
1- Open android studio using the Android Library we Created Above and goto file -> new -> new Module -> KMM shared module.
2- Select the check box for Create PackForXcode Gradle Task and click Finish.
We now have a shared KMM module, this module will allow us to share code between iOS and Android.
3- Add the Lib as git submodule for android
1- Create git repository.
2- Push the files from the Android Library directory we created (the KMM shared module is part of this Library).
3- Open the Android Studio using the app to which you want to add the library.
3- From the terminal (of the Android app) follow these steps :
git submodule add <git repository URL>
git submodule init
4- Open buidl.gradle and add the following under dependencies
implementation project(':KMMSharedModule')
5- Open setting.gradle and add the following :
include ':KMMSharedModule'
Now your Android app can use the shared code.
4- Distribute the KMM shared module using Cocoa-pods
1- Open the android studio using the Android Library we Created Above.
2- Edit the build.gradle.kts file under the KMM shared module so that it looks like this file:
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
kotlin("multiplatform")
id("com.android.library")
}
kotlin {
android()
targets {
ios() {
binaries {
framework {
baseName = "KMMSharedModule"
}
}
}
}
sourceSets {
val commonMain by getting
val androidMain by getting
val iosMain by getting
}
}
android {
compileSdkVersion(29)//Should be like your Android app
defaultConfig {
minSdkVersion(21)// Should be like your Android app
targetSdkVersion(29)//Should be like your Android app
}
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
}//create iOS framework for real device (arm64 only)
val packForXcodeArm by tasks.creating(Sync::class) {
group = "build"
val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
val framework = kotlin.targets.getByName<KotlinNativeTarget>("iosArm64").binaries.getFramework(mode)
inputs.property("mode", mode)
dependsOn(framework.linkTask)
val targetDir = File(buildDir, "xcode-framework-arm")
from({ framework.outputDirectory })
into(targetDir)
}
//create iOS framework for simulators
val packForXcodeX64 by tasks.creating(Sync::class) {
group = "build"
val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
val framework = kotlin.targets.getByName<KotlinNativeTarget>("iosX64").binaries.getFramework(mode)
inputs.property("mode", mode)
dependsOn(framework.linkTask)
val targetDir = File(buildDir, "xcode-framework-X64")
from({ framework.outputDirectory })
into(targetDir)
}
tasks.getByName("build").dependsOn(packForXcodeArm)
tasks.getByName("build").dependsOn(packForXcodeX64)
3- Add this script to the Android library:
This script is to create a .xcframework file from the KMM Shared module, we will publish the .xcframework file with Cocoa-pod.
./gradlew packForXCodeArm -PXCODE_CONFIGURATION=Release
./gradlew packForXCodeX64 -PXCODE_CONFIGURATION=Release
FRAMEWORK_NAME="KMMSharedModule"
ARM64PATH="./KMMSharedModule/build/xcode-framework-arm/${FRAMEWORK_NAME}.framework"
X64PATH="./KMMSharedModule/build/xcode-framework-X64/${FRAMEWORK_NAME}.framework"
UNIVERSAL_PATH="./xcode-frameworks-universal/"
rm -r "${UNIVERSAL_PATH}"
xcodebuild -create-xcframework -framework "${ARM64PATH}" -framework "${X64PATH}" -output "${UNIVERSAL_PATH}/${FRAMEWORK_NAME}.xcframework"
4- create KmmSharedLib.podspec file like this :
Pod::Spec.new do |spec|
spec.name = 'KmmSharedLib'
spec.version = '0.1.0'
spec.homepage = ''
spec.source = { :git => "Android Library git repository URL ", :tag => "#{spec.version}" }
spec.authors = ''
spec.license = ''
spec.summary = ''
spec.static_framework = true
spec.vendored_frameworks = "xcode-frameworks-universal/KMMSharedModule.xcframework"
spec.libraries = "c++"
spec.module_name = "KMMSharedModule_umbrella"
spec.ios.deployment_target = '11.0'
spec.pod_target_xcconfig = {
'KOTLIN_TARGET[sdk=iphonesimulator*]' => 'ios_x64',
'KOTLIN_TARGET[sdk=iphoneos*]' => 'ios_arm',
'KOTLIN_TARGET[sdk=watchsimulator*]' => 'watchos_x64',
'KOTLIN_TARGET[sdk=watchos*]' => 'watchos_arm',
'KOTLIN_TARGET[sdk=appletvsimulator*]' => 'tvos_x64',
'KOTLIN_TARGET[sdk=appletvos*]' => 'tvos_arm64',
'KOTLIN_TARGET[sdk=macosx*]' => 'macos_x64'
}
spec.pod_target_xcconfig = {
'ONLY_ACTIVE_ARCH' => 'YES'
}
end
5- Run the script we created above from the Android library terminal (./script.script).
6- Push all the files into the git repository.
7- add your pod repo , run this line from the terminal :
- pod repo add repoName ”Android Library git repository URL”
8- run pod repo push repoName ${path to the .podspec file} (should be part of the android library).
just add this pod to your pod file in the iOS project and run pod install.
Be sure to run the script from above each time before releasing a new pod version for iOS.