Ktor 2.3.8 Help

Creating a cross-platform mobile application

The Ktor HTTP client can be used in multiplatform projects. In this tutorial, we'll create a simple Kotlin Multiplatform Mobile application, which sends a request and receives a response body as plain HTML text.

Prerequisites

First, you need to set up an environment for cross-platform mobile development by installing the necessary tools on a suitable operating system. Learn how to do this from the Set up an environment section.

Create a new project

To start a new Kotlin Multiplatform project, there are two approaches available:

  • You can create a project from a template within Android Studio.

  • Alternatively, you can use the Kotlin Multiplatform Wizard to generate a new project. The wizard provides options for customizing your project setup, allowing you to exclude Android support or include a Ktor Server, for instance.

For the sake of this tutorial, we will demonstrate the process of creating a project from a template:

  1. In Android Studio, select File | New | New Project.

  2. Select Kotlin Multiplatform App in the list of project templates, and click Next.

  3. Specify a name for your application, and click Next. In our tutorial, the application name is KmmKtor.

  4. On the next page, leave the default settings and click Finish to create a new project. Now, wait while your project is set up. It may take some time to download and set up the required components when you do this for the first time.

Configure build scripts

Update Kotlin Gradle plugins

Open the gradle/libs.versions.toml file and update the Kotlin version to the latest:

kotlin = "1.9.20"

Add Ktor dependencies

To use the Ktor HTTP client in your project, you need to add at least two dependencies: a client dependency and an engine dependency.

In the gradle/libs.versions.toml file add the Ktor version:

[versions] ktor = "2.3.8"

Then, define the Ktor client and engine libraries:

[libraries] ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }

To add the dependencies, open the shared/build.gradle.kts file and follow the steps below:

  1. To use the Ktor client in common code, add the dependency ktor-client-core to the commonMain source set:

    sourceSets { commonMain.dependencies { implementation(libs.ktor.client.core) } }
  2. Add an engine dependency for each required platform to the corresponding source set:

    • For Android, add the ktor-client-okhttp dependency to the androidMain source set:

      androidMain.dependencies { implementation(libs.ktor.client.okhttp) }

      For Android, you can also use other engine types.

    • For iOS, add the ktor-client-darwin dependency to iosMain:

      iosMain.dependencies { implementation(libs.ktor.client.darwin) }

Add coroutines

To use coroutines in Android code, you need to add kotlinx.coroutines to your project:

  1. Open the gradle/libs.versions.toml file and specify the kotlinx version and libraries:

    [versions] coroutines = "1.7.3" [libraries] kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
  2. Open the build.gradle.kts file and add the kotlinx-coroutines-core dependency to the commonMain source set:

    sourceSets { commonMain.dependencies { implementation(libs.ktor.client.core) implementation(libs.kotlinx.coroutines.core) } }
  3. Then, open the androidApp/build.gradle.kts and add the kotlinx-coroutines-android dependency:

dependencies { implementation(libs.kotlinx.coroutines.android) }

Click Sync Now in the top right corner of the gradle.properties file to install the added dependencies.

Update your application

Shared code

To update code shared between Android and iOS, open the shared/src/commonMain/kotlin/com/example/kmmktor/Greeting.kt file and add the following code to the Greeting class:

package com.example.kmmktor import io.ktor.client.* import io.ktor.client.request.* import io.ktor.client.statement.* class Greeting { private val client = HttpClient() suspend fun greeting(): String { val response = client.get("https://ktor.io/docs/") return response.bodyAsText() } }
  • To create the HTTP client, the HttpClient constructor is called.

  • The suspending greeting function is used to make a request and receive the body of a response as a string value.

Android code

To call the suspending greeting function from the Android code, we'll be using rememberCoroutineScope.

Open the androidApp/src/main/java/com/example/kmmktor/android/MainActivity.kt file and update MainActivity code as follows:

package com.example.kmmktor.android import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.example.kmmktor.Greeting import kotlinx.coroutines.launch class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MyApplicationTheme { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { val scope = rememberCoroutineScope() var text by remember { mutableStateOf("Loading") } LaunchedEffect(true) { scope.launch { text = try { Greeting().greeting() } catch (e: Exception) { e.localizedMessage ?: "error" } } } GreetingView(text) } } } } } @Composable fun GreetingView(text: String) { Text(text = text) } @Preview @Composable fun DefaultPreview() { MyApplicationTheme { GreetingView("Hello, Android!") } }

Inside the created scope, we can call the shared greeting function and handle possible exceptions.

iOS code

  1. Open the iosApp/iosApp/iOSApp.swift file and update the entry point for the application:

    import SwiftUI @main struct iOSApp: App { var body: some Scene { WindowGroup { ContentView(viewModel: ContentView.ViewModel()) } } }
  2. Open the iosApp/iosApp/ContentView.swift file and update ContentView code in the following way:

    import SwiftUI import shared struct ContentView: View { @ObservedObject private(set) var viewModel: ViewModel var body: some View { Text(viewModel.text) } } extension ContentView { class ViewModel: ObservableObject { @Published var text = "Loading..." init() { Greeting().greeting { greeting, error in DispatchQueue.main.async { if let greeting = greeting { self.text = greeting } else { self.text = error?.localizedDescription ?? "error" } } } } } }

    On iOS, the greeting suspending function is available as a function with a callback.

Enable internet access on Android

The final thing we need to do is to enable internet access for the Android application. Open the androidApp/src/main/AndroidManifest.xml file and enable the required permission using the uses-permission element:

<manifest> <uses-permission android:name="android.permission.INTERNET" /> <application> ... </application> </manifest>

Run your application

To run the created multiplatform application on the Android or iOS simulator, select androidApp or iosApp and click Run. The simulator should display the received HTML document as plain text.

Android simulator
iOS simulator
Last modified: 29 November 2023