主题
第 2 章 环境搭建 & 跑通你的第一个 Kuikly 页面
学习目标:理解 Kuikly 工程的组成(KMP 模块 + 各端宿主壳工程);学会用
create-kuikly-app脚手架 30 秒生成项目;在 Android 模拟器跑出 "Hello Kuikly"。
2.1 先搞清楚:跑一个 Kuikly 工程都需要什么?
Kuikly 不是一个独立的 App,它是嵌入到原生 App 里的 UI 模块。所以一个完整的 Kuikly 工程包含两部分:
┌───────────────────────────────────────────────────────────┐
│ 你的 Kuikly 工程目录 │
├───────────────────────────────────────────────────────────┤
│ │
│ shared/ ← 跨端业务代码(commonMain 写一次) │
│ ├─ commonMain/ │
│ ├─ androidMain/ 各端"差异化"代码(少量) │
│ ├─ iosMain/ │
│ └─ ohosArm64Main/ │
│ │
│ androidApp/ ← Android 宿主壳,集成 shared.aar │
│ iosApp/ ← iOS 宿主壳,集成 shared.framework │
│ ohosApp/ ← 鸿蒙宿主壳,集成 shared.so │
│ h5App/ ← H5 宿主壳,集成 shared.js │
│ miniApp/ ← 小程序宿主壳 │
│ │
└───────────────────────────────────────────────────────────┘📌 生活化类比:Kuikly 工程像「做饭的中央厨房 + 各分店」。
shared是中央厨房,做"标准菜谱"(业务代码);androidApp/iosApp等是分店,按当地口味装修(适配各端 UI 框架),但端上来的菜(页面)来自同一个中央厨房。
2.2 环境准备清单
2.2.1 必装清单(开发 Android 端最低要求)
| 工具 | 版本 | 用途 | 链接 |
|---|---|---|---|
| JDK | 11 或 17(推荐 17) | 编译 Kotlin / Android | https://www.oracle.com/java/technologies/downloads/ |
| Android Studio | Hedgehog 2023.1+ | IDE + Android SDK 管理 | https://developer.android.com/studio |
| Android SDK | API 33+ | 编译目标 | Android Studio 内置 |
| Node.js | 16+ | 跑 create-kuikly-app 脚手架 | https://nodejs.org/ |
| Git | 任何最近版本 | 拉取模板 | https://git-scm.com/ |
2.2.2 按需安装(要做对应平台才装)
| 平台 | 必备工具 | 备注 |
|---|---|---|
| iOS / macOS | Xcode 15+、CocoaPods、XcodeGen | 必须 Mac |
| HarmonyOS | DevEco Studio 5.0+、hvigorw、ohpm | Windows / Mac 都行 |
| 小程序 | 微信开发者工具 | / |
| Web (H5) | 浏览器即可 | / |
2.2.3 环境验证:跑一遍 doctor
create-kuikly-app 脚手架自带健康检查命令:
bash
# 全局装一次脚手架
npm install -g create-kuikly-app
# 验环境
kuikly doctor输出大概长这样:
✔ Node.js 18.17.0
✔ JDK 17.0.5
✔ Android SDK /Users/you/Library/Android/sdk
✔ Gradle 8.4
✔ Git 2.39.0
✔ Xcode 15.2 (iOS only)
✔ XcodeGen 2.39.0
✔ CocoaPods 1.14.3
⚠ DevEco Studio not found ← 你不做鸿蒙就忽略它⚠️ 国内网络注意:
- npm 建议切到淘宝镜像:
npm config set registry https://registry.npmmirror.com/- Gradle 建议在
~/.gradle/init.d/init.gradle.kts加阿里云镜像- Maven 依赖:Kuikly 已切到腾讯镜像
https://mirrors.tencent.com/nexus/repository/maven-tencent/
2.3 第一个工程:kuikly create 30 秒搞定
bash
# 创建一个名叫 MyFirstKuikly 的工程
kuikly create MyFirstKuikly \
--package com.example.kuikly \
--dsl kuikly \
--kotlin-version 2.1.21 \
--kuikly-version 2.16.0这条命令做了什么?
┌──────────────────────────────────────────────────────────┐
│ 1. 拉取 kuikly 模板(Kuikly DSL 版本) │
│ 2. 把模板里 com.example.template 替换成你的 package │
│ 3. 写入指定的 Kotlin 和 Kuikly 版本到 buildSrc │
│ 4. 创建 shared / androidApp 两个模块 │
│ 5. 自动跑 gradle wrapper 准备 Gradle │
└──────────────────────────────────────────────────────────┘工程目录结构:
MyFirstKuikly/
├── settings.gradle.kts ← Gradle 多模块配置
├── build.gradle.kts ← 根项目配置
├── gradle.properties ← Gradle 全局参数
├── buildSrc/ ← 集中管理版本号
│ └── src/main/kotlin/
│ └── KotlinBuildVar.kt ← Kotlin / Kuikly 版本变量
│
├── shared/ ← ★ 你的业务代码主战场
│ ├── build.gradle.kts
│ └── src/
│ ├── commonMain/ ← 跨端共享代码
│ │ └── kotlin/com/example/kuikly/
│ │ └── pages/
│ │ └── HomePage.kt ← 模板生成的首页
│ ├── androidMain/ ← Android 特有代码
│ └── iosMain/ ← iOS 特有代码
│
└── androidApp/ ← Android 宿主壳
├── build.gradle.kts
└── src/main/
├── AndroidManifest.xml
├── java/com/example/kuikly/
│ ├── MainActivity.kt ← Android 入口
│ └── KuiklyApplication.kt ← Application
└── res/ ← Android 资源(图标、字符串)📌 认知升级:工程里有两层"App"概念:
androidApp是 Android 宿主 App(壳),shared模块里的Pager才是 Kuikly 逻辑页面。打开 App 后,宿主先启动,再让 Kuikly 引擎接管某个 Activity 的内容区域,渲染指定的 Pager。
2.4 模板生成的 HomePage 拆解
打开 shared/src/commonMain/kotlin/com/example/kuikly/pages/HomePage.kt:
kotlin
package com.example.kuikly.pages
import com.tencent.kuikly.core.annotations.Page
import com.tencent.kuikly.core.base.Color
import com.tencent.kuikly.core.base.ViewBuilder
import com.tencent.kuikly.core.pager.Pager
import com.tencent.kuikly.core.views.Text
@Page("HomePage")
internal class HomePage : Pager() {
override fun body(): ViewBuilder {
return {
attr {
allCenter()
backgroundColor(Color.WHITE)
}
Text {
attr {
text("Hello Kuikly!")
fontSize(20f)
fontWeightBold()
color(Color(0xFF7F52FFL))
}
}
}
}
}逐行拆开看:
| 行 | 作用 | 通俗解释 |
|---|---|---|
@Page("HomePage") | 注册为可路由页面 | "我叫 HomePage,谁想跳转用这个名字" |
internal class HomePage : Pager() | 继承 Pager 基类 | Pager 就是 Kuikly 的"页面" |
override fun body() | 必须实现的方法 | 返回"页面长啥样"的描述 |
return { ... } | 一个 ViewBuilder 闭包 | 这个闭包告诉 Kuikly 引擎要画啥 |
attr { allCenter(); ... } | 根容器属性 | 子组件居中 + 白色背景 |
Text { attr { ... } } | 文本组件 | 显示 "Hello Kuikly!" |
📌 DSL 三件套:以后写每一个组件都是
组件名 { attr { 样式 } event { 交互 } 子组件 }。第 3 章会专门讲。
2.5 跑起来:从 0 到看见 "Hello Kuikly"
2.5.1 方式 A:脚手架一键运行
bash
cd MyFirstKuikly
kuikly run android # 自动找一个连接的设备/模拟器,编译 + 安装 + 启动如果一切顺利,3-5 分钟后你应该能看到模拟器屏幕中央出现紫色的 "Hello Kuikly!"。
2.5.2 方式 B:用 Android Studio 跑(推荐学习用)
1. Android Studio → Open → 选择 MyFirstKuikly 根目录
2. 等 Gradle Sync 完成(首次 5-10 分钟,下载依赖)
3. 选择 androidApp 配置,点击 ▶ 运行
4. 模拟器/真机弹出 "Hello Kuikly!"💡 Gradle Sync 慢是因为要下载 KMP 工具链 + Kuikly 各模块依赖。首次打开建议挂代理或切镜像。
2.5.3 跑不起来怎么办?常见问题速查
| 错误信息 | 原因 | 解法 |
|---|---|---|
Unsupported Java version | JDK 版本太老 | 换成 JDK 17 |
Could not resolve com.tencent.kuikly:... | Maven 拉不到 | 换腾讯镜像 |
Plugin requires Kotlin 2.x.x | Kotlin 版本不匹配 | 看 buildSrc/KotlinBuildVar.kt 改成模板要求的版本 |
KSP processor not generating sources | KSP 插件没启用 | 检查 shared/build.gradle.kts 有没有 id("com.google.devtools.ksp") |
| 模拟器跑空白 | 路由没注册 | MainActivity.onCreate 里要调 KuiklyCoreEntry.triggerRegisterPages() |
2.6 拆开 Android 宿主:它是怎么打开 Kuikly 页面的?
打开 androidApp/.../MainActivity.kt:
kotlin
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ① 触发 KSP 编译期生成的路由注册代码
KuiklyCoreEntry.triggerRegisterPages()
// ② 跳转到指定的 Pager
val intent = KuiklyActivity.createIntent(
context = this,
pageName = "HomePage", // ★ 跟 @Page("HomePage") 对应
pageData = mapOf<String, Any>(),
)
startActivity(intent)
finish()
}
}整个流程:
App 启动
│
▼
MainActivity.onCreate
│
├─► triggerRegisterPages() ← 把所有 @Page 类登记到路由表
│
▼
startActivity(KuiklyActivity, pageName="HomePage")
│
▼
KuiklyActivity(框架内置)
│
├─► 从路由表查 pageName="HomePage" 对应的类
├─► 反射 / 工厂创建 HomePage 实例
├─► 调用 HomePage.body() 拿到 ViewBuilder
└─► 引擎渲染:BuildTree → RenderTree → Android Native View
│
▼
屏幕显示 "Hello Kuikly!"📌 关键细节:
KuiklyActivity是 Kuikly 框架提供的"通用容器 Activity",所有 Kuikly 页面都跑在它里面。你不需要为每个 Pager 写一个 Activity。这跟 Compose 的setContent {}思路类似。
2.7 改一行代码,立刻看到效果
修改 HomePage.kt:
kotlin
@Page("HomePage")
internal class HomePage : Pager() {
override fun body(): ViewBuilder {
return {
attr {
allCenter()
backgroundColor(Color(0xFF1E1E1EL)) // ← 改成深色背景
}
Text {
attr {
text("Hello Kuikly! ❤️") // ← 加个表情
fontSize(28f) // ← 字号变大
fontWeightBold()
color(Color(0xFFFFA500L)) // ← 改成橙色
}
}
}
}
}重新跑(或用 IDE 的 "Apply Changes"):紫底变深底,文字变橙色 + 加表情。改 → 跑 → 看 → 改,跨端开发的快感就出来了。
2.8 工程认知升级:3 个常见误区
误区 1:「我应该写在 androidApp 里」
错。 androidApp/ 只是宿主壳,不要在里面写业务代码。所有 Pager 都应该写在 shared/src/commonMain/,这样 iOS / 鸿蒙才能复用。
误区 2:「shared 里能直接调用 Android API」
错。 commonMain 是跨端共享代码,不能引用 android.* 的任何类。如果你确实需要平台 API(比如调相机),有两条路:
- 简单需求:在
androidMain/iosMain写actual实现,commonMain 里写expect - 复杂需求:写一个 Module,通过桥接调原生
第 8 章会专门讲。
误区 3:「换平台要重新写代码」
部分错。 大约 90% 的代码(页面布局、状态管理、网络逻辑)写一次就够;约 10% 的"平台特性"(推送、相机、文件系统)需要各端实现。这就是 KMP 的核心理念:"共享你能共享的,差异化你必须差异化的"。
2.9 工具链速查表
┌─────────────────────────────────────────────────────────────┐
│ CLI 命令 作用 │
├─────────────────────────────────────────────────────────────┤
│ kuikly create <name> 创建工程 │
│ kuikly create-page <name> 在工程里加一个新页面 │
│ kuikly create-component <name> 加一个可复用组件 │
│ kuikly build android 编译 Android Debug APK │
│ kuikly build ios 编译 iOS framework │
│ kuikly build h5 编译 H5 bundle │
│ kuikly run android 编译 + 安装 + 启动 Android │
│ kuikly run ios 同上 iOS │
│ kuikly preview 可视化预览 │
│ kuikly screenshot android 快速截屏 │
│ kuikly upgrade 升级 SDK 版本 │
│ kuikly doctor 环境健康检查 │
└─────────────────────────────────────────────────────────────┘💡 所有命令都支持
--json参数输出结构化数据,方便 CI / AI Agent 集成。
2.10 章末小结
★ 第 2 章核心知识图谱 ★
│
┌───────────────────────┼─────────────────────────┐
│ │ │
┌────▼──────┐ ┌────▼─────┐ ┌────▼──────┐
│ 工程结构 │ │ 工具链 │ │ 跑通流程 │
├──────────┤ ├──────────┤ ├──────────┤
│ shared │ │ JDK 17 │ │ create │
│ androidApp│ │ AS Hedgehog│ │ Pager │
│ iosApp │ │ Node 16+ │ │ register │
│ ohosApp │ │ kuikly CLI│ │ run │
└──────────┘ └──────────┘ └──────────┘🎤 2.11 章末面试题(8 道高频题)
Q1. Kuikly 一个完整工程包含哪几个模块?各自职责是什么?
答:典型 Kuikly 工程分两层:
sharedKMP 模块:跨端业务代码主战场。包含commonMain(共享)、androidMain/iosMain(平台差异化)等源码集,编译产物是.aar/.framework/.so等- 各端宿主壳工程:
androidApp、iosApp、ohosApp、h5App、miniApp等,分别用各端原生工具链构建,依赖 shared 的产物,提供 App 入口和宿主能力(推送、生命周期等)
Q2. 为什么 commonMain 里不能直接调 Android API?
答:因为 commonMain 是跨端共享源码集,要被编译到所有平台。Android API(android.content.Context 等)只在 Android 平台存在,写进 commonMain 后 iOS / 鸿蒙编译会找不到符号。
如果业务确实需要平台能力,KMP 提供了两种机制:
expect/actual:在 commonMain 声明接口,各 platformMain 写实现- Module 桥接(Kuikly 推荐):定义一个 Module 接口,原生侧实现并通过
callNative/callKotlin通信
Q3. JDK 用 8、11、17 都行吗?
答:不行。Kuikly 至少需要 JDK 11,推荐 JDK 17。JDK 8 早就被 Kotlin 工具链放弃了。如果环境里有多个 JDK,需要在 Android Studio 的 File → Project Structure → SDK Location → Gradle JDK 里指定。
Q4. KuiklyCoreEntry.triggerRegisterPages() 是干嘛的?为什么必须调?
答:这是 Kuikly 的路由注册入口。
底层原理:Kuikly 用 KSP(Kotlin Symbol Processing)在编译期扫描所有 @Page 注解,生成一个 KuiklyCoreEntry 类,里面有 triggerRegisterPages() 方法,作用是把所有 @Page 类的工厂函数注册到路由表里。
如果不调用这个方法,KuiklyActivity 通过 pageName 找不到对应的 Pager 工厂,会渲染空白页或抛异常。
Q5. kuikly create 和直接 clone 模板有什么区别?
答:CLI 做了几件手工 clone 做不到的事:
- 包名替换:自动把模板里所有
com.example.template改成你指定的 package - 版本注入:把指定的 Kotlin / Kuikly 版本写到
buildSrc/KotlinBuildVar.kt - 可选模块:根据
--h5--miniapp等参数动态生成对应宿主壳 - 环境检查:自动跑 doctor,缺啥提示啥
- Gradle 准备:自动生成 wrapper
Q6. 一个 Kuikly 页面是怎么从代码到屏幕显示的?
答:5 步:
- 编译期:KSP 扫描
@Page→ 生成路由注册代码 - App 启动:调
KuiklyCoreEntry.triggerRegisterPages()把所有 Pager 登记到路由表 - 跳转:宿主调
KuiklyActivity.createIntent(pageName="X")启动通用容器 Activity - 创建 Pager:容器 Activity 从路由表查到 X 对应的工厂,创建 Pager 实例
- 渲染:调
pager.body()拿 ViewBuilder → 生成 BuildTree → RenderTree → 发指令到原生 View 系统
Q7. kuikly run android 和直接 gradle assembleDebug 有什么区别?
答:
gradle assembleDebug只是编译出 APK,不安装、不启动,需要你手动 adb installkuikly run android是一站式:编译 → 找设备 → adb install → adb shell am startkuikly run还做了一些贴心的事:自动找模拟器(没启动就启动)、智能 retry、错误日志高亮
Q8. 如何加快首次 Gradle Sync?
答:3 招:
- 切镜像源:腾讯 / 阿里 / 华为云镜像(在
~/.gradle/init.d/init.gradle.kts配) - 开启 Gradle 守护进程 + 并行:
org.gradle.parallel=true、org.gradle.daemon=true - 启用 KMP 增量编译:
kotlin.mpp.enableGranularSourceSetsMetadata=true
加了这些后,首次 sync 能从 10 分钟压到 3 分钟左右。
下一站 → 第 3 章 · 核心概念 Pager / ViewBuilder / attr-event →
🎬 可视化演示
演示加载缓慢或样式异常?点此在新标签页打开 ↗
💻 示例代码
kotlin
/**
* 第 2 章配套代码 · 模板生成的 HomePage(带详细注释版)
*
* 文件位置:shared/src/commonMain/kotlin/com/example/kuikly/pages/HomePage.kt
*
* 这是 `kuikly create` 模板自动生成的 HomePage,本文件加了大量注释帮助理解。
*
* ⚠ commonMain 里不能 import 任何 android.* 或 ios 的类!
* 所有平台无关的 Kotlin 标准库 + Kuikly 框架是允许的。
*/
package com.example.kuikly.pages
import com.tencent.kuikly.core.annotations.Page
import com.tencent.kuikly.core.base.Color
import com.tencent.kuikly.core.base.ViewBuilder
import com.tencent.kuikly.core.pager.Pager
import com.tencent.kuikly.core.views.Text
// ───────────────────────────────────────────────────────
// @Page 注解的两个常用参数:
// name 页面路由名(必填)
// supportInLocal 是否注册到本地路由表(默认 true)
// ───────────────────────────────────────────────────────
@Page("HomePage")
internal class HomePage : Pager() {
/**
* body() 是 Pager 必须实现的方法。
*
* 返回值是 ViewBuilder(其实就是 () -> Unit 类型的别名),
* Kuikly 引擎会执行这个闭包,把里面的组件描述转成 BuildTree。
*/
override fun body(): ViewBuilder {
return {
// ─────────────────────────────────────
// attr {} 块:根容器的样式 + 布局属性
// allCenter() 所有子组件居中(水平 + 垂直)
// backgroundColor(...) 背景色
//
// 注意:Kuikly 颜色是 Long 类型(注意末尾的 L 不能丢),
// 格式是 0xAARRGGBBL(前 2 位是透明度,后 6 位是 RGB)
// ─────────────────────────────────────
attr {
allCenter()
backgroundColor(Color.WHITE)
}
// ─────────────────────────────────────
// Text 组件:纯文本显示
// text(...) 文字内容
// fontSize(20f) 字号(注意是 Float,要带 f)
// fontWeightBold() 粗体(Kuikly 用方法形式而不是属性赋值)
// color(...) 文字颜色
// ─────────────────────────────────────
Text {
attr {
text("Hello Kuikly!")
fontSize(20f)
fontWeightBold()
color(Color(0xFF7F52FFL)) // Kotlin 紫
}
}
}
}
}kotlin
/**
* 第 2 章配套代码 · Android 宿主壳的 MainActivity
*
* 文件位置:androidApp/src/main/java/com/example/kuikly/MainActivity.kt
*
* 这是宿主 App 的入口,演示如何从原生侧打开一个 Kuikly 页面。
*/
package com.example.kuikly
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
// 注意:以下 import 来自 Kuikly 框架
// import com.tencent.kuikly.android.KuiklyActivity
// import com.tencent.kuikly.core.KuiklyCoreEntry // KSP 编译期生成
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ① 触发 KSP 自动生成的路由注册代码
// 这一行的本质:把所有 @Page 注解的类登记到 Kuikly 的路由表
KuiklyCoreEntry.triggerRegisterPages()
// ② 跳转到指定的 Kuikly Pager
// KuiklyActivity 是框架提供的通用容器,所有 Pager 都跑在它里面
val intent = KuiklyActivity.createIntent(
context = this,
pageName = "HomePage", // 与 @Page("HomePage") 对应
pageData = mapOf<String, Any>( // 可选:传给 Pager 的初始化数据
"userId" to "12345",
"from" to "main_entry",
),
)
startActivity(intent)
// ③ 关闭壳 Activity,避免按返回键回到这里
finish()
}
}
// 仅为示意,真实工程下 KuiklyActivity 来自框架。这里给出"它大概长啥样"
object KuiklyActivity {
fun createIntent(context: Any, pageName: String, pageData: Map<String, Any>): Any {
TODO("框架内置实现")
}
}
object KuiklyCoreEntry {
fun triggerRegisterPages() {
// KSP 在编译期会生成实际实现
// 类似:
// PagerRegistry.register("HomePage") { HomePage() }
// PagerRegistry.register("DetailPage") { DetailPage() }
// ...
}
}bash
#!/bin/bash
# 第 2 章配套脚本 · 一键搭建 Kuikly 开发环境(macOS / Linux)
#
# 使用方法:
# chmod +x setup.sh
# ./setup.sh
set -e
echo "★ Kuikly 环境一键安装脚本"
echo "============================="
# ─────────────────────────────────
# 1. 检查 / 提示安装 JDK
# ─────────────────────────────────
echo ""
echo "[1/5] 检查 JDK..."
if ! command -v java &> /dev/null; then
echo " ✗ 未检测到 JDK"
echo " → 请先安装 JDK 17:https://www.oracle.com/java/technologies/downloads/"
echo " → 或 macOS 用 brew: brew install openjdk@17"
exit 1
fi
JAVA_VER=$(java -version 2>&1 | head -1 | awk -F '"' '{print $2}')
echo " ✔ JDK 版本:$JAVA_VER"
# ─────────────────────────────────
# 2. 检查 / 提示安装 Node
# ─────────────────────────────────
echo ""
echo "[2/5] 检查 Node.js..."
if ! command -v node &> /dev/null; then
echo " ✗ 未检测到 Node"
echo " → 请先安装 Node 16+:https://nodejs.org/"
exit 1
fi
NODE_VER=$(node --version)
echo " ✔ Node 版本:$NODE_VER"
# ─────────────────────────────────
# 3. 切换 npm 镜像(国内加速)
# ─────────────────────────────────
echo ""
echo "[3/5] 切换 npm 到国内镜像..."
npm config set registry https://registry.npmmirror.com/
echo " ✔ npm registry:$(npm config get registry)"
# ─────────────────────────────────
# 4. 全局安装 create-kuikly-app
# ─────────────────────────────────
echo ""
echo "[4/5] 安装 create-kuikly-app..."
npm install -g create-kuikly-app
echo " ✔ kuikly CLI 已安装:$(which kuikly)"
# ─────────────────────────────────
# 5. 配置 Gradle 国内镜像
# ─────────────────────────────────
echo ""
echo "[5/5] 配置 Gradle 全局镜像..."
mkdir -p ~/.gradle/init.d
cat > ~/.gradle/init.d/init.gradle.kts <<'EOF'
allprojects {
repositories {
// 腾讯 Maven 镜像(Kuikly 官方推荐)
maven { url = uri("https://mirrors.tencent.com/nexus/repository/maven-tencent/") }
// 阿里云镜像(通用 fallback)
maven { url = uri("https://maven.aliyun.com/repository/public/") }
maven { url = uri("https://maven.aliyun.com/repository/google/") }
google()
mavenCentral()
}
}
EOF
echo " ✔ Gradle init.gradle.kts 已配置"
# ─────────────────────────────────
# 验证
# ─────────────────────────────────
echo ""
echo "============================="
echo "★ 环境就绪!跑一遍 doctor 看看:"
echo " kuikly doctor"
echo ""
echo "★ 创建你的第一个工程:"
echo " kuikly create MyFirstKuikly --package com.example.myfirst"
echo ""
echo "★ 跑起来:"
echo " cd MyFirstKuikly && kuikly run android"
echo ""