Flutter 开发鸿蒙 6 应用,祝贺六一儿童节 🎈
使用 Flutter OHOS 分支在 HarmonyOS 6 设备(HUAWEI Mate 60 Pro)上创建并运行一个充满童趣的六一儿童节祝贺应用。
一、背景
六一儿童节到了!作为一名开发者,我想用技术来表达对孩子们的祝福。正好手头有一台 HUAWEI Mate 60 Pro(HarmonyOS 6),于是决定用 Flutter 创建一个鸿蒙应用,既体验 Flutter 在 HarmonyOS 平台上的开发流程,又能输出一个有意义的作品。
技术栈
| 项目 | 详情 |
|---|---|
| 开发框架 | Flutter (OHOS 分支) |
| 目标设备 | HUAWEI Mate 60 Pro (HarmonyOS 6.1.0, API 23) |
| 开发工具 | DevEco Studio (含 HarmonyOS SDK) |
| 编程语言 | Dart |
二、环境准备
2.1 Flutter OHOS 分支
Flutter 官方支持 HarmonyOS 平台需要通过 OHOS 分支。我们使用的是社区维护的 oh-* 版本:
bash
$ flutter --version
Flutter (Channel stable, oh-3.41.9-dev, on macOS)
2.2 检查设备连接
确认鸿蒙设备已通过 USB 连接,并开启了开发者模式和 USB 调试:
bash
$ hdc list targets
2LQ0224129000383
2.3 设置 HarmonyOS SDK
DevEco Studio 自带了 HarmonyOS SDK,配置好环境变量即可:
bash
export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk
注意 :如果使用
HOS_SDK_HOME环境变量指向 DevEco Studio 的 SDK 路径,可能遇到 Flutter 工具的 SDK 检测 bug,详见下文"踩坑记录"。
三、创建项目
使用 flutter create 命令创建鸿蒙 Flutter 项目:
bash
flutter create --project-name childrens_day childrens_day
创建后的项目结构包含 ohos/ 目录,这是 HarmonyOS 平台的原生代码:
childrens_day/
├── lib/ # Dart 源码
│ └── main.dart
├── ohos/ # HarmonyOS 原生代码
│ ├── entry/ # HAP 入口模块
│ ├── build-profile.json5 # 构建配置
│ └── hvigorconfig.ts # Hvigor 构建工具配置
├── android/ # Android 平台
├── ios/ # iOS 平台
├── pubspec.yaml
└── ...
项目创建完成后的下一步就是编写 UI 代码!
四、UI 设计思路
既然是六一儿童节的应用,我设计了以下核心元素:
| 元素 | 说明 |
|---|---|
| 🎈 气球 | 8 个彩色气球在屏幕上方漂浮,营造节日氛围 |
| 🌟 闪烁星星 | 12 颗星星随机分布,呼吸式闪烁 |
| 🎉 主标题 | "六一儿童节快乐!" + 英文祝福 |
| 💖 祝福语卡片 | 半透明毛玻璃效果,传递温暖祝福 |
| ✨ 交互按钮 | 点击触发弹跳动画,增加互动趣味 |
| 🌸 底部装饰 | 7 个 emoji 轻轻浮动,点缀画面 |
颜色方案采用了渐变紫色系(紫蓝渐变),搭配粉色、黄色、绿色等鲜艳的气球颜色,整体视觉效果明亮活泼。
五、核心代码实现
5.1 入口与主题
dart
void main() {
runApp(const ChildrensDayApp());
}
class ChildrensDayApp extends StatelessWidget {
const ChildrensDayApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '六一儿童节快乐',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFFFF6B9D),
brightness: Brightness.light,
),
useMaterial3: true,
),
home: const ChildrensDayPage(),
);
}
}
5.2 动画控制器初始化
使用 TickerProviderStateMixin 管理三个独立动画:
dart
class _ChildrensDayPageState extends State<ChildrensDayPage>
with TickerProviderStateMixin {
late final AnimationController _floatController; // 浮动动画(气球/emoji)
late final AnimationController _bounceController; // 弹跳动画(点击交互)
late final AnimationController _sparkleController; // 闪烁动画(星星)
@override
void initState() {
super.initState();
_floatController = AnimationController(
vsync: this,
duration: const Duration(seconds: 4),
)..repeat(reverse: true);
_bounceController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 600),
);
_bounceAnimation = Tween<double>(begin: 0, end: -20).animate(
CurvedAnimation(parent: _bounceController, curve: Curves.easeOutBack),
);
_sparkleController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
)..repeat();
_sparkleAnimation = Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(parent: _sparkleController, curve: Curves.easeInOut),
);
}
}
5.3 气球实现
气球由彩色圆角矩形 + 细线组成,通过 sin 函数实现上下浮动效果:
dart
Widget _buildBalloon(Color color, double size) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: size,
height: size * 1.2,
decoration: BoxDecoration(
color: color.withValues(alpha: 0.8),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(size * 0.5),
topRight: Radius.circular(size * 0.5),
bottomLeft: Radius.circular(size * 0.2),
bottomRight: Radius.circular(size * 0.2),
),
boxShadow: [
BoxShadow(
color: color.withValues(alpha: 0.3),
blurRadius: 8,
spreadRadius: 1,
),
],
),
),
Container(
width: 1.5,
height: size * 0.4,
color: Colors.white38,
),
],
);
}
5.4 背景渐变
使用四色线性渐变,从蓝紫过渡到粉红,营造梦幻氛围:
dart
Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFF667eea),
Color(0xFF764ba2),
Color(0xFFf093fb),
Color(0xFFf5576c),
],
),
),
)
5.5 点击交互
点击"点击接收祝福"按钮或 emoji 集合时,触发弹跳动画:
dart
GestureDetector(
onTap: () {
_bounceController.forward(from: 0);
},
child: Column(
children: [
AnimatedBuilder(
animation: _bounceAnimation,
builder: (context, child) {
return Transform.translate(
offset: Offset(0, _bounceAnimation.value),
child: child,
);
},
child: const Text('🎉', style: TextStyle(fontSize: 64)),
),
// ...
],
),
)
六、运行与效果
6.1 构建并运行
bash
$ cd childrens_day
$ flutter run
构建输出:
Building flutter tool...
Resolving dependencies...
Launching lib/main.dart on 2LQ0224129000383 in debug mode...
Running Hvigor task assembleHap... 13.5s
✓ Built build/ohos/hap/entry-default-signed.hap.
installing hap. bundleName: com.example.childrens_day
Syncing files to device 2LQ0224129000383... 104ms
6.2 最终效果
应用成功运行在 HUAWEI Mate 60 Pro 上,呈现:
- 💜 紫色渐变背景 + 漂浮的彩色气球
- ⭐ 呼吸闪烁的星星
- 🎉 点击弹跳的庆祝动画
- 💖 暖心的祝福语卡片
- 🌸 底部 emoji 浮动装饰
七、踩坑记录 🕳️
7.1 问题:No Hmos SDK found
现象:
[!] No Hmos SDK found. Try setting the HOS_SDK_HOME environment variable.
根因分析 :Flutter OHOS 工具链中的 ohos_sdk.dart 存在一个共享全局状态 bug。
核心代码如下(位于 Flutter SDK 内的 packages/flutter_tools/lib/src/ohos/ohos_sdk.dart):
💡 在你的机器上,完整路径类似:
- macOS :
~/flutter/packages/flutter_tools/lib/src/ohos/ohos_sdk.dart- Windows :
C:\flutter\packages\flutter_tools\lib\src\ohos\ohos_sdk.dart- Linux :
/opt/flutter/packages/flutter_tools/lib/src/ohos/ohos_sdk.dart不确定 Flutter SDK 在哪?运行
which flutter(macOS/Linux)或where flutter(Windows)即可看到路径。
dart
// 全局共享变量!
final SplayTreeMap<int, String> sdkVersionMap =
SplayTreeMap<int, String>((int a, int b) => b.compareTo(a));
OhosSdk(负责 OpenHarmony CLI SDK)和 HmosSdk(负责 DevEco Studio SDK)共用了同一个全局 sdkVersionMap。执行流程:
OhosSdk.localOhosSdk()先被调用,将 API 23 写入sdkVersionMapHmosSdk.localHmosSdk()被调用时,将 API 24 也写入同一 mapHmosSdk.validApi11SdkDirectory()遍历 map 所有条目 ,要求在 DevEco SDK 路径下同时存在default(API 24)和23(API 23)两个子目录- 但 DevEco SDK 路径下没有
23目录 → 校验失败
修复方案:
将 validApi11SdkDirectory 从"所有版本目录都必须存在"改为"任意一个版本目录存在即成立":
dart
// 修复前:要求 ALL 条目都存在
static bool validApi11SdkDirectory(String hmosHomeDir) {
if (sdkVersionMap.length == 0) return false;
for (String sdkName in sdkVersionMap.values) {
Directory sdkDir = globals.fs.directory(
globals.fs.path.join(hmosHomeDir, sdkName));
if (!sdkDir.existsSync()) return false;
}
return true;
}
// 修复后:ANY 条目存在即可
static bool validApi11SdkDirectory(String hmosHomeDir) {
if (sdkVersionMap.length == 0) return false;
for (String sdkName in sdkVersionMap.values) {
Directory sdkDir = globals.fs.directory(
globals.fs.path.join(hmosHomeDir, sdkName));
if (sdkDir.existsSync()) return true;
}
return false;
}
修复后清除 Flutter 工具缓存并重新编译:
bash
# 找到 Flutter SDK 路径
which flutter # macOS/Linux: → /Users/yourname/flutter/bin/flutter
# 或
where flutter # Windows: → C:\flutter\bin\flutter.exe
# 删除缓存中的编译快照(路径相对于 Flutter SDK 根目录)
rm <flutter_sdk_dir>/bin/cache/flutter_tools.snapshot
# 重新运行即可自动重新编译工具链
flutter run
🔑 如果不想手动找路径,也可以直接使用:
bashrm "$(dirname $(dirname $(which flutter)))/bin/cache/flutter_tools.snapshot" flutter run
八、总结与感想
这次 Flutter + HarmonyOS 开发体验整体令人满意:
- ✅ 开发效率高 :Flutter 的热重载在鸿蒙上同样有效,修改代码后按
r键即可实时预览 - ✅ 跨平台一致性:一套 Dart 代码同时覆盖 Android、iOS、HarmonyOS,业务逻辑完全复用
- ✅ 原生体验 :构建产物是标准的
.hap包,和原生鸿蒙应用无差异 - 🐛 工具链仍在打磨:共享状态 bug 说明 OHOS 分支还在早期阶段,但不影响核心功能
六一儿童节,愿每一个孩子都能保持童真,愿每一颗童心都能被温柔以待 💖
附录:完整代码
完整的 lib/main.dart 源码见项目文件,核心结构:
| 组件 | 行数 | 功能 |
|---|---|---|
ChildrensDayApp |
L8-26 | 应用入口 + Material 主题 |
ChildrensDayPage |
L28-33 | 页面 StatefulWidget |
_ChildrensDayPageState |
L35-369 | 动画 + UI 构建 + 交互逻辑 |
_Balloon |
L371-382 | 气球数据模型 |
_Star |
L384-395 | 星星数据模型 |
Happy Children's Day! 🎈🎉