1. AR眼镜厨房应用开发全记录
作为一名长期关注AR技术落地的开发者,我最近完成了一个特别实用的项目——用AR眼镜解决厨房看菜谱的痛点。这个想法源于去年春节的亲身经历:当时我正在准备年夜饭,手上沾满油渍却不得不频繁查看手机菜谱,结果把手机屏幕弄得油腻不堪。这促使我思考:AR眼镜或许是最佳解决方案。
经过一周的密集开发,基于Rokid CXR-M SDK的"菜谱步骤助手"应用终于成型。它不仅能让厨师在双手忙碌时轻松查看菜谱步骤,还支持语音播报和智能计时功能。下面我将完整分享这个项目的技术实现细节和实战经验。
2. 技术选型与架构设计
2.1 为什么选择CXR-M SDK?
Rokid为开发者提供了多套SDK工具,经过仔细评估,我最终选择了CXR-M SDK,主要基于以下几点考量:
- 跨设备协同能力:CXR-M SDK专为手机与眼镜的交互设计,完美匹配"手机选菜谱、眼镜看步骤"的核心需求
- 开发效率优势:SDK内置的"提词器场景"可以直接复用,省去了从零开发眼镜端应用的麻烦
- 技术成熟度:相比实验性的AR Studio SDK,CXR-M的API更稳定,文档更完善
注意:当前CXR-M SDK仅支持Android平台,iOS版本还在开发中。如果你的目标用户主要是iPhone用户,可能需要考虑其他方案。
2.2 系统架构解析
整个应用的架构可以分为三个主要部分:
- 数据层:本地存储的菜谱数据模型
- 逻辑层:处理菜谱选择、步骤切换、计时器等核心功能
- 通信层:通过蓝牙连接手机与眼镜,实时同步数据
通信流程特别值得一提:当用户在手机端切换菜谱步骤时,应用会通过蓝牙将步骤内容发送到眼镜端,同时触发TTS语音播报。这种双通道反馈机制确保了用户即使不看眼镜也能获取关键信息。
3. 开发环境配置详解
3.1 基础环境搭建
配置开发环境时遇到了几个关键问题,这里特别提醒后来者注意:
- minSdk版本:必须≥28(Android 9.0),低于此版本会导致编译错误
- NDK配置:需要明确指定armeabi-v7a和arm64-v8a两种ABI
正确的build.gradle配置如下:
kotlin复制android {
defaultConfig {
minSdk = 28
ndk {
abiFilters += listOf("armeabi-v7a", "arm64-v8a")
}
}
}
dependencies {
implementation("com.rokid.cxr:client-m:1.0.9")
implementation("com.squareup.okhttp3:okhttp:4.9.3")
implementation("com.google.code.gson:gson:2.10.1")
}
3.2 权限管理陷阱
蓝牙相关权限是最大的坑,特别是对于Android 12及以上版本:
xml复制<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
关键注意事项:
- 即使不需要定位功能,也必须声明定位权限
- Android 12+必须使用
neverForLocation标志 - 所有蓝牙权限都需要运行时动态申请
4. 核心功能实现细节
4.1 蓝牙连接管理
蓝牙连接是整套系统的基础,我将其封装为RokidGlassesManager单例类。连接过程分为两个阶段:
- 初始化阶段:获取设备的UUID和MAC地址
- 正式连接:使用获取的信息建立稳定连接
kotlin复制object RokidGlassesManager {
private val cxrApi = CxrApi.getInstance()
fun connectGlasses(context: Context, device: BluetoothDevice) {
cxrApi.initBluetooth(context, device, object : BluetoothStatusCallback {
override fun onConnectionInfo(socketUuid: String?, macAddress: String?) {
// 第二阶段连接
connectBluetooth(context, socketUuid, macAddress)
}
// 其他回调处理...
})
}
}
4.2 菜谱数据同步
数据同步是本项目的核心创新点。通过复用提词器场景,我们可以将格式化的菜谱步骤发送到眼镜:
kotlin复制fun sendStepToGlasses(stepData: StepData): Boolean {
// 1. 确保场景已开启
cxrApi.controlScene(ValueUtil.CxrSceneType.WORD_TIPS, true, null)
// 2. 发送格式化文本
val text = """
【${stepData.recipeName}】
步骤 ${stepData.stepNumber}/6:${stepData.title}
${stepData.content}
⏱ 预计时间:${stepData.duration}分钟
💡 ${stepData.tips}
""".trimIndent()
return cxrApi.sendStream(
ValueUtil.CxrStreamType.WORD_TIPS,
text.toByteArray(Charsets.UTF_8),
"step.txt",
callback
) == ValueUtil.CxrStatus.REQUEST_SUCCEED
}
4.3 语音播报集成
TTS功能极大提升了使用体验,但需要注意两个关键点:
- 每次播报后调用
notifyTtsAudioFinished() - 控制播报频率,避免信息过载
kotlin复制fun sendTtsFeedback(text: String): Boolean {
val result = cxrApi.sendTtsContent(text)
if (result == ValueUtil.CxrStatus.REQUEST_SUCCEED) {
cxrApi.notifyTtsAudioFinished() // 关键调用!
}
return result == ValueUtil.CxrStatus.REQUEST_SUCCEED
}
5. 数据模型设计艺术
5.1 菜谱数据结构
考虑到春节菜谱的特点,我设计了分层数据结构:
kotlin复制data class Recipe(
val id: Int,
val name: String,
val category: String, // 年夜饭/家常菜/汤品等
val steps: List<RecipeStep>
)
data class RecipeStep(
val stepNumber: Int,
val title: String,
val content: String,
val duration: Int, // 分钟
val tips: String? = null
)
5.2 本地数据管理
由于稳定的菜谱API难寻,我选择了硬编码20道春节常见菜品:
kotlin复制object RecipeRepository {
val recipes = listOf(
Recipe(
id = 1,
name = "红烧肉",
category = "年夜饭",
steps = listOf(
RecipeStep(1, "准备食材", "五花肉切块...", 10),
RecipeStep(2, "焯水处理", "冷水下锅...", 5)
// 其他步骤...
)
),
// 其他菜谱...
)
}
这种方案虽然简单,但非常可靠,特别适合春节这种菜单相对固定的场景。
6. 用户界面设计要点
6.1 菜谱列表界面
采用RecyclerView实现分类展示,支持按年夜饭、家常菜、汤品等筛选。每个卡片展示:
- 菜品图片
- 名称和预估总时长
- 难度星级
- 分类标签
6.2 步骤详情界面
这是核心交互界面,包含以下关键区域:
- 状态栏:显示眼镜连接状态和电量
- 步骤区:当前步骤的图文详情
- 控制区:上一步/下一步按钮
- 计时器:大号数字显示+控制按钮
特别优化了单手操作体验,所有关键按钮都集中在屏幕右侧。
7. 开发中的典型问题与解决
7.1 中文乱码问题
最初发送到眼镜的中文显示为乱码,原因是未明确指定UTF-8编码:
kotlin复制// 错误做法
text.toByteArray()
// 正确做法
text.toByteArray(Charsets.UTF_8)
7.2 TTS播放中断
部分长文本播放不完整,解决方案是:
- 合理拆分长文本为短句
- 确保每次播报后调用
notifyTtsAudioFinished()
7.3 场景未开启导致无显示
最隐蔽的问题:sendStream调用成功但���镜无显示。原因是必须先开启场景:
kotlin复制// 正确调用顺序
1. controlScene(WORD_TIPS, true) // 开启场景
2. sendStream(...) // 发送内容
8. 功能扩展与未来展望
8.1 计划中的增强功能
- 语音控制:实现"下一步"、"重复"等语音指令
- 智能计时:根据步骤自动设置倒计时
- 多人协作:家人可以查看烹饪进度
8.2 AR眼镜的厨房前景
虽然当前AR眼镜在厨房应用还面临价格、续航等挑战,但我坚信这是未来趋势。随着技术进步,五年内AR眼镜可能会像现在的智能手机一样普及。
这个项目让我深刻体会到:好的技术解决方案应该源于真实的痛点。厨房场景虽然简单,但确实是AR技术能够立即创造价值的领域。
