如果你现在还盯着终端里一行行报错、一个类一个类地手工补代码,我觉得你大概率已经被同行甩开半个身位了。这篇文章不是讲怎么用AI写个demo,而是记录我一个真实的7天冲刺:用Vibe Coding的方式,从零开始做一款Flutter鸿蒙音乐播放器,并且赶在周五之前把它变成能在鸿蒙应用市场搜到的生产级App。
题目里那句“碎片化敲代码”确实戳中我之前的痛点。以前做跨端应用,光是Android和iOS两套平台细节就够消耗精力,再加一个鸿蒙,人力直接翻倍。而这次我把“逐行写代码”降级成“逐句下需求”,让AI代码工具去干累活,我只负责架构、验收和上架。过程没少踩坑,但产出的这套打法,我觉得值得整理成系列连载,慢慢讲透。
1. 先解决一个核心问题:Vibe Coding到底怎么用在正经项目里
1.1 它和“用AI写代码”的区别在哪
Vibe Coding不是简单地把需求丢给AI然后复制粘贴。这次项目里我的理解是:它是一套“意图驱动开发”的工作流,把编码从打字动作变成对话交互。你描述目标、验收条件、边界约束,AI负责生成可编译、可运行的代码;你再跑测试、看效果、纠正方向,循环到满意为止。
用开车来类比:以前是踩离合挂挡,油离配合都得自己来;现在是自动挡,你只管方向盘和路况。AI生成代码是变速器,它替你处理了“怎么写”的机械动作,但车往哪开、走哪条路、遇到坑怎么绕,得你拍板。
这次我给自己定的规则很清楚:
- 重复性的UI代码、样板代码、平台通道对接,全部交给AI;
- 涉及用户数据、播放状态机、安全性、上架合规的决策,我必须自己审一遍;
- 每次AI输出后,编译和跑通是底线,不能让它交出一堆看着像、跑不了的代码。
第一条规则其实是从上一段失败经历里学来的。之前我图省事,让AI一口气生成了五六个页面和一套完整路由,结果编译通过率极高,但页面上有几个诡异的状态,互相之间跳转逻辑乱成一锅粥。所以这次把工作量拆成小块,每次只让AI动一个模块。
1.2 为什么选Flutter做鸿蒙App
无非三个原因:跨端复用、渲染一致性、生态在快速补齐。
第一个原因是真金白银的成本。手头有Android和iOS两端的App,再加一个鸿蒙版本,如果原生重写,等于多养一支团队。用Flutter,核心业务逻辑在同一套Dart代码里跑,只需要在平台层做适配。第二个原因是Flutter的自绘引擎能保证三端视觉一致,不需要在鸿蒙里专门调原生组件。音乐播放器这类应用,UI动效在体验里占的比重很大,这个优势会被放大。第三个原因是生态虽然比Android少一截,但核心场景已经够用。
我见过很多团队在方案评估时反复纠结,最后停在“等适配更成熟再上”。如果你做的App不只是列表加详情,而是有复杂的播放控制、后台任务、横竖屏切换,那早点拿真实业务去趟坑,比后续迁移的成本低得多。先花两周做一个垂直场景Demo,验证音频链路和后台播放这条生命线,再决定全量投入。
2. 第1-2天:环境准备和工程骨架,AI帮你把“Hello World”变成有结构的项目
2.1 鸿蒙构建环境怎么搭
这个阶段AI帮不上太多忙,因为工具链安装是机器交互,不是语言交互。需要准备的东西有:
- HarmonyOS SDK和相关命令行工具;
- 配置好Node环境和包管理工具;
- Flutter的鸿蒙适配版本;
- 编辑器里安装对应的Dart和Flutter插件。
环境变量比较敏感,我习惯写成一条初始化脚本,放到仓库的tools目录下。团队新人拉下来跑一遍就能编译,不用看十几页文档。这一步跑通之后的标志很简单:能执行下面这两条命令,并且产出一个能装在真机上的空壳包。
flutter create --platforms=ohos --org com.example demo_player flutter build ohos --release这个阶段容易忽略的是SDK版本匹配。鸿蒙SDK、Flutter分支、Dart SDK之间有一组隐式对应关系,装错了很可能冒出一些莫名其妙的编译错误。排查了半天最后发现是SDK版本不对,白白浪费了一个晚上。现在我的做法是:把SDK版本固定写进脚本里,并且每次升级前先跑现有工程的回归测试。
2.2 让AI生成目录结构和基础页面
空工程跑通后,我不会手工建十几个Dart文件。我直接对AI说:需要按feature-first结构组织项目,每个feature包含数据模型、状态管理、页面、服务四个文件;播放器需要独立模块;请先生成发现页、歌单页、播放页三个页面的骨架。
这里要特别注意约束表达。AI第一次生成的代码经常把路由和页面混在一个文件里,或者状态管理用了一个我不打算引入的库。我改进了提示词,把技术选型直接写进去:
- 状态管理用Riverpod,不要用Provider;
- 路由先手动维护映射表,不引入重框架;
- 页面组件拆成widget和container两个层级。
这种“给约束,不给答案”的提示方式,生成出来的代码可维护性会高很多。第一次生成完,我做的事情是:先看结构,再看关键文件,最后编译。结构不对就让它重构;编译不过就把报错日志贴回去,让AI自己修。
这里有个经验:AI连续改代码时容易越改越乱。每轮结果我都要提交一次Git,回退成本就很低。实测下来,一个10分钟的需求对话,通常需要3到5轮迭代才能通过编译。这个过程不是浪费,每轮都在帮AI摸清我们的代码风格。
2.3 为什么坚持用Riverpod
既然AI每次都爱推荐Provider,我说一下为什么坚持Riverpod。音乐播放器有全局播放状态,播放暂停、进度、播放列表、当前歌曲这些状态在多个页面间共享。Riverpod的provider天然带依赖注入和自动重建能力,配合消费者widget,UI层能精准局部刷新。这种架构选择,在Vibe Coding时代尤其重要。AI生成代码时会大量复制模板代码,如果你没锁定架构说明,它会东用一个模式、西用一个风格,后期变成一座屎山。先定架构,再让AI填充,是这次我最深的体会。
3. 第3-5天:播放器核心链路,一个功能一个功能喂给AI
3.1 音频引擎:鸿蒙上最折腾的一步
音乐播放器的心脏是音频引擎。Android上我有现成的插件可选,鸿蒙的音频插件没那么丰富。我采用的方案是:先找社区里对OpenHarmony有适配的音频播放插件,本地验证它对音频焦点、缓冲、格式支持的表现,不行就自己在平台通道里写一层原生实现。
AI在这里的用法是:让它扫描现有插件源码,分析鸿蒙平台适配的完整度,输出一份对比报告。报告里要列出支持的音频格式、是否支持后台播放、是否暴露暂停恢复接口。这一步省掉了我大量调研时间。但AI的结论不能直接用,我让团队里的同学在真机上分别播放了几种不同格式的音频文件和在线流,各测一分钟,验证插件稳定性和码率切换表现。
最终我们选择了一个用于核心播放的插件,并在鸿蒙侧自己补了几个平台通道方法,实现耳机拔插监听和音频焦点处理。这部分原生代码总共没几行,但它是生产级播放器区别于demo的关键。你甚至可以理解为:跨端框架把90%的活干了,剩下那10%平台特性,恰恰是决定App能不能上生产的分水岭。
3.2 状态机:播放器状态别让AI自由发挥
播放器状态比想象中复杂:空闲、加载中、播放中、暂停、错误、已结束。每次切歌、拖进度、断网,都要有对应的状态转换。AI生成的代码如果不约束,经常会漏掉错误状态和恢复路径。我做了两件事。
第一件事,我先把状态机画成表格给AI:
| 状态 | 触发条件 | 目标行为 |
|---|---|---|
| idle | 初始化/播放结束 | 无任务,UI显示空态 |
| loading | 资源加载中 | 显示缓冲动画 |
| playing | 加载完成/用户播放 | 更新进度,联动锁屏 |
| paused | 用户主动暂停 | 保留进度,释放音频焦点 |
| interrupted | 来电、耳机拔出、焦点被抢 | 暂停并保留恢复入口 |
| error | 播放失败/网络异常 | 显示错误文案,允许重试 |
然后让AI按这个表生成状态流转方法,任何非法转换都抛异常。这一步是防止AI在业务代码里私下处理状态,导致世界各地的奇奇怪怪分支越来越多。
第二件事,在Dart层封装了一个PlayerController,对外只暴露几个语义化方法:load()、play()、pause()、seekTo()、next()、previous()。UI层和业务层永远不直接操作底层播放器对象,这样即使AI生成的底层代码被替换,上层也不受影响。这个封装模式也降低了AI生成的代码相互耦合的概率,后期增删功能时,只改一个壳就行。
3.3 后台播放和锁屏控制:平台能力必须真人验证
鸿蒙对后台任务管控很严,如果不申请正确的长任务类型,应用退到后台几十秒就会被系统挂起。播放器属于音频播放类任务,需要在Native侧声明对应的长任务类型,才能在息屏后继续出声。这一步我让AI生成了一版后台任务声明代码,但运行时发现锁屏卡片和播放进度没有联动。
排查花了不少时间,最后确定是媒体会话的数据刷新时机不对。AI代码在收到进度回调后没有及时更新锁屏界面,而是在自己的定时器里更新,锁屏拿到的永远是旧数据。解决方式:在Native侧监听播放进度回调,立刻同步给媒体会话;同时把Dart层每500毫秒上报进度的逻辑改成了事件驱动。
这个问题的教训是:凡是涉及系统级UI联动的功能,别只盯着Dart层,一定要在真机息屏、锁屏、来电三个场景各测一遍。AI能帮你生成代码框架,但不替你做感官层面的体验验收。
3.4 歌词与动效:AI生成速度比想象中靠谱
歌词滚动页面是播放器里比较麻烦的部分。逐行歌词解析、当前行高亮、平滑滚动到中间位置,这些逻辑如果手写,需要处理时间轴解析和列表定位。AI生成一版之后,居然一次性跑通了。
我当时的提示词是这样的:使用LRC格式解析,同步歌词列表到当前播放进度,高亮当前行,并自动滚动到可视区域中间;滚动动画使用系统提供的曲线,不要自定义插值。AI给出的实现思路是直接计算当前行的scroll offset,配合一个简单的滚动控制器。
真正出问题的地方是一些边角需求:歌词界面需要支持点击某一行跳转到对应时间,以及拖动进度条时歌词要实时跟进。这两个需求要求UI和播放进度保持双向同步。AI在第一版忽略了点击跳转,我在验收清单里补上,第二轮就解决了。这说明验收清单本身就是最有效的提示词。
4. 第6天:性能优化和兼容性,从“能跑”到“配叫生产级”
4.1 列表页的流畅度
AI初版代码用了一个简单的ListView.builder,2000首歌滑起来倒还行,但一旦开了专辑封面图,卡顿就很明显。我把图片加载替换成了带内存缓存的方案,并顺手加了预加载窗口。
这个优化过程很有意思。如果我自己写,可能得半天;但AI能直接把“侧滑卡顿、CPU占用高”的诊断日志拿去定位,给出两三个候选方案。我选了最稳的那个,前后不到40分钟。这比我自己翻源码找卡点快得多。
这里补充一个细节:列表卡片里如果有动画,建议用RepaintBoundary隔离开。AI不懂哪些widget需要隔离,但你在提示词里说出这句话,它就会自动给关键区域包上。生产级App的流畅度,往往就是这么一层一层包出来的。
4.2 内存和包体积
播放器最怕内存泄漏,切歌几百次后内存如果只升不降,上架后就是事故。我让AI写了一个自动化稳定压测:循环切歌、暂停、恢复、切后台、回前台,每轮记录内存曲线。跑了一晚上,发现某条歌词滚动页面会持有播放器引用,AI自动补了一个释放逻辑。
包体积我也做了裁剪。字体、图标、无用依赖删了一轮,HAP包从初版的接近90MB降到50多MB。对鸿蒙应用来说,包太大不仅用户下载意愿低,上架审核也容易被多问几句。这里给个小工具建议:在依赖里加上一个构建分析模块,直接看每个依赖占多少空间,AI会告诉你哪些是可以替换成更小实现的高频库。
4.3 断网、来电、耳机拔插这些边角料
demo版本可以忽略这些,生产级不行。我列了一个异常场景清单,逐一让AI生成处理逻辑,再手动验证:
- 播放中网络切换:自动暂停并弹提示,恢复网络后手动续播;
- 来电接听:触发音频焦点丢失,先暂停,挂断后恢复;
- 耳机拔插:拔掉时暂停,插回时不自动恢复,避免公共场合尴尬;
- 音频焦点被其他App抢占:本应用暂停,并降低音量感知;
- 播放器进入后台超过系统阈值:请求长任务,同时准备停止并保存进度。
每一条看着小,但漏掉任何一条,用户真实使用都会骂娘。AI生成这些逻辑的时候,经常会写得很“理想化”,比如自动恢复播放、自动切歌。我的原则是:涉及用户主观意图的,一律保守处理,绝不自动干。
5. 第7天:发布前最后的冲刺,上架审核的坑我帮你踩过
5.1 签名、权限声明和隐私合规
从开发包到上架包,中间有很多现实事。开发签名、发布签名、权限声明、隐私政策、软件著作权,每一样缺了都有可能被驳回。音乐播放器还牵扯到内容版权说明,这个必须提前准备。
AI在这次流程里能帮的是生成权限说明文档和隐私政策初稿。但审核侧的细节,比如哪些权限需要单独说明用途,每个市场要求不同,必须人工核对。我这次就因为“读取本地存储”的申请理由写得不够具体,被打回来一次。改完理由,重新打包,第二天就过审了。写权限理由有个技巧:别写“用于播放音乐”,要写“用于扫描用户本地音频文件并在播放列表中展示”,这会让审核人员觉得你确实说清楚了。
5.2 一键打包脚本
发布流程如果手工操作,重复且容易漏。我让AI写了一个打包发布脚本,把签名、版本号递增、构建HAP、生成校验和、输出发布说明合并成一步。脚本发布到仓库,后续每周更新版本时,只需要跑一条命令。
这个脚本的重点是版本号和校验和。AI默认生成的版本号逻辑是每次加一,但实际发布需要遵循语义化版本规则。我把它改成通过命令行参数传入,避免了自动递增带来的混乱。
发布脚本我建议放在单独的发布分支里,和日常开发分支解耦。因为发布脚本一旦跑歪,影响的不是某个功能,而是整个线上版本。
5.3 上线后的观察项
生产级的定义不只在上架那一刻。我给自己留了一天的灰度观察期,重点看三个指标:
| 指标 | 阈值 | 异常动作 |
|---|---|---|
| 启动崩溃率 | 小于0.1% | 回滚上一版本 |
| 音频播放失败率 | 小于0.5% | 检查音频引擎和网络策略 |
| 后台播放被杀率 | 小于1% | 检查长任务申请和资源释放 |
这三个指标对音乐类App基本能代表健康度。
最终效果:从工具链搭建到过审上架,确实用了7个工作日。其中AI承担了接近70%的编码工作量,但关键的架构决策和平台适配验证,仍然是我自己完成的。如果还是碎片化敲代码,我可能需要三周以上。
我个人的体会是,Vibe Coding不是玄学,也不是要替代程序员,它更像是把个人效率和团队效率拉高了几个档次,但前提是你得有一份清晰的架构意识和验收标准。它放大的是你的判断力,而不是遮住你的懒惰。下一篇我会把“音频引擎选型对比”和“鸿蒙插件适配过程”单独拆开,写一份可以直接照着做的实战手册。如果你也在用Flutter做鸿蒙应用,欢迎把你的坑留在评论区,后面我汇总成一篇避坑合集。