Takeaway from this article
In this article, you’ll learn why we might need to migrate from Retrofit to Ktor and KAPT to KSP. By the end of this article, you will be able to remove Retrofit and KAPT from the project safely.
. . .
Introduction
This is part 2 in the series of migrations from the Android project to the kotlin multiplatform project. In Part 1, we discussed the KMP technology and the tech stack used in migrating applications to KMP. Then as a first step, we started with dependency injection migration from Hilt to Koin. The following is the link to the article in case you missed it.
In this part of the series, we’ll focus on migrating two main things:
- Android network library Retrofit to purely Kotlin-based Ktor.
- KAPT annotation processor to generate the code to KSP (Kotlin Symbol Processing).
Retrofit is a stable and very popular library in the Android world, but the lack of KMP support leaves me with no choice but to migrate. Ktor is the obvious choice to migrate as it’s built purely with Kotlin and is being maintained by Google. Ktor is more than just another client library for networking, to learn more about it read the following in-depth articles:
Kapt (Kotlin Annotation Processing Tool) enables Java annotation processors usage in Kotlin projects, even when the processors aren’t designed for Kotlin. KSP (Kotlin Symbol Processing) offers a Kotlin-centric alternative to Kapt. Unlike Kapt, KSP directly analyzes Kotlin code, making it up to twice as fast. Additionally, it has a deeper understanding of Kotlin’s language features.
. . .
Retrofit to Ktor Migration
Integration
To integrate ktor into the project add the following lines under the dependencies node in the app module and other modules where you might have to make the network calls.
// Ktor implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") implementation("io.ktor:ktor-client-core:2.3.12") // CIO - for JVM and Android implementation("io.ktor:ktor-client-cio:2.3.12") implementation("io.ktor:ktor-client-content-negotiation:2.3.12") implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.12")
Then add the following line under the plugins section in the project-level gradle file.
id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.23' apply false
Now add the following lines in app/proguard-rules.pro
to make sure Ktor works as expected in release builds even with obfuscation.
# Ktor -keep class io.ktor.** { *; } -keep class kotlinx.coroutines.** { *; } -dontwarn kotlinx.atomicfu.** -dontwarn io.netty.** -dontwarn com.typesafe.** -dontwarn org.slf4j.**
Then remove all the Retrofit-related dependencies and hit the sync now button.
DI Migration
Now we need to update the Koin network and data source modules, replacing the Retrofit with Ktor. Let’s start with the network module, The following is the Retrofit setup of the network module.
val networkModule = module { single<Gson> { GsonFactory.create() } single<Converter.Factory> { GsonConverterFactory.create(get()) } single<OkHttpClient> { OkHttpClientFactory.create() } single<Retrofit> { RetrofitFactory.create( okHttpClient = get(), converterFactory = get(), ) } }
After migration to Ktor, it looks as follows:
val networkModule = module { single<Json> { Json { ignoreUnknownKeys = true isLenient = true prettyPrint = true encodeDefaults = true } } single<HttpClient> { HttpClient(CIO) { install(ContentNegotiation) { get<Json>() } } } }
Now we need to replace the retrofit inject with the Ktor client, as I’ve a single API in the application, I’m replacing the retrofit service interface with Kotr client and requesting with the client directly. But the real-time use of Ktor will be much more complicated with multiple routes and header configuration for which please refer to this article.
Before:
class WizardRemoteDataSource constructor( private val api: RetrofitServiceApi, ): WizardDataSource
After:
class WizardRemoteDataSource constructor( private val httpClient: HttpClient, ): WizardDataSource
That’s all, now the project network module is compatible with kotlin multiplatform.
Job Offers
KAPT to KSP Migration
Before migrating your code to KSP, there are a few important considerations to keep in mind. Since KSP is relatively new, some libraries may not yet support it. However, there’s no need to worry — you can run KSP and Kapt side by side in your project.
It’s worth noting that Kapt is now in maintenance mode, so it’s a good idea to encourage your library providers to upgrade to KSP as soon as possible. Fortunately, many popular libraries like Dagger, Moshi, Room, and others already support KSP. To know more about supported libraries refer to this link.
Now let’s start the migration, I prefer to increase the Kotlin version before integrating KSP, in the project-level gradle upgrade Kotlin plugin.
// Before id 'org.jetbrains.kotlin.android' version '1.8.10' apply false // After id 'org.jetbrains.kotlin.android' version '2.0.0' apply false
Then move to the module-level gradle files starting with the app module, remove the kapt
and add ksp
plugin, have a look:

Then remove all the kapt
references like the following from the gradle:

As a final step replace all the kapt
dependency integration to ksp
as shown below:

Now hit the “sync now” button and then rebuild the project to complete the code generation.
The following are some common issues to look out for stated in the Android Official Documentation:
- Some libraries don’t support the same set of features with kapt and KSP. If your code breaks after migrating, check the library’s documentation.
- KSP has more accurate Kotlin-type information than kapt (for example, about nullability), which means that KSP processors can be more precise about type requirements. This might require some fixes in your source code as well, in addition to updating your build files.
- If you were previously passing in arguments to the annotation processor, you’ll likely need to pass in those arguments to KSP now. Note that the format of the arguments might differ between kapt and KSP. See the KSP documentation and consult the documentation of the library you’re using to learn more.
. . .
This article is previously published on proandroiddev.com.