【KMP for OpenHarmony】-- 在鸿蒙工程中使用 Apollo-Kotlin
02 · 在鸿蒙工程中使用 Apollo-Kotlin
本文讲怎么用:把适配好的 Apollo 引入你的 KMP 鸿蒙工程并发起请求。
假设你已按 01 · 适配 完成适配,或直接使用本文给出的坐标。
一、引入依赖
1.1 配置仓库
settings.gradle.kts 里两个 repositories 块都要加(模板里 mavenLocal() 默认是注释掉的):
pluginManagement {
repositories {
mavenLocal() // ← 适配产物在这里
maven("https://maven.eazytec-cloud.com/nexus/repository/maven-public/")
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositories {
mavenLocal() // ← 别忘了这个
maven("https://maven.eazytec-cloud.com/nexus/repository/maven-public/")
}
}
漏掉任何一处都会报
Could not resolve com.apollographql.apollo:...。
1.2 声明依赖
关键:必须放在 ohosMain,不能放 commonMain。
kotlin {
sourceSets {
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
// ❌ 不要在这里加 apollo!
}
val ohosMain = sourceSets.create("ohosMain").apply {
dependsOn(commonMain.get())
}
ohosMain.dependencies {
api(libs.compose.multiplatform.export)
// ✅ 正确位置
implementation("com.apollographql.apollo:apollo-runtime:4.3.0")
implementation("com.apollographql.apollo:apollo-normalized-cache:4.3.0")
implementation("com.apollographql.apollo:apollo-adapters:4.3.0")
}
}
}
为什么不能放 commonMain?
因为你的工程通常同时有 androidTarget,而 commonMain 必须对所有目标成立。
Apollo 的适配产物只发布了 ohosArm64 变体,Android 侧没有 → 解析失败:
The dependency should target platforms: [android, android, ohosArm64]
Unresolved platforms: [android, android]
判断标准:这个依赖有没有覆盖工程的所有 target?
- 只有 ohos → 放
ohosMain - 全平台都有(如 kotlinx-coroutines)→ 才放
commonMain
1.3 桥接(如果 UI 在 commonMain)
如果 commonMain 里的 UI 要调用 Apollo,用 expect/actual 桥接:
// commonMain —— 只声明能力
expect fun runApolloDemo(): String
// ohosMain —— 真正调用 Apollo
actual fun runApolloDemo(): String {
val engine = DefaultHttpEngine(timeoutMillis = 15_000)
// ...
}
// androidMain —— 占位(保证 commonMain 能解析)
actual fun runApolloDemo(): String = "该演示仅在 HarmonyOS 启用"
二、基础用法
2.1 发一个 HTTP 请求(用 ohos 引擎)
import com.apollographql.apollo.network.http.DefaultHttpEngine
import com.apollographql.apollo.network.http.get
import kotlinx.coroutines.runBlocking
fun fetchSomething(): String = runBlocking {
val engine = DefaultHttpEngine(timeoutMillis = 15_000)
try {
val response = engine.get("https://jsonplaceholder.typicode.com/todos/1").execute()
val body = response.body?.readUtf8() ?: "(empty)"
"HTTP ${response.statusCode}\n$body"
} finally {
engine.close() // 必须关闭,释放连接池
}
}
DefaultHttpEngine()就是我们在适配时新写的 ktor/Curl 实现(CIO 在 Kotlin/Native 上不支持 TLS)。

2.2 构造 ApolloClient
import com.apollographql.apollo.ApolloClient
val client = ApolloClient.Builder()
.serverUrl("https://your-graphql-endpoint/graphql")
.build()
如果要配拦截器、缓存等:
val client = ApolloClient.Builder()
.serverUrl("https://your-endpoint/graphql")
.normalizedCache(MemoryCacheFactory(maxSizeBytes = 10 * 1024 * 1024))
.build()
normalizedCache需要引入apollo-normalized-cache(已在 1.2 中声明)。
2.3 用 BigDecimal 适配器
GraphQL 没有原生的十进制类型,Apollo 提供了 BigDecimal 适配器:
import com.apollographql.apollo.adapter.BigDecimal
val price = BigDecimal("12345.678")
val tax = BigDecimal("1000.322")
val total = price.add(tax) // 13346.000
val doubled = price.multiply(BigDecimal("2")) // 24691.356
鸿蒙上这是纯 Kotlin 实现(unscaled + scale 十进制表示),精度可靠:
println("$price + $tax = $total") // 12345.678 + 1000.322 = 13346.000
println("$price * 2 = $doubled") // 12345.678 * 2 = 24691.356
2.4 时间戳
import com.apollographql.apollo.mpp.currentTimeMillis
val ts = currentTimeMillis() // 毫秒时间戳,POSIX clock_gettime 实现
三、完整可跑示例
下面这段代码在 KMPCMPOHOS 的 ohosMain 里,点按钮即可运行:
package com.goway.kmpcmpohos
import com.apollographql.apollo.ApolloClient
import com.apollographql.apollo.adapter.BigDecimal
import com.apollographql.apollo.mpp.currentTimeMillis
import com.apollographql.apollo.network.http.DefaultHttpEngine
import com.apollographql.apollo.network.http.get
import kotlinx.coroutines.runBlocking
import okio.IOException
actual fun runApolloDemo(): String = buildString {
// ① mpp-utils 的 ohos actual
appendLine("① currentTimeMillis() = ${currentTimeMillis()}")
// ② adapters 的 ohos BigDecimal
val a = BigDecimal("12345.678")
val b = BigDecimal("1000.322")
appendLine("② BigDecimal: $a + $b = ${a.add(b)} ; $a * 2 = ${a.multiply(BigDecimal("2"))}")
// ③ runtime 可构建
appendLine(runCatching {
ApolloClient.Builder().serverUrl("https://jsonplaceholder.typicode.com/todos/1").build()
"③ ApolloClient 构建成功"
}.getOrElse { "③ ApolloClient 构建失败:${it.message}" })
// ④ 真实 HTTP 请求
append(httpEngineDemo())
}
private fun httpEngineDemo(url: String = "https://jsonplaceholder.typicode.com/todos/1"): String = try {
runBlocking {
val engine = DefaultHttpEngine(timeoutMillis = 15_000)
try {
val r = engine.get(url).execute()
"④ HTTP ${r.statusCode} ← $url\n${(r.body?.readUtf8() ?: "").take(280)}"
} finally {
engine.close()
}
}
} catch (e: IOException) {
"④ 网络异常(引擎已正常构建):${e.message}"
} catch (e: Throwable) {
"④ 请求失败:${e::class.simpleName}: ${e.message}"
}
UI 侧(commonMain):
@Composable
private fun ApolloDemoCard() {
var result by remember { mutableStateOf<String?>(null) }
var running by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(12.dp)) {
Text("Apollo-Kotlin(清单 #1)", style = MaterialTheme.typography.titleMedium)
Button(
enabled = !running,
onClick = {
running = true
// 不要在 onClick 里直接 runBlocking:网络请求会阻塞 UI 线程,
// 触发 APP_INPUT_BLOCK / THREAD_BLOCK_3S,应用被系统强杀(闪退)。
scope.launch {
val text = withContext(Dispatchers.Default) {
runCatching { runApolloDemo() }
.getOrElse { "异常:${it.message}" }
}
result = text
running = false
}
},
) { Text(if (running) "运行中…" else "运行 Apollo 演示") }
result?.let { Text(it, style = MaterialTheme.typography.bodySmall) }
}
}
}

四、注意事项
| 项 | 说明 |
|---|---|
| 依赖位置 | 必须在 ohosMain,放 commonMain 会因 Android 缺变体而失败 |
mavenLocal() | settings.gradle.kts 两处都要开 |
| 网络权限 | module.json5 需声明 ohos.permission.INTERNET |
| HTTPS | 鸿蒙默认校验证书;自签证书需额外配置 |
engine.close() | 用完必须关,否则连接池泄漏 |
| 协程 | execute() 是 suspend,需在协程中调用;禁止在 UI 线程 runBlocking,否则输入阻塞会被系统强杀 |
加网络权限
harmonyApp/entry/src/main/module.json5:
{
"module": {
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" }
]
}
}
不加会报
Network is unreachable或直接抛异常。
下一篇:03 · 排障 —— 常见报错速查。
更多推荐



所有评论(0)