Migration of Android library to Kotlin Multiplatform
Recently I went through a process of migration with my Android/Kotlin lib, so here is a quick overview with possible issues you may encounter.
Why?
Let’s start with the reason. Nowadays the vast majority of native Android projects are written in Kotlin. And Kotlin can be used beyond Android. So basically you can write your code once and run it on iOS, desktop and other platforms. If you already have your code in Kotlin, it may be quite easy to shift to Multiplatform.
Pitfalls
- First of all it’s necessary to eliminate all Java dependencies (imports) from your code. We just don’t have Java libraries in Kotlin Multiplatform. Of course it may be a huge drawback if your core functionality is related to Android/Java code. In this case you will probably spend some time writing expect/actual connections.
- KMP is still in Beta stage (July 2023). So maybe not everyone can afford this by internal policy. The caption on site states:
“Kotlin Multiplatform is in Beta. It is almost stable, but migration steps may be required in the future. We’ll do our best to minimize any changes you have to make.
” - If you use JitPack for publishing your library, you have to migrate to Maven Central. JitPack is a really easy option but it doesn’t support KMP. The issue is open since 2019: https://github.com/jitpack/jitpack.io/issues/3853
- iOS support. You need a Mac. Documentation says:
“To write iOS-specific code and run an iOS application on a simulated or real device, you’ll need a Mac with macOS. This cannot be performed on other operating systems, such as Microsoft Windows. This is an Apple requirement
”
💡 Hint: This can be partially mitigated by using third-party build systems like GitHub Actions with macOS runner.
The migration
Project modification
I started with a creation of a new Multiplatform Library project as a template in IDEA. This step is described really well in the documentation here. Of course, you can modify your project structure and build scripts manually but in my case, it was easier to just use the template.
After that, I copied my existing Kotlin code into commonMain
folder and then I saw all compatibility errors that needed to be fixed.
In my case there were several issues:
- Absence of System.currentTimeMillis()
function in KMP.
- Absence of Dispatchers.IO
by default.
- No JUnit
for tests.
- No java.util.concurrent.atomic.*
package.
When every issue was solved and tests became green, I deleted almost everything (don’t remove Git files!) from the folder in my original project’s location and copied the new structure into that. Luckily Git was smart enough to detect files movements so in most cases it was an easy-to-read diff.
From JitPack to Maven Central
1. Sonatype
First of all, you need a Sonatype account. And to get it you have to create a task here. More details about account creation here.
If you don’t have a dedicated web-site with a domain, it’s not a problem. You can use your GitHub address instead.
2. GPG Key
Next, you need to create a GPG Key Pair for signing your library. It may be generated in several ways depending on your OS. Don’t forget to upload the public part of your key to the server like this: gpg --keyserver keyserver.ubuntu.com --send-keys 5BEF072A
.
3. Publication script
After the steps above you need to set up your publication script. If you use kts
scripts, this instruction should work for you.
Make sure you don’t add secret files to your Git history. Use
.gitignore
file. And make a separate backup of secret files.
One thing that is missed in the instruction above is that you also have to add a settings.gradle.kts
file with one line: rootProject.name = “convention-plugins”
into convention-plugins folder too because it’s basically a separate Gradle project.
4. Publish to Sonatype
The last step on IDE side is publication. To publish your library you have to invoke publishAllPublicationsToSonatypeRepository
Gradle task.
Here you can face an error that wasn’t described in the instruction above. It may look like: Task ‘:publishIosArm64PublicationToSonatypeRepository’ uses this output of task ‘:signIosX64Publication’ without declaring an explicit or implicit dependency
In this case, you can manually declare dependencies between tasks with dependsOn
function or automate it all at once like it’s suggested in the issue.
5. Release to Maven Central
Log-in into Nexus repository manager and let the system check your publication by pressing “Close” button. If everything is OK — release it to Maven Central via “Release” button. Soon after, everyone will be able to find your library on Maven. Good job!
Extra step. Automation
If you build your library often enough — think about build/publication automation. Nowadays GitHub Actions may be a good choice with a free quota.
Conclusion
Kotlin Multiplatform looks promising and it may be a good idea to increase the reach of your Android library with relatively little effort. It took me 2 evenings to migrate my project to KMP and the only drawback for me is the necessity to do a more complicated release process compared to JitPack.
By the way, here is the library that I’m talking about. If you think about the efficiency of your caching logic, try it:
Thanks for reading!