引言:为什么选择 Kuikly Compose 开发鸿蒙应用?
随着鸿蒙生态的快速发展,为这个新平台开发应用已成为许多团队的必选项。然而,学习一门新的语言(ArkTS)和框架(ArkUI)需要成本。如果你是一名 Android 开发者,并且已经熟悉了 Jetpack Compose,那么 Kuikly Compose 让你能够几乎零成本地将 Compose 开发技能直接应用到鸿蒙平台。
本教程将带你一步步使用 Kuikly Compose 开发一个功能完整的计算器应用,并最终运行在鸿蒙设备上。你将亲身体验到 "Write in Kotlin, Run natively on HarmonyOS" 的强大魅力。
一、环境准备与项目创建
1. 前置条件
- 安装 Android Studio(建议最新版本)
- 安装 Kuikly Android Studio 插件
- 配置好鸿蒙开发环境(DevEco Studio,HarmonyOS SDK)
- 一台鸿蒙真机或模拟器
2. 创建 Kuikly 项目
- 在 Android Studio 中,选择
File > New > New Project - 在模板选择中,找到并选择 Kuikly Project Template
- 在项目配置向导中,关键一步:在 DSL 选择 处,务必选择 Compose
- 填写项目名称(例如
HarmonyCalculator),完成项目创建
项目创建成功后,你的工程会包含以下主要模块:
- shared: 核心模块,所有 Kotlin 编写的业务逻辑和 UI 代码
- androidApp: Android 宿主应用
- ohosApp: 鸿蒙(OpenHarmony)宿主应用(本次重点)
- iosApp: iOS 宿主应用
二、使用 Kuikly Compose 编写计算器界面
我们将在 shared 模块的 commonMain 源码目录下进行开发。Kuikly Compose 的 API 与 Jetpack Compose 高度一致。
1. 创建计算器主页面 (CalculatorApp.kt)
在 shared/src/commonMain/kotlin/ 下创建文件:
kotlin
// 导入Kuikly Compose的包,它们与Jetpack Compose的包名非常相似
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.tencent.kuikly.compose.ComposeContainer
import com.tencent.kuikly.core.annotation.Page
// 定义计算器的操作符
sealed class CalculatorAction {
object Clear : CalculatorAction()
object Delete : CalculatorAction()
object Equals : CalculatorAction()
data class Number(val number: Int) : CalculatorAction()
data class Operation(val operation: Char) : CalculatorAction()
}
@Page("Calculator") // 使用@Page注解,这是Kuikly路由系统的关键
class CalculatorApp : ComposeContainer() {
// 使用Compose的状态管理来记录当前输入和计算结果
private var currentInput by mutableStateOf("0")
private var previousInput by mutableStateOf("")
private var currentOperation by mutableStateOf<Char?>(null)
override fun willInit() {
super.willInit()
setContent {
// 设置Compose主题和内容
MaterialTheme {
CalculatorScreen(
currentInput = currentInput,
previousInput = previousInput,
onAction = { handleAction(it) }
)
}
}
}
// 处理计算逻辑
private fun handleAction(action: CalculatorAction) {
when (action) {
is CalculatorAction.Number -> {
if (currentInput == "0") {
currentInput = action.number.toString()
} else {
currentInput += action.number.toString()
}
}
is CalculatorAction.Operation -> {
if (currentInput.isNotEmpty()) {
previousInput = currentInput
currentInput = "0"
currentOperation = action.operation
}
}
CalculatorAction.Equals -> {
if (previousInput.isNotEmpty() && currentOperation != null) {
val prev = previousInput.toDouble()
val current = currentInput.toDouble()
val result = when (currentOperation) {
'+' -> prev + current
'-' -> prev - current
'×' -> prev * current
'÷' -> if (current != 0.0) prev / current else Double.NaN
else -> return
}
currentInput = if (result.isNaN()) "Error"
else if (result % 1 == 0.0) result.toInt().toString()
else result.toString()
previousInput = ""
currentOperation = null
}
}
CalculatorAction.Clear -> {
currentInput = "0"
previousInput = ""
currentOperation = null
}
CalculatorAction.Delete -> {
if (currentInput.length > 1 && currentInput != "Error") {
currentInput = currentInput.dropLast(1)
} else {
currentInput = "0"
}
}
}
}
}
2. 构建计算器 UI 组件
kotlin
// 计算器UI主界面
@Composable
fun CalculatorScreen(
currentInput: String,
previousInput: String,
onAction: (CalculatorAction) -> Unit
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFF000000)) // 黑色背景
) {
// 显示屏区域
DisplaySection(
currentInput = currentInput,
previousInput = previousInput,
modifier = Modifier
.weight(2f)
.fillMaxWidth()
)
// 按钮区域
ButtonSection(onAction = onAction, modifier = Modifier.weight(3f))
}
}
// 显示屏组件
@Composable
fun DisplaySection(
currentInput: String,
previousInput: String,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier.padding(16.dp),
verticalArrangement = Arrangement.Bottom,
horizontalAlignment = Alignment.End
) {
// 显示上一次的计算式
Text(
text = previousInput,
color = Color(0xFF888888),
fontSize = 20.sp,
modifier = Modifier.padding(bottom = 8.dp)
)
// 显示当前输入或结果
Text(
text = currentInput,
color = Color.White,
fontSize = 48.sp,
fontWeight = FontWeight.Light,
maxLines = 1
)
}
}
// 按钮区域组件
@Composable
fun ButtonSection(onAction: (CalculatorAction) -> Unit, modifier: Modifier = Modifier) {
val buttonSpacing = 8.dp
Column(modifier = modifier.padding(16.dp)) {
// 第一行: AC, DEL, 空, ÷
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.spacedBy(buttonSpacing)
) {
CalculatorButton(
text = "AC",
color = Color(0xFFA5A5A5),
onClick = { onAction(CalculatorAction.Clear) }
)
CalculatorButton(
text = "DEL",
color = Color(0xFFA5A5A5),
onClick = { onAction(CalculatorAction.Delete) }
)
Spacer(modifier = Modifier.weight(1f))
CalculatorButton(
text = "÷",
color = Color(0xFFFF9500),
onClick = { onAction(CalculatorAction.Operation('÷')) }
)
}
// 第二行: 7, 8, 9, ×
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.spacedBy(buttonSpacing)
) {
CalculatorButton(text = "7", onClick = { onAction(CalculatorAction.Number(7)) })
CalculatorButton(text = "8", onClick = { onAction(CalculatorAction.Number(8)) })
CalculatorButton(text = "9", onClick = { onAction(CalculatorAction.Number(9)) })
CalculatorButton(
text = "×",
color = Color(0xFFFF9500),
onClick = { onAction(CalculatorAction.Operation('×')) }
)
}
// 第三行: 4, 5, 6, -
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.spacedBy(buttonSpacing)
) {
CalculatorButton(text = "4", onClick = { onAction(CalculatorAction.Number(4)) })
CalculatorButton(text = "5", onClick = { onAction(CalculatorAction.Number(5)) })
CalculatorButton(text = "6", onClick = { onAction(CalculatorAction.Number(6)) })
CalculatorButton(
text = "-",
color = Color(0xFFFF9500),
onClick = { onAction(CalculatorAction.Operation('-')) }
)
}
// 第四行: 1, 2, 3, +
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.spacedBy(buttonSpacing)
) {
CalculatorButton(text = "1", onClick = { onAction(CalculatorAction.Number(1)) })
CalculatorButton(text = "2", onClick = { onAction(CalculatorAction.Number(2)) })
CalculatorButton(text = "3", onClick = { onAction(CalculatorAction.Number(3)) })
CalculatorButton(
text = "+",
color = Color(0xFFFF9500),
onClick = { onAction(CalculatorAction.Operation('+')) }
)
}
// 第五行: 0, 空, ., =
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.spacedBy(buttonSpacing)
) {
CalculatorButton(
text = "0",
modifier = Modifier.weight(2f),
onClick = { onAction(CalculatorAction.Number(0)) }
)
CalculatorButton(text = ".", onClick = { /* 小数点功能扩展 */ })
CalculatorButton(
text = "=",
color = Color(0xFFFF9500),
onClick = { onAction(CalculatorAction.Equals) }
)
}
}
}
// 可复用的计算器按钮组件
@Composable
fun CalculatorButton(
text: String,
color: Color = Color(0xFF333333),
modifier: Modifier = Modifier.weight(1f),
onClick: () -> Unit
) {
Box(
contentAlignment = Alignment.Center,
modifier = modifier
.fillMaxSize()
.aspectRatio(1f)
.background(color, shape = androidx.compose.foundation.shape.CircleShape)
.clickable { onClick() }
) {
Text(
text = text,
color = Color.White,
fontSize = 24.sp,
fontWeight = FontWeight.Medium
)
}
}
三、鸿蒙平台适配与运行
代码写完后,我们需要将其编译并运行到鸿蒙设备上。Kuikly 的强大之处在于,你几乎不需要为鸿蒙平台编写任何额外的 UI 代码。
1. 编译 Kotlin 代码为鸿蒙产物
在终端中,进入项目根目录,执行以下命令,将 Kotlin 代码编译成鸿蒙能够调用的 .so 库和头文件:
bash
./gradlew -c settings.ohos.gradle.kts :shared:linkOhosArm64
2. 配置鸿蒙宿主应用 (ohosApp)
Kuikly 项目模板已经生成好了鸿蒙宿主应用的基本配置。确保:
ohosApp/entry/oh-package.json5中的 Kuikly 渲染器版本与shared/build.gradle.kts中的版本一致- 设备架构配置正确(arm64)
3. 运行鸿蒙应用
- 使用 DevEco Studio 打开
ohosApp目录 - 连接鸿蒙设备或启动模拟器
- 点击运行按钮,DevEco Studio 会自动安装并启动应用
4. 在鸿蒙设备上体验
应用启动后,你将看到一个标准的计算器界面。这个界面由 Kuikly Compose 代码驱动,但最终渲染的是鸿蒙原生的 ArkUI 组件:
- 性能流畅:滚动、触摸反馈与纯鸿蒙应用无异
- 外观原生:字体、布局渲染符合鸿蒙的设计规范
- 交互自然:所有触摸反馈都符合鸿蒙系统的交互标准
四、核心优势总结
通过这个计算器项目,你可以清晰地感受到 Kuikly Compose 开发鸿蒙应用的优势:
🚀 开发效率极高
- 使用熟悉的 Kotlin 和 Compose DSL
- 无需学习 ArkTS/ArkUI 新语法
- 与现有 Android 开发工作流无缝衔接
🔄 代码真正复用
- 同一套 UI 和业务逻辑代码
- 可同时用于 Android、iOS 和鸿蒙三端
- 大幅降低维护成本
⚡ 原生性能保障
- 最终渲染的是平台原生组件
- 无性能损耗,体验流畅
- 直接调用系统底层能力
🔧 无缝热更新
- 结合 Kuikly 的动态化能力
- 未来可轻松实现应用热更新
- 快速迭代,无需重新上架
下一步探索
你现在已经成功使用 Kuikly Compose 创建了第一个鸿蒙应用!可以在此基础上继续探索:
🎨 更复杂的 UI
- 尝试使用
LazyColumn、Pager等复杂布局 - 实现更丰富的动画效果
- 自定义绘制和图形效果
📱 鸿蒙特定能力
- 通过 Kuikly 的 Module 机制调用鸿蒙分布式能力
- 集成传感器、相机等原生 API
- 实现跨设备协同功能
🔍 多端调试
- 在 Android 和 iOS 上运行同一套代码
- 体验真正的跨端开发效率
- 对比不同平台上的运行效果
🛠 工程化优化
- 配置 CI/CD 流水线
- 实现自动化多端构建
- 集成性能监控和分析工具
Kuikly Compose 为 Kotlin 开发者打开了一扇通往鸿蒙乃至全平台开发的大门,让你能专注于业务逻辑本身,而非纠结于不同平台的技术差异。开始你的跨平台开发之旅吧!