我用 AI 辅助开发了一个发型 App,然后打包成了 APK
起因
我做了十几年 Java 后端,安卓 App 开发对我来说基本是"听说过但没摸过"。
前一阵想看看 AI 辅助编程到底能到什么程度------不写 Demo,不写脚本,正儿八经做一个能装到手机里跑的 App。结果就搞出了这个项目:一个发型试戴 App,有 32 种发型库,支持摄像头实时试戴,还能拍照合成,最后打包成了 APK 装到手机上跑。
全程 AI 辅助开发。我不是说 AI 帮我写了几段代码,而是从项目搭建到最终出 APK,几乎每一个环节都有 AI 参与。
这篇文章记录这个过程中我踩过的几个坑,以及一些关于 AI 辅助开发的真实感受。
项目大概是做什么的
简单说就是:打开摄像头,系统识别你的脸,然后把发型图片叠加到你头上,跟着你的头部移动实时调整位置。
听起来像是美颜相机的玩法,但技术实现其实没那么简单------需要人脸识别、关键点定位、Canvas 渲染,还要处理移动端摄像头权限、性能优化这些杂七杂八的事情。
技术栈选了 React + TypeScript + Capacitor(把 Web 项目包装成原生 App 壳子)+ MediaPipe(人脸检测)。发型素材是 PNG 透明图,一共 32 种,男女各 16 种。
最终产物是一个 APK,装到 Android 手机上就能直接用摄像头试发型。
几个关键的坑
1. 发型到底应该"贴"在脸的哪个位置
这是整个项目最核心的技术问题------怎么让发型图片准确地对齐到人的头顶,而不是跑到鼻子上或者嘴巴上。
MediaPipe 返回 468 个面部关键点,我一开始的思路是:取眉毛和额头的中点,把发型锚点放在那里。结果跑出来一看,发型图片直接压到了鼻子以下。
试了好几次都不对。后来调整了算法,用额头点为基准,向上偏移头部高度的 35%:
typescript
// 计算头部姿态时确定发型锚点
const hairAnchorY = forehead.y - height * 0.35;
这个 0.35 不是算出来的,是试出来的。最开始设的是 15%,结果发型还是往下掉,压住了半张脸。调到 35% 之后,发型正好覆盖头顶区域。
这里还有个细节:头部高度是用额头到下巴的距离算的,但发型锚点要跑到额头以上 ,因为实际发型是长在额头上面的。所以是 forehead.y - height * 0.35(减去而不是加上)。
这种"参数不是算出来的,是试出来的"的场景,在 AI 辅助开发里很常见。AI 能帮你写出算法框架,但最终调参这种事,只能人肉做。
2. WASM 模型加载,在网络不好的时候直接挂了
人脸检测用的是 MediaPipe 的 WebAssembly 模型,需要从 CDN 加载 WASM 文件和 .task 模型文件。国内网络环境你懂的,偶尔 CDN 延迟高或者超时,页面就卡在那儿不动了。
最开始的处理特别简单------await FilesetResolver.forVisionTasks(wasmPath),完事。但第一次加载失败就直接抛异常了,用户看到一个白屏。
后来加了重试机制:
typescript
private async loadVisionWithRetry(): Promise<...> {
let lastError: unknown;
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
try {
const vision = await FilesetResolver.forVisionTasks(WASM_PATH);
return vision;
} catch (error) {
lastError = error;
if (attempt < MAX_RETRIES) {
await new Promise(resolve => setTimeout(resolve, attempt * 1000));
}
}
}
throw lastError;
}
延迟重试,1 秒、2 秒、3 秒递增,最多试 3 次。同时页面上给用户反馈"正在加载"、"加载失败,正在重试",而不是干等着。
还做了一个优化:把 WASM 文件和模型文件放到项目 public/models/ 目录,本地加载而不是每次从 CDN 拉。这对 App 场景很关键------装到手机之后,资源都是本地的,启动速度明显快。
3. Android 运行时权限------装好 App 打不开相机
项目打包成 APK 之后,第一次安装到手机上,打开摄像头页面弹了通知权限,但没问相机权限。用户点"试发型"就直接闪退了。
原因:AndroidManifest.xml 里声明了相机权限,但这只是"申请",Android 6.0 以上还需要在代码里运行时请求用户授权。
在 Web 里你只需要 navigator.mediaDevices.getUserMedia(),浏览器会自动弹权限。但包装成 Android App 之后,Capacitor 不会自动帮你请求权限。
修复方案是在 capacitorService 里加了个 initializePermissions() 方法,应用启动时主动请求相机和照片权限:
typescript
initializePermissions() {
// 使用 @capacitor/camera 插件的 requestPermissions API
return Camera.requestPermissions();
}
然后在 App.tsx 里加了个 AppInitializer 组件,在应用启动时调用这个方法,等权限处理完再显示主界面。
这个问题是装到真机上之后才发现的。模拟器有时候权限处理比较宽松,真机才会暴露问题。
4. GPU delegate 不是什么时候都靠谱
MediaPipe 支持 GPU 加速,理论上比 CPU 快很多。最开始配置的是 delegate: 'GPU',但有些低端 Android 手机上 GPU delegate 初始化失败。
现在的处理是 GPU 失败后自动回退到 CPU:
typescript
try {
this.faceLandmarker = await FaceLandmarker.createFromOptions(vision, {
baseOptions: { delegate: 'GPU' },
runningMode: 'VIDEO'
});
} catch (error) {
// 回退到 CPU 模式
this.faceLandmarker = await FaceLandmarker.createFromOptions(vision, {
baseOptions: { delegate: 'CPU' },
runningMode: 'VIDEO'
});
}
这个 fallback 逻辑也是 AI 帮我加的。我问"GPU delegate 在某些设备上会失败怎么办",它直接给出了 try-catch 双层初始化的方案。
AI 辅助开发,真实感受
AI 擅长什么
1. 脚手架搭建
项目初始化、配置文件、CI/CD 脚本、Android SDK 安装指南------这些繁琐但标准化的工作,AI 写得又快又好。我几乎没手写过配置文件。
2. 代码生成,尤其是模板代码
React 组件、TypeScript 接口、权限服务、Canvas 渲染循环------这些有固定模式的代码,AI 生成的质量很高。
3. 错误排查
遇到报错,把错误信息丢给它,它基本能准确定位问题。比如 Android 权限那个问题,AI 一眼就看出来是运行时权限没请求。
AI 不擅长什么
1. 业务判断
"这个发型锚点应该偏多少"、"重试延迟设几秒合适"、"chunkSize 设 4000 还是 8000"------这些和业务场景、用户体验相关的判断,AI 给不了答案,只能靠你自己试。
2. 整体架构
AI 能写好一个组件,但"整个项目怎么分层、各个模块怎么解耦"这种架构决策,需要你脑子里有整体图景。AI 写出来的代码如果没有人把关,很容易变成一团散沙。
3. 边界场景
AI 能处理正常的流程,但对"用户拒绝权限之后怎么办"、"低端设备性能不足怎么降级"这些边界场景,你需要主动问它,它不会自己想到。
AI 写得快,但改起来也慢
这个体验很矛盾:AI 生成代码的速度是真的快,一个 npx create-react-app 级别的脚手架,跟它说一声,几百行代码几秒钟就出来了。
但一旦出了问题,改起来比手写还慢。
原因有几个:
- 上下文太长。AI 生成的代码往往一次性涉及好几个文件,出问题后你得自己搞清楚问题出在哪个环节,然后重新把完整的上下文喂给它。喂少了它改不对,喂多了提示词太长又容易跑偏。
- 迭代回合多。手写代码你知道自己在干什么,改一次定位一个问题。AI 改代码你得"描述问题 → 它改 → 验证 → 还不对 → 再描述 → 再改",来回三四轮是常态。一个权限问题我来回问了五六次才彻底解决。
- "黑盒感"强。自己写的代码出了问题你知道大致方向,AI 写的代码出问题有时候你连问题在哪都不知道,得先把它写的代码读懂才能去改。读别人写的代码本来就比写新代码累。
所以我的感受是:AI 确实让"从 0 到 1"变快了,但"从 1 到 1.1"------也就是后续的小修小改和测试验证------花的时间一点没少,甚至因为要反复和 AI 沟通,比手写还多。
这个体验也提醒我,AI 辅助开发不是写完就完事,后续的测试和迭代才是真正耗时间的环节。如果以后要做更大的项目,这块的效率问题得想办法解决,比如更结构化的测试用例、更清晰的代码组织让 AI 更容易定位问题,或者引入更完善的 CI 流程。这些都是后面需要继续深入的方向。
一个重要的经验
AI 写得快的代码,不代表你不需要理解它。
项目里有一段 Canvas 渲染循环,AI 写了几十行代码处理视频帧检测、动画帧调度、摄像头开关。我一开始没仔细看,结果后面调试的时候发现摄像头关了但检测循环还在跑,排查了半天才发现是 animationFrameId 没正确 cancel。
那次之后我养成了个习惯:AI 写完的代码,每一段我都自己过一遍,搞清楚它在干什么。否则出了问题你根本不知道怎么查。
关于打包 APK
从 React Web 项目到 Android APK,中间用了 Capacitor:
bash
npm run build # 构建 Web 产物
npx cap sync android # 同步到 Android 壳子
cd android && ./gradlew assembleDebug # 构建 APK
过程本身不复杂,但安装 Android SDK 是个门槛------需要装 JDK、Android Studio(或者命令行工具)、配置环境变量,一套下来花了不少时间。
AI 帮了一个大忙:它直接生成了完整的 Android SDK 安装文档,三种方式(Android Studio、Homebrew、纯命令行),每一步都有命令,照着做就行。
最终出来的 APK 可以直接装到 Android 手机上,不需要上架应用商店,自己测试用足够了。
总结
这个项目从开始到出 APK,大概花了几天时间。如果是以前,我一个纯后端工程师想从零搞出一个能跑的 Android App,可能得先学一个月 Android 开发。
有了 AI 辅助,这个时间被大幅压缩了。但压缩的不是"开发"这个环节本身,而是查文档、配环境、调细节的时间。
说几点实话:
- AI 不会替代程序员------它替代的是"查 Stack Overflow"和"写模板代码"的时间,核心的架构思维和业务判断还是靠人
- AI 辅助开发 ≠ 完全交给 AI------你得能看懂它写的每一段代码,否则出了问题就是灾难
- 跨平台开发的门槛确实在降低------用 Capacitor,一个 Web 项目打包成 App,这个以前想都不敢想
项目开源在 Gitee:https://gitee.com/yannik/hairstyle-app,感兴趣可以看看代码,或者直接下载 APK 到手机上试试。有问题的话,欢迎提 Issue 交流。
tangyuewei,从后端出发,用 AI 拓展到全栈的工程师。