把开源的世界,搬进鸿蒙的房间【鸿蒙心迹】

摘要:一个为 Android 和 iOS 设计的三方库,硬搬进鸿蒙到底值不值得?本文记录了我把 Kotlin Multiplatform 生态里的好库适配到 ArkTS 的这趟心路:适配不是逐行翻译,而是在语义层不动、在引擎层搭桥。文中以网络库
net-lite为例,给出公开接口定义与 ArkTS 侧引擎实现的完整代码,说明"语义不变、引擎替换"的关键点,也聊了 ArkTS 严格模式下那些看不见的规矩,以及开源协作让这件事不再是一个人的孤军。
目录
一、深夜的那行红色报错
做跨平台开发这几年,我越来越多地把时间花在一件"搬东西"的事上——把那些为别处设计的好库,搬进鸿蒙的房间。这篇心迹,想说说这趟搬运里,那些卡住又通了的瞬间。
深夜,IDE 里又跳出一行红色报错。我盯着 ArkTS 严格模式给的那句提示,第无数次问自己:把一个为 Android 和 iOS 设计的三方库,硬搬进鸿蒙,到底值不值得。
二、为什么非要自己搬
我日常和 Kotlin Multiplatform、Compose Multiplatform 打交道。这套工具链最迷人的地方,是"一次书写,多端运行"。可当它遇见鸿蒙,遇见 ArkTS 这门更克制、更讲规矩的语言,很多原本顺滑的假设突然就卡住了。
社区里明明有现成的好库——管网络的、管状态的、发本地通知的——它们只是没为鸿蒙准备原生实现。等官方适配?不如自己上手。
三、适配不是翻译,是搭桥
慢慢摸到门道之后,我发现适配不是把代码逐行翻译过去,而是在语义层不动、在引擎层搭一座桥。
库的公开接口是真的接口,我只要在 ArkTS 这边把"引擎"重新实现一遍,让它去调用系统真实的 API:
- 网络交给系统网络栈;
- 通知交给 NotificationKit;
- 状态交给 ArkTS 自己的响应式机制。
这就像给一位只会说外语的客人,配一个懂本地话的翻译——客人要表达的意思不变,落地的口音换了。
光说"搭桥"还是太抽象,拿一个网络库来落地会更清楚。假设社区里有个叫 net-lite 的库,它对外只承诺三件事:发请求、拿响应、出错时给个明确的异常。这三件事就是"语义",无论底层是 OkHttp 还是鸿蒙的系统网络栈,调用方看到的都该是同一副面孔。
先看库的公开接口定义——这部分几乎原样保留,只把 Kotlin 的写法换成 ArkTS 能接受的显式声明:
// 库的公开接口:语义层,跨平台保持一致
// 关键点一:接口签名不变,调用方无需感知底层实现
export interface NetRequest {
url: string;
method: string;
headers: Record<string, string>;
body?: string;
}
export interface NetResponse {
status: number;
headers: Record<string, string>;
body: string;
}
export interface NetError {
code: number;
message: string;
}
// 对外暴露的唯一入口,语义与 Kotlin 版本完全一致
export interface NetClient {
request(req: NetRequest): Promise<NetResponse>;
}
接着是 ArkTS 侧的引擎实现。这里才是真正"换口音"的地方:接口没动,但内部把请求交给了鸿蒙的系统网络栈 @ohos.net.http。
// ArkTS 侧引擎实现:引擎层,替换为鸿蒙系统网络栈
// 关键点二:只替换引擎,不改语义
import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';
import { NetClient, NetRequest, NetResponse, NetError } from './NetTypes';
export class HarmonyNetClient implements NetClient {
// 语义不变:入参 NetRequest,出参 Promise<NetResponse>
async request(req: NetRequest): Promise<NetResponse> {
const httpRequest = http.createHttp();
try {
// 引擎替换:真正干活的是系统网络栈,而不是 OkHttp
const resp = await httpRequest.request(req.url, {
method: this.mapMethod(req.method),
header: req.headers,
extraData: req.body,
connectTimeout: 10000,
readTimeout: 10000
});
// 把系统返回的原始结构,翻译回库约定的 NetResponse
return {
status: resp.responseCode as number,
headers: resp.header as Record<string, string>,
body: resp.result as string
};
} catch (e) {
// 语义不变:错误也统一收敛成 NetError,调用方无需区分平台
const err = e as BusinessError;
const netError: NetError = {
code: err.code,
message: err.message
};
throw netError;
} finally {
// 系统资源要显式释放,这是 ArkTS 侧多出来的一步
httpRequest.destroy();
}
}
// 方法名映射:库的语义 -> 系统枚举,属于引擎层的适配细节
private mapMethod(method: string): http.RequestMethod {
switch (method.toUpperCase()) {
case 'POST':
return http.RequestMethod.POST;
case 'PUT':
return http.RequestMethod.PUT;
case 'DELETE':
return http.RequestMethod.DELETE;
default:
return http.RequestMethod.GET;
}
}
}
把这段代码和上面的流程图对照着看,桥的两端就很清楚了:
- 语义不变:
NetClient、NetRequest、NetResponse这些类型一个没改,业务代码里client.request(...)的写法在 Kotlin 和 ArkTS 上完全一样; - 引擎替换:
HarmonyNetClient内部换成@ohos.net.http,请求真正落到系统网络栈; - 适配细节收敛在引擎层:方法名映射、超时参数、
destroy()释放资源,这些平台差异全被关在实现类里,不会漏到调用方。
这就是我说的"搭桥":桥面(接口)保持原样,桥墩(引擎)按当地的地基重新打。换一座桥,路还是那条路。
四、难的是那些看不见的规矩
难的是那些看不见的规矩。ArkTS 严格模式下,对象字面量不能随手当类型用,未知类型被直接禁掉,构造参数属性声明也不被允许。一行在 Kotlin 里天经地义的代码,常常要拆成具名接口、改写成显式写法。
有那么几个晚上,我和一个图片解码的字节对齐问题较劲到凌晨,最后发现只是少做了一次 buffer 的切片。那种挫败,和忽然通了的爽快,中间只隔着一行代码。
五、房间亮了
当 demo 工程终于在模拟器上跑出 BUILD SUCCESSFUL,当那几个适配过的库真正在鸿蒙设备上响应点击、弹出通知、拉回数据,我忽然觉得这间房间亮了。
开源世界那么大,而我往鸿蒙的房间里,又搬进了一件趁手的家具。
六、这件事不该是一个人的孤军
最让我安心的是,这件事不该是一个人的孤军。我把适配的代码、踩过的坑、写下的说明,都公开在 AtomGit 上。有人复用,有人指正,有人顺着我的路接着走。
鸿蒙的生态,就是这样一个个被搬进来的房间,慢慢连成的社区。
七、总结
回头看这趟搬运,真正难的从来不是把代码从一种语言抄成另一种语言,而是想清楚哪些东西必须原样保留、哪些东西可以彻底换掉。
- 语义是桥面,必须稳:库的公开接口、类型签名、错误约定,这些是调用方唯一能看见的东西,跨平台就该保持一致。
NetClient在 Kotlin 和 ArkTS 上是同一副面孔,业务代码才不用为平台写两套。 - 引擎是桥墩,可以换:底层是 OkHttp 还是
@ohos.net.http,调用方并不关心。把请求交给系统网络栈、把通知交给 NotificationKit、把状态交给 ArkTS 的响应式机制,换的是地基,不是路。 - 差异要收敛在实现层:方法名映射、超时参数、
destroy()释放资源,这些平台特有的细节全部关在引擎实现类里,一旦漏到调用方,桥就白搭了。 - 规矩要提前摸清:ArkTS 严格模式禁掉了对象字面量当类型、未知类型、构造参数属性声明这些写法,早点把接口拆成具名声明,比事后返工省力得多。
- 别一个人扛:适配的代码、踩过的坑、写下的说明公开在 AtomGit 上,有人复用、有人指正,房间才会一间间连成社区。
如果你手上也有一个想搬进鸿蒙的库,不妨先从它的公开接口看起——把语义钉死,再去实现引擎。桥搭好了,路自然就通了。
更多推荐


所有评论(0)