引言
我写过Swift(IOS),写过Kotlin(Android),这两年,我也开始写ArkTS(HarmonyOS)
而这次,就来分享一下三个系统开发的不一样~
它们看起来像三兄弟,其实是三个平行宇宙。
infographic compare-binary-horizontal-simple-fold
data
title 三个平台,两种活法
items
- label 鸿蒙的甜
children
- label 一套 ArkUI 通吃多端
desc 手机、平板、PC、车机共用同一套声明式框架
- label 系统能力接口统一
desc 权限、网络、界面都从同一套 Kit 里出来
- label 工程链路闭环
desc DevEco Studio 与方舟编译器同源,少吵构建的架
- label 鸿蒙的苦
children
- label 三方库密度低
desc 很多轮子得自己造,或者等别人移植
- label 严格模式的门槛
desc 存量 JS 库不能直接搬,要按 ArkTS 规则重写
- label 海外市场缺席
desc 用户主要在国外的话,现在不该选它
先看看同一种功能的实现方法
ArkTS(鸿蒙)
@Entry
@Component
struct CounterPage {
@State count: number = 0;
build() {
Column({ space: 12 }) {
Text(`当前计数:${this.count}`)
.fontSize(20)
.fontColor('#182431')
Button('点我 +1')
.onClick(() => {
this.count += 1; // 改状态,UI 自己会跟上
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}SwiftUI(iOS)
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack(spacing: 12) {
Text("当前计数:\(count)")
.font(.system(size: 20))
Button("点我 +1") {
count += 1
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}Jetpack Compose(安卓)
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "当前计数:$count", fontSize = 20.sp)
Button(onClick = { count += 1 }) {
Text("点我 +1")
}
}
}三份代码的骨架几乎一模一样:声明式 UI + 状态驱动。但实际上还是有区别的:
flowchart TB
subgraph IOS["iOS · 精装修房间"]
I1["Swift 语言<br/>ARC 内存管理"] --> I2["SwiftUI / UIKit<br/>苹果自家框架"]
I2 --> I3["Xcode + 模拟器"]
I3 --> I4["App Store<br/>唯一分发口"]
end
subgraph ANDROID["安卓 · 自由市场"]
A1["Kotlin / Java<br/>ART 虚拟机 + GC"] --> A2["Compose / View<br/>厂商可定制"]
A2 --> A3["Android Studio<br/>真机碎片化严重"]
A3 --> A4["Google Play / 各厂商商店"]
end
subgraph HARMONY["鸿蒙 · 一栈通全部终端"]
H1["ArkTS(UI)<br/>+ C/C++(Native)<br/>+ 仓颉(孵化中)"] --> H2["ArkUI 声明式框架<br/>系统统一提供"]
H2 --> H3["DevEco Studio<br/>一套工程多端产物"]
H3 --> H4["应用市场 + 元服务<br/>手机/平板/PC/车机/穿戴"]
end
这张图里最关键的是中间那一层。iOS 和安卓的框架层,是「一家公司/一个社区做出来的 UI 工具包」;鸿蒙的 ArkUI 是「操作系统的一部分」,是系统直接提供给全场景设备的统一渲染与交互层。我认为这是「多端部署」不同于响应式布局的一个关键区别。
ArkTS 不是 TypeScript
在阅读鸿蒙开发文档的时候,我发现有很多 TypeScript 的语法在ArkTS中被严格限制。
// 这些在 .ts 里都合法,在 .ets 里全部报错
let data: any = getData(); // ❌ arkts-no-any-unknown
const obj = { name: 'koharu', age: 15 }; // ❌ arkts-no-untyped-obj-literals
const key = 'name';
console.log(obj[key]); // ❌ 禁止动态属性访问
eval('1 + 1'); // ❌ 禁止 eval
delete obj.name; // ❌ 禁止 delete
把 ArkTS 的严格模式摊成一张表,方便对照:
| 特性 | TypeScript | ArkTS | 为什么禁 |
|---|---|---|---|
any / unknown | 允许 | 禁止 | 编译器要能静态确定每个值的类型,才能提前布局内存 |
as 类型断言 | 允许 | 禁止 | 断言等于「相信我」,而 AOT 编译器不能靠信仰工作 |
| 结构类型 | 允许 | 名义类型 | 结构相同的两个类不能互赋值,必须显式继承 |
| 对象字面量 | 任意写 | 必须有显式类型 | 无类型字面量无法在编译期分配固定内存布局 |
obj[key] 动态访问 | 允许 | 禁止 | 属性访问必须在编译期解析成固定偏移 |
eval / with / delete | 允许 | 禁止 | 它们让「编译期确定一切」这个前提直接失效 |
通过阅读鸿蒙系统的架构介绍,就能知道原因,这样做其实是为了 AOT 编译。
ArkTS 代码会被编译成方舟字节码,再提前编译成本地机器码。要让这件事成立,编译器必须在打包时就知道「这个对象有几个字段、每个字段什么类型、占多少字节」。any 让这件事不可能,delete 让这件事在运行时失效,obj[key] 让属性访问从「查表」变成「算偏移」。
flowchart LR
A["ArkTS 源码<br/>.ets"] --> B["ArkCompiler<br/>静态类型检查"]
B --> C["方舟字节码<br/>.abc"]
C --> D["AOT 提前编译"]
D --> E["本地机器码<br/>启动即执行"]
F["TypeScript 源码"] -.-> G["JIT 边跑边编译<br/>热点才优化"]
对比一下:V8 跑 JS 靠 JIT,热点代码才被优化成机器码,冷启动时边解释边编译;方舟的路线是打包阶段就把优化做完。代价是写代码时必须「像个静态语言」,收益是应用启动更快、内存更可预测。
这其实带来了一个很实在的优点:因为限制多,ArkTS 的报错来得特别早。IDE 在写错的那一刻就知道类型不对。而不是等你点下运行、真机上转三秒圈之后给你一个 undefined is not a function。
状态管理差异,从「钉钉子」到「挂画」
命令式 UI 时代,改一个数字要在三个地方手动同步:数据模型、视图对象、局部刷新调用。漏一个就是「界面没更新」的经典 bug。
声明式把这件事翻了过来:你只描述「数据是什么」和「数据长什么样」,同步由框架负责。三个平台的做法各有风格:
| 平台 | 状态声明 | 传值方式 | 心智模型 |
|---|---|---|---|
| 鸿蒙 ArkUI | @State / @Prop / @Link / @Provide / @Consume | 装饰器标注父子流向 | 「给数据贴上标签,框架按标签决定谁能改」 |
| iOS SwiftUI | @State / @Binding / @Observable | 属性包装器 | 「值语义 + 单向数据流」 |
| 安卓 Compose | remember { mutableStateOf() } | 参数传递 + ViewModel | 「函数式重组,状态提升到调用方」 |
ArkUI 这套装饰器将可修改的权限安排的很好。
@Component
struct ParentView {
@State total: number = 0; // 自己拥有,自己可改
@Provide('theme') theme: string = 'light'; // 向下广播,后代都能取
build() {
Column() {
ChildView({ count: this.total }) // 单向传入,子组件只读
DeepChild() // 深处组件用 @Consume 直接取主题
}
}
}
@Component
struct ChildView {
@Prop count: number; // 父给的值,本地可改但不回传
@Link total: number; // 与父双向绑定,改了父也变
build() {
Button(`加一(${this.count})`)
.onClick(() => { this.total += 1; })
}
}@State 是自留地,@Prop 是单向水管,@Link 是双向水管,@Provide/@Consume 是跨层级广播(类似 React 的 Context,但语法上更重一点)。这套设计比 Compose 的「状态提升」啰嗦,但比 React 时代手动 useContext + useReducer 省心。它把「数据流向」写进了类型系统里,这是 ArkUI 我觉得做得相当漂亮的一个地方。
一个坑:为什么是 struct 而不是 class
如果你有 React 或 Vue 的底子,第一眼看到 ArkUI 一定会卡在这个字上:为什么组件用 struct 声明,而不是 class?
因为 ArkUI 的组件会被反复重新执行。状态一变,框架重新跑一遍 build(),把新描述和旧描述做 diff,只更新变化的那部分。这个模型要求组件本身是「无身份的、可以随时重建的」——用 struct(值语义)表达这件事,比用 class(引用语义)贴切得多。class 意味着你可能有实例字段、有 this 上的可变状态、有生命周期,而这些东西在「重新执行 build」的模型里全是隐患。
另外。ArkUI 的状态管理有 V1 和 V2 两套模型。V1 是 @State / @Prop / @Link 那套装饰器;V2 引入了 @ComponentV2 + @Local / @Param / @Event / @ObservedV2 / @Trace,主要是为了解决 V1 在深层嵌套对象上的观测粒度问题。重点来了:
两套模型不能混用在同一个组件里。
V2 组件里不能出现 V1 装饰器,反过来也一样。虽说是避免两套观测机制互相打架而做的硬性隔离,但确实为开发带来不少小麻烦 /(ㄒoㄒ)/~~
鸿蒙真正的独特之处:一次开发,多端部署
前面说的都是「三种方言」,到这里才是鸿蒙独有的一句话。
它的官方完整表述是十六个字:一次开发、多端部署、可分可合、自由流转。前八个字是界面适配,后八个字是分布式能力。
界面适配这一半,是三层机制叠出来的:
infographic sequence-pyramid-simple
data
title 一次开发多端部署的三层机制
items
- label 交互归一
- label 自适应布局
- label 断点与栅格
theme
palette
- #8b5cf6
- #3b82f6
- #06b6d4
机制一:断点 + 栅格,让「一份布局」自己变形
ArkUI 定义了一套标准断点。单位是 vp(虚拟像素,密度无关)而不是 px:
| 断点 | 宽度范围 | 典型设备 |
|---|---|---|
sm | [0, 320) vp | 小屏手机、手表 |
md | [320, 520) vp | 大屏手机 |
lg | [520, 840) vp | 平板竖屏 |
xl | [840, +∞) vp | 平板横屏、折叠屏展开、PC |
有了断点,栅格布局就能「一份代码、四种长相」:
@Entry
@Component
struct GalleryPage {
@State items: number[] = [1, 2, 3, 4, 5, 6];
build() {
GridRow({
columns: { sm: 4, md: 8, lg: 12 }, // 总列数随断点变
gutter: { x: 12, y: 12 }
}) {
ForEach(this.items, (item: number) => {
GridCol({ span: { sm: 2, md: 4, lg: 3 } }) { // 每个卡片占几列也随断点变
Column() {
Text(`卡片 ${item}`).fontSize(16)
}
.height(96)
.width('100%')
.backgroundColor('#F1F3F5')
.borderRadius(12)
}
})
}
.width('100%')
.padding(16)
}
}手机上一行两列,平板上一行四列。代码里没有一个 if (isTablet)。
要用运行时更细的控制,还能订阅断点变化:
import { mediaQuery } from '@kit.ArkUI';
aboutToAppear() {
const rule = mediaQuery.matchMediaSync('(840vp<=width)');
rule.on('change', (result: mediaQuery.MediaQueryResult) => {
this.isWide = result.matches; // 折叠屏展开的瞬间就能收到
});
}
机制二:自适应布局,让容器自己分配空间
光有断点还不够——折叠屏用户会一边看视频一边拖窗口,宽度是连续变化的,不是离散跳变。所以 ArkUI 还有一层自适应能力:RelativeContainer 做相对约束,layoutWeight 让子元素按权重瓜分剩余空间,Flex 做流式换行。这一层不依赖断点,是连续响应。
Row() {
if (this.isWide) {
Column() { Text('侧边栏') }.width(240)
}
Column() { Text('主内容') }
.layoutWeight(1) // 剩下的空间全给它,不用算具体宽度
}
.width('100%')
机制三:交互归一,一次点击适配五种输入
这层最容易被忽略。
多端意味着同一个按钮会被手指点(手机)、被鼠标点(PC)、被遥控器选中(智慧屏)、被旋钮转(手表)、被语音唤起(车机)。如果每种输入都要单独写事件,那「一次开发」就是空话。
ArkUI 的做法是在组件层面把输入抽象掉:你写 .onClick(),系统负责把触屏 tap、鼠标 click、键盘 Enter、遥控器确认键统一映射过来。你写 .onHover(),PC 上才有鼠标悬停,手机上不触发也不报错。业务代码不需要知道用户在用什么设备。
那「可分可合」是什么
上面三层解决的是「一份 UI 适配多个屏幕」。鸿蒙还多走了一步:一个应用可以拆成多个可独立运行的能力单元。
听起来抽象,看 module.json5 就懂了:
{
"module": {
"name": "entry",
// 这个模块能在哪些设备上安装——打包时会按设备类型分别产出
"deviceTypes": ["phone", "tablet", "2in1", "wearable", "car"],
"abilities": [
{
"name": "EntryAbility",
"exported": true,
"skills": [{ "entities": ["entity.system.home"], "actions": ["action.system.home"] }]
}
]
}
}deviceTypes 里那个 2in1 指的是 PC 形态设备。同一份工程在打包时会按设备类型分别产出安装包,应用市场上不同设备看到的是各自的版本。这就是「一次开发」在工程层面的落地方式。
更进一步是「元服务」——把应用里的一部分能力拆出来,做成免安装、卡片化、可以被系统智能推荐的原子化服务。这跟 iOS 的 App Clips 有点像,区别在于鸿蒙把它当成了系统级的一等公民:服务卡片可以直接放在桌面,可以被小艺建议调度,可以跨设备调用。
但是依然存在缺点
说了这么多好话,必须补一句实话。
「一次开发多端部署」省掉的是重复编写业务逻辑的成本,没有省掉为每种设备设计交互的成本。手机的底部标签栏搬到 PC 上就是灾难,平板的双栏布局在手表上根本放不下。断点和栅格给你的是工具,不是答案——你依然得想清楚「这个功能在手表上应该长什么样」,只不过想清楚之后不用重写一遍。
官方文档里那句「一次开发,多端部署」后面其实还有半句潜台词:一次设计,多端思考。
生态现状
这里聊聊鸿蒙生态,鸿蒙到现在已经7年了,我一直都在关注,这一路走来确实非常不容易,到本文截稿已有8000万设备,但生态上仍然任重而道远。
infographic compare-swot
data
title 鸿蒙生态 SWOT
items
- label 优势 (Strengths)
children
- label 多设备统一框架
- label 系统能力接口一致
- label 国内产业推力真实
- label 劣势 (Weaknesses)
children
- label 三方库密度低
- label 文档质量参差
- label 模拟器体验一般
- label 机会 (Opportunities)
children
- label 全场景设备增量
- label 元服务新形态
- label 仓颉语言生态
- label 威胁 (Threats)
children
- label 海外市场缺位
- label 开发者迁移成本
- label 存量应用适配周期
优点
第一,系统能力的调用被统一了。 这是我最喜欢的一点。在安卓上做一个「长按弹出菜单 + 震动反馈 + 跨应用分享」,你可能要对接三套厂商 API,还要处理各家返回码不一致。鸿蒙上这些能力都从同一套 Kit 里出:@kit.ArkUI 管界面,@kit.AbilityKit 管能力,@kit.NetworkKit 管网络。导入路径统一,文档同一套,返回值风格一致。少了一半的搜索时间。
第二,权限模型是「最小授权」导向的。 鸿蒙把权限分成了 system_grant(装的时候就给)和 user_grant(运行时问用户)两类,并且对敏感权限支持「单次授权」这种粒度。iOS 在这条路上走得很远(隐私清单、App Tracking Transparency),鸿蒙追得很快,安卓相对最松。对用户是好事,对开发者是「必须把授权流程想清楚」的额外工作量。
第三,开发工具是一套闭环。 DevEco Studio、方舟编译器、模拟器、性能分析器、上架流程,全部来自同一家。少了「Android Studio 版本和 Gradle 版本和 Kotlin 版本互相打架」这类玄学调试时间。不用花整个下午跟构建系统吵架,这件事的价值被严重低估了。
第四,国内市场有实打实的推力。 鸿蒙原生应用的适配在国内已经是政务、金融、出行、社交各行业的既定动作,这意味着需求侧是真实的,不是只有极客在自娱自乐。
缺点
第一,三方库生态还薄。 这是最硬的一条。iOS 有 CocoaPods/SPM 十几年攒下来的库,安卓有 Maven Central 和 JitPack,你想找个「带圆角的图片压缩库」大概率有人写过。鸿蒙这边,很多时候答案是「自己写一个」或者「找找有没有人移植过」。
第二,ArkTS 的严格模式让存量 JS 库没法直接搬。 那些依赖动态特性、any、原型链魔改的 npm 包,在 ArkTS 里基本要重写。官方提供了三方库移植的路径,但移植本身是要人力和时间的工作。
第三,文档质量参差。 主流 API 的文档写得很细,连参数取值范围的边界情况都列了;但偏门一点的场景,经常出现「文档只写了一半,剩下的一半要靠社区帖子或读源码」。我在处理一个跨设备数据同步的问题时,最后是靠读一个两年老的论坛回复解决的。
第四,模拟器还不算好用。 冷启动慢,某些系统能力在模拟器上表现和真机不一致——这点上 Xcode 的模拟器依然是行业天花板,安卓的模拟器靠真机兜底,鸿蒙目前只能老老实实插真机测。
第五,海外市场几乎为零。 如果你的用户主要在国外,鸿蒙现在不是一个值得投入的目标平台,这是地理和生态的现实,跟技术好坏无关。
简单对比
| 维度 | iOS | 安卓 | 鸿蒙 |
|---|---|---|---|
| 语言与框架成熟度 | 极高 | 高 | 中(迭代很快) |
| 三方库丰富度 | 极高 | 极高 | 低 |
| 多设备形态统一 | 中(各设备独立 SDK) | 中(Wear/TV 分开) | 高(一套 ArkUI 通吃) |
| 开发工具体验 | 极佳 | 中 | 好 |
| 分发渠道 | 单一(App Store) | 分散 | 较集中(应用市场) |
| 海外市场 | 全球 | 全球 | 基本没有 |
| 学习曲线(有前端基础) | 中 | 中 | 低(但严格模式要适应) |
鸿蒙现在的短板全在「生态密度」上,长处全在「系统统一性」上。 生态密度是可以靠时间和钱堆出来的,系统统一性则是架构决定的、很难后天补的。所以我对它的长期判断偏乐观,对它的短期体验保持清醒。
仓颉:为什么鸿蒙还要再造一门语言
ArkTS 已经能写 UI 了,C/C++ 能写 Native 层,那为什么华为还要花五年时间从零造一门语言?
先给时间线(都是公开信息):仓颉的研发大约从 2019 年开始;2025 年 7 月 31 日,华为在 AtomGit 上正式开源了仓颉的编译器、运行时和标准库;此后仓颉发布了首个 LTS 版本 1.0.0,从「内部语言」变成了可以真正拿来写东西的语言。
它和 ArkTS 的分工
这个问题在官方《鸿蒙编程语言白皮书》里说得很清楚:ArkTS 负责声明式 UI,仓颉负责业务逻辑与系统级能力,两者可以互操作。虽然到截稿时,我依然觉得互操作的开发文档写的奇烂无比。
| 仓颉 | ArkTS | |
|---|---|---|
| 文件后缀 | .cj | .ets |
| 定位 | 通用编程语言 | 声明式 UI 语言 |
| 范式 | 多范式(OOP / FP / 命令式) | 以声明式 UI 为核心 |
| 并发模型 | 用户态线程 + 并发对象 | 单线程事件循环 |
| 内存管理 | 自动 GC(全并发 GC) | 自动 GC |
| 类型系统 | 静态强类型 + 类型推断 | 静态强类型(TS 子集) |
介绍下「用户态线程」。
ArkTS 的并发模型是单线程事件循环——UI 在主线跑,耗时任务丢到 Worker 或 TaskPool 里,跨线程通信要序列化。这是移动端的标准做法(iOS 的 main thread、安卓的主线程 + 协程都是这个思路),但它有个天然限制:并发粒度是被系统框死的。
仓颉直接给了轻量级用户态线程(类似 Go 的 goroutine),再加一层「并发对象」库。它的目标是让你写并发代码时不需要手动加锁:
// 并发对象:多线程访问时由运行时保证安全,不用自己写锁
public class Counter {
private var value: Int64 = 0
public func increase(): Unit {
synchronized(this) {
value += 1
}
}
public func get(): Int64 {
synchronized(this) {
return value
}
}
}再加上仓颉本来就有代数数据类型和模式匹配,写业务逻辑的表达力明显强于 ArkTS:
enum NetworkResult {
| Success(String)
| Failure(Int64, String)
}
func handle(result: NetworkResult): String {
match (result) {
case Success(body) => "拿到数据:${body}"
case Failure(code, msg) where code >= 500 => "服务器打盹了(${code}):${msg}"
case Failure(code, msg) => "请求失败(${code}):${msg}"
}
}这段代码如果翻译成 ArkTS,你得写一个联合类型 + 一层 if 判断 + 手动保证所有分支都处理到。仓颉的 match 在编译期就能告诉你「你漏了一个分支」——类型系统帮你干掉了整整一类 bug。
仓颉还支持 extend,能给已有类型加方法,这点和 Swift 的 extension 很像:
extend String {
public func shout(): String {
return this + "!!!"
}
}
main() {
println("仓颉".shout()) // 仓颉!!!
}我对仓颉的看法
仓颉现在还是「值得学,但不急着用」的状态。
值得学,是因为它的设计很干净。代数数据类型、模式匹配、值类型、用户态线程、extend——这些特性没有一个是新发明,但组合在一起就构成了一门「知道自己在干什么」的语言。它不像某些为了赶风口仓促推出的语言那样塞满半成品特性。
不急着用,是因为工具链和生态还在长。IDE 支持、调试体验、三方库、社区问答量,都处在早期阶段。现在拿它做正式项目,你大概率会成为那个「帮别人踩坑的人」——如果你享受这件事,那正好;如果你只想按时交付,再等一两个版本会更舒服。
LeetCode 中国目前已经支持使用 Cangjie 答题了,对于第一个“中国造”编程语言,我也在积极学习,用仓颉写算法题和练手小工具。
所以一门鸿蒙应用,将来大概会这样分层:
infographic hierarchy-structure
data
title 未来鸿蒙应用的代码分层
desc 三层各司其职,用互操作粘起来
items
- label 界面层
children
- label ArkTS + ArkUI
- label 声明式状态管理
- label 断点与栅格适配
- label 业务层
children
- label 仓颉
children
- label 并发对象
- label 模式匹配
- label 值类型
- label 系统层
children
- label C / C++
- label Native API
未来的看法
一、鸿蒙的差异化会越来越集中在「多设备」上,而不是「单设备」
单设备的 UI 框架,三个平台已经卷到没有明显差距了:声明式、状态驱动、热重载、可视化预览,大家都有。真正拉开距离的是「手机、平板、PC、车机、手表能不能算一台设备」。
flowchart LR
A["现在的鸿蒙<br/>一套代码 + 断点适配<br/>多产物打包"] --> B["正在发生的<br/>自由流转<br/>任务跨设备接力"]
B --> C["目标形态<br/>设备边界消失<br/>算力与屏幕按需调度"]
「自由流转」这个词现在还有点理想主义色彩——真机体验里偶尔会有延迟、会有状态同步不完整。但方向是明确的:当你的手机、平板、车机、手表共享同一套系统底座时,「把任务从这台设备挪到那台设备」应该像拖动一个窗口一样自然。这是 iOS 和安卓在架构上做不到的事——它们的设备之间隔着不同的系统版本、不同的框架、不同的账号体系。作为新生的系统,这是非常好的优势。
二、AI 会从「一个功能」变成「一层能力」
以前做 AI 功能,是应用里加一个「智能助手」入口,接一个 API,用户点进去问问题。鸿蒙的路线是把 AI 能力下沉到系统层,让应用通过系统接口拿到智能能力,而不是每个应用都自己接一遍模型。
对开发者的影响很实际:你不需要再自己实现一套意图识别,也不需要为了调用系统级智能去猜接口。当然这也意味着新的适配工作——多了一层系统 API 要学。
三、仓颉和 ArkTS 会长期共存,而不是谁吃掉谁
声明式 UI 和系统级编程的诉求是冲突的。
UI 代码需要的是「快速迭代、热重载、语法糖多、写起来短」;系统级代码需要的是「确定性、零开销抽象、精确的内存与并发控制」。硬要用一门语言同时满足这两边,结果通常是两边都不舒服。Swift 和 SwiftUI 的关系、Kotlin 和 Compose 的关系,都已经证明了这一点:同一个生态里,UI 层和逻辑层可以有不同的语言风格。
sequenceDiagram
participant U as 用户操作
participant A as ArkTS / ArkUI
participant C as 仓颉逻辑层
participant N as C/C++ Native
U->>A: 点击「开始导入」
A->>C: 调用仓颉函数(互操作)
C->>C: 并发解析 + 模式匹配分发
C->>N: 调用底层编解码
N-->>C: 返回结果
C-->>A: 通过状态回传
A-->>U: 界面自动刷新
所以我猜未来的鸿蒙应用长这样:ArkTS 写界面和交互,仓颉写核心业务与并发,C/C++ 留给真正需要抠性能的角落。三层各司其职,用互操作粘起来。
总结
iOS 在追求「同一个体验的极致打磨」,安卓在追求「最大程度的开放自由」,而鸿蒙在追一个更冒险的命题:能不能让一套代码自然地活在所有屏幕尺寸和形态上,并且让这些设备像一台设备一样协作。
它现在做得还不够好——三方库太少,文档偶尔坑人,模拟器让人想砸键盘。但它的短板几乎全是「时间能解决的」,而它的长处是「架构决定的」。这两件事的性质完全不同,前者会变好,后者不会变差。