创建跨平台移动应用程序
Ktor HTTP 客户端可用于多平台项目。在本教程中,我们将创建一个简单的 Kotlin Multiplatform Mobile 应用程序,它将发送请求并接收纯 HTML 文本形式的响应体。
要了解如何创建你的第一个 Kotlin Multiplatform Mobile 应用程序,请参阅 创建你的第一个跨平台移动应用。
前提条件
首先,你需要在合适的操作系统上安装必要的工具,以设置跨平台移动开发环境。关于如何执行此操作,请参阅 设置环境 部分。
你需要一台装有 macOS 的 Mac 电脑来完成本教程中的某些步骤,其中包括编写 iOS 特有的代码和运行 iOS 应用程序。
创建新项目
要启动新的 Kotlin Multiplatform 项目,有两种方法可用:
- 你可以在 Android Studio 中从模板创建项目。
- 或者,你可以使用 Kotlin Multiplatform Wizard 来生成新项目。该向导提供了自定义项目设置的选项,例如,你可以选择排除 Android 支持或包含 Ktor Server。
为了本教程的目的,我们将演示从模板创建项目的过程:
- 在 Android Studio 中,选择 File | New | New Project。
- 在项目模板列表中选择 Kotlin Multiplatform App,然后点击 Next。
- 指定你的应用程序名称,然后点击 Next。在本教程中,应用程序名称为
KmmKtor
。 - 在下一页,保留默认设置并点击 Finish 创建新项目。现在,等待项目设置完成。首次执行此操作时,下载和设置所需组件可能需要一些时间。
要查看生成的完整多平台项目结构,请在 Project view 中从 Android 切换到 Project。
配置构建脚本
更新 Kotlin Gradle 插件
打开 gradle/libs.versions.toml
文件并将 Kotlin 版本更新到最新:
kotlin = "2.1.20"
添加 Ktor 依赖项
要在项目中使用 Ktor HTTP 客户端,你需要添加至少两个依赖项:客户端依赖项和引擎依赖项。
在 gradle/libs.versions.toml
文件中添加 Ktor 版本:
[versions]
ktor = "3.2.3"
要使用 Ktor 的 抢先体验预览 版本,你需要添加一个 Space 版本库。
然后,定义 Ktor 客户端和引擎库:
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
要添加这些依赖项,请打开 shared/build.gradle.kts
文件并按照以下步骤操作:
要在公共代码中使用 Ktor 客户端,请将依赖项
ktor-client-core
添加到commonMain
源代码集:kotlinsourceSets { commonMain.dependencies { implementation(libs.ktor.client.core) } }
将每个所需平台的 引擎依赖项 添加到相应的源代码集:
对于 Android,将
ktor-client-okhttp
依赖项添加到androidMain
源代码集:kotlinandroidMain.dependencies { implementation(libs.ktor.client.okhttp) }
对于 Android,你还可以使用 其他引擎类型。
对于 iOS,将
ktor-client-darwin
依赖项添加到iosMain
:kotliniosMain.dependencies { implementation(libs.ktor.client.darwin) }
添加协程
要在 Android 代码 中使用协程,你需要将 kotlinx.coroutines
添加到你的项目:
打开
gradle/libs.versions.toml
文件并指定协程版本和库:kotlin[versions] coroutines = "1.9.0" [libraries] kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
打开
build.gradle.kts
文件并将kotlinx-coroutines-core
依赖项添加到commonMain
源代码集:kotlinsourceSets { commonMain.dependencies { implementation(libs.ktor.client.core) implementation(libs.kotlinx.coroutines.core) } }
然后,打开
androidApp/build.gradle.kts
并添加kotlinx-coroutines-android
依赖项:
implementation(libs.compose.ui)
}
点击 gradle.properties
文件右上角的 Sync Now 以安装添加的依赖项。
更新你的应用程序
共享代码
要更新 Android 和 iOS 之间共享的代码,请打开 shared/src/commonMain/kotlin/com/example/kmmktor/Greeting.kt
文件并将以下代码添加到 Greeting
类:
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()
}
}
Android 代码
要在 Android 代码中调用挂起函数 greeting
,我们将使用 rememberCoroutineScope。
打开 androidApp/src/main/java/com/example/kmmktor/android/MainActivity.kt
文件并按如下方式更新 MainActivity
代码:
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!")
}
}
在创建的作用域内,我们可以调用共享的 greeting
函数并处理可能的异常。
iOS 代码
打开
iosApp/iosApp/iOSApp.swift
文件并更新应用程序的入口点:Swiftimport SwiftUI @main struct iOSApp: App { var body: some Scene { WindowGroup { ContentView(viewModel: ContentView.ViewModel()) } } }
打开
iosApp/iosApp/ContentView.swift
文件并按如下方式更新ContentView
代码:Swiftimport 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" } } } } } }
在 iOS 上,挂起函数
greeting
可作为带回调的函数使用。
在 Android 上启用互联网访问
我们需要做的最后一件事是为 Android 应用程序启用互联网访问。打开 androidApp/src/main/AndroidManifest.xml
文件并使用 uses-permission
元素启用所需权限:
<manifest>
<uses-permission android:name="android.permission.INTERNET" />
<application>
...
</application>
</manifest>
运行你的应用程序
要在 Android 或 iOS 模拟器上运行创建的多平台应用程序,请选择 androidApp 或 iosApp,然后点击 Run。 模拟器应将接收到的 HTML 文档显示为纯文本。