技术拆解:Rokid CXR-M SDK 构建 AI 智能提词眼镜助手连接到场景落地
技术拆解:Rokid CXR-M SDK 构建 AI 智能提词眼镜助手连接到场景落地
技术拆解:Rokid CXR-M SDK 构建 AI 智能提词眼镜助手连接到场景落地
一、开发背景
作为一名长期活跃在 Rokid 开发者社区的技术爱好者,我一直在思考:如何将 Rokid Glasses 的 AR 能力真正融入到高频、刚需的工作场景中?
提词器,就是这样一个典型场景。无论是线上直播、线下演讲,还是课堂教学,用户往往需要一边注视前方观众,一边记住冗长的台词。传统提词器要么依赖支架(破坏沉浸感),要么依赖手机/平板(频繁低头)。而 Rokid Glasses 凭借其轻量化、第一视角显示的特性,天然适合作为「隐形提词器」。
但市面上的提词方案大多局限于单端操作,缺乏与手机的协同能力。于是,我决定基于 Rokid CXR-M SDK,开发一款 手机端编辑 + 眼镜端显示 + AI 语音联动 的完整提词助手应用。
本文将完整记录从 SDK 集成、设备连接、提词场景构建,到 AI 联动、异常处理、性能优化的全过程,希望能为其他开发者提供一份可复用的实操指南。
二、技术选型与整体架构
2.1 核心技术栈
- 移动端:Kotlin + Android Jetpack(ViewModel, LiveData)
- SDK:Rokid CXR-M SDK v1.0.1-Preview(仅支持 Android)
- 通信协议:蓝牙(控制信令) + Wi-Fi P2P(媒体同步)
- UI 渲染:眼镜端使用 SDK 内置的「自定义页面场景」(JSON 驱动)
2.2 系统架构图
整个系统以 手机为控制中枢,眼镜为 显示与交互终端。CXR-M SDK 作为桥梁,封装了底层通信细节,让我们能专注于业务逻辑。
三、项目初始化:集成 CXR-M SDK
3.1 配置 Maven 仓库
在 settings.gradle.kts
中添加 Rokid 私有仓库:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
maven { url = uri("https://maven.rokid.com/repository/maven-public/") }
google()
mavenCentral()
}
}
3.2 添加依赖与权限
在 build.gradle.kts
中:
android {
defaultConfig {
minSdk = 28 // 必须 ≥28
}
}
dependencies {
implementation("com.rokid.cxr:client-m:1.0.1-20250812.080117-2")
// 其他 transitive 依赖(如 Retrofit, OkHttp)SDK 已声明,无需重复添加
}
在 AndroidManifest.xml
中声明权限(缺一不可):
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
⚠️ 注意:从 Android 12(API 31)起,蓝牙扫描/连接需动态申请 BLUETOOTH_SCAN
和 BLUETOOTH_CONNECT
,且必须搭配 ACCESS_FINE_LOCATION
。
3.3 权限动态申请封装
我封装了一个 PermissionHelper
,在 MainActivity
启动时调用:
class PermissionHelper(private val activity: AppCompatActivity) {
fun requestRequiredPermissions(onGranted: () -> Unit) {
val permissions = mutableListOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
permissions += Manifest.permission.BLUETOOTH_SCAN
permissions += Manifest.permission.BLUETOOTH_CONNECT
}
if (permissions.all { activity.checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED }) {
onGranted()
} else {
activity.requestPermissions(permissions.toTypedArray(), REQUEST_CODE)
}
}
}
只有权限全部授予,才进入设备连接流程。
四、设备连接:蓝牙 + Wi-Fi 双通道建立
4.1 蓝牙连接流程
CXR-M SDK 的蓝牙连接分为两步:初始化 → 连接。
// 1. 初始化蓝牙(传入扫描到的 BluetoothDevice)
CxrApi.getInstance().initBluetooth(context, device, object : BluetoothStatusCallback {
override fun onConnectionInfo(socketUuid, macAddress, rokidAccount, glassesType) {
// 保存 socketUuid 和 macAddress,用于后续连接
connectBluetooth(socketUuid!!, macAddress!!)
}
override fun onConnected() { /* 连接成功 */ }
override fun onDisconnected() { /* 断开处理 */ }
override fun onFailed(errorCode) { /* 错误处理 */ }
})
// 2. 正式连接
private fun connectBluetooth(uuid: String, mac: String) {
CxrApi.getInstance().connectBluetooth(context, uuid, mac, callback)
}
💡 提示:socketUuid
是 Rokid Glasses 在 BLE 广播中携带的自定义服务 UUID(00009100-...
),用于建立 RFCOMM 通道。
4.2 Wi-Fi P2P 初始化(用于后续文件同步)
提词内容虽小,但若未来扩展图片/视频提词,则需 Wi-Fi 通道。初始化如下:
val wifiStatus = CxrApi.getInstance().initWifiP2P(object : WifiP2PStatusCallback {
override fun onConnected() {
Log.d("WiFi", "P2P connected")
}
override fun onDisconnected() { /* ... */ }
override fun onFailed(errorCode) { /* ... */ }
})
⚠️ 注意:Wi-Fi P2P 必须在蓝牙连接成功后才能初始化,且耗电较高,建议按需开启。
五、核心功能实现:提词器场景构建
5.1 打开提词器场景
fun openWordTips() {
CxrApi.getInstance().controlScene(
ValueUtil.CxrSceneType.WORD_TIPS,
true, // true = 打开
null
)
}
5.2 发送提词内容
提词内容以 ByteArray
形式通过 sendStream
发送:
fun sendScript(text: String, fileName: String = "script.txt") {
CxrApi.getInstance().sendStream(
ValueUtil.CxrStreamType.WORD_TIPS,
text.toByteArray(),
fileName,
object : SendStatusCallback {
override fun onSendSucceed() {
Log.d("Script", "Sent successfully")
}
override fun onSendFailed(errorCode) {
Log.e("Script", "Send failed: $errorCode")
}
}
)
}
5.3 配置提词器显示参数
支持字体大小、行距、显示区域、滚动模式等:
fun configureWordTips() {
CxrApi.getInstance().configWordTipsText(
textSize = 18f, // 字体大小(sp)
lineSpace = 1.5f, // 行距
mode = "ai", // "ai" 模式支持 ASR 自动滚动
startPointX = 100, // X 起始坐标(像素)
startPointY = 200, // Y 起始坐标
width = 800, // 显示区域宽
height = 600 // 显示区域高
)
}
5.4 AI 模式下的 ASR 联动
当用户说话时,手机端 ASR 引擎识别结果,实时发送给眼镜,触发自动滚动:
fun onAsrResult(text: String) {
CxrApi.getInstance().sendAsrContent(text) // 注意:此处复用 AI 场景的 ASR 接口
}
📌 关键点:提词器的 "ai"
模式会监听 ASR 内容,当识别文本接近当前显示末尾时,自动向上滚动,确保用户始终看到下一句。
六、增强体验:设备状态控制与监听
6.1 远程调节亮度/音量
演讲环境光线多变,允许用户在手机端滑动调节眼镜亮度:
// 设置监听器(获取当前亮度)
CxrApi.getInstance().setBrightnessUpdateListener { brightness ->
viewModel.updateBrightnessUI(brightness)
}
// 设置亮度(0-15)
CxrApi.getInstance().setGlassBrightness(10)
同理,音量控制也支持双向同步。
6.2 电量与充电状态监听
CxrApi.getInstance().setBatteryLevelUpdateListener { level, charging ->
Log.d("Battery", "Level: $level%, Charging: $charging")
if (level < 20 && !charging) {
showLowBatteryWarning()
}
}
6.3 自动关机与熄屏策略
为节省电量,设置 10 分钟无操作自动关机:
CxrApi.getInstance().setPowerOffTimeout(10) // 单位:分钟
CxrApi.getInstance().setScreenOffTimeout(60) // 60秒无操作熄屏
七、异常处理与健壮性设计
7.1 连接断开重连机制
监听 onDisconnected()
,尝试自动重连:
override fun onDisconnected() {
viewModel.setConnectionStatus(false)
// 延迟 3 秒后重试
handler.postDelayed({
if (lastMac != null && lastUuid != null) {
connectBluetooth(lastUuid!!, lastMac!!)
}
}, 3000)
}
7.2 权限缺失友好提示
若用户拒绝关键权限,引导其手动开启:
if (!allGranted) {
AlertDialog.Builder(this)
.setTitle("权限不足")
.setMessage("请授予位置和蓝牙权限,否则无法连接眼镜")
.setPositiveButton("去设置") { _, _ ->
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.parse("package:$packageName")
startActivity(intent)
}
.show()
}
7.3 SDK 错误码解析
CXR-M SDK 定义了详细的错误码(如 CxrBluetoothErrorCode.SOCKET_CONNECT_FAILED
),我在日志中统一映射为用户可读信息:
when (errorCode) {
ValueUtil.CxrBluetoothErrorCode.BLE_CONNECT_FAILED -> "蓝牙连接失败,请靠近眼镜重试"
ValueUtil.CxrWifiErrorCode.WIFI_DISABLED -> "请先打开手机 Wi-Fi"
else -> "未知错误,请重启应用"
}
八、性能优化与用户体验细节
8.1 避免频繁发送相同内容
在发送提词脚本前,做内容哈希比对,避免重复传输:
if (currentScriptHash != newScript.hashCode()) {
sendScript(newScript)
currentScriptHash = newScript.hashCode()
}
8.2 Wi-Fi P2P 按需开启
仅在用户点击“同步历史图片”时才初始化 Wi-Fi,用完立即 deinitWifiP2P()
。
8.3 自定义页面作为备选方案
若未来提词需求复杂(如图文混排),可使用「自定义页面场景」:
{
"type": "LinearLayout",
"props": { "orientation": "vertical" },
"children": [
{ "type": "TextView", "props": { "text": "标题", "textSize": "20sp" } },
{ "type": "ImageView", "props": { "name": "icon1" } }
]
}
先调用 sendCustomViewIcons()
上传图标,再 openCustomView(json)
显示。
九、总结与展望
通过本次实践,我深刻体会到 Rokid CXR-M SDK 的强大与易用:
- 连接稳定:蓝牙 + Wi-Fi 双通道设计,兼顾控制与传输;
- 场景丰富:提词器、翻译、AI 助手等开箱即用;
- 控制精细:从亮度、音量到关机策略,全面掌控设备;
- 扩展灵活:自定义页面 JSON 方案,极大降低眼镜端开发门槛。
目前,这款「AI 智能提词眼镜助手」已在内部测试中获得良好反馈。下一步,我计划:
- 集成云端脚本管理,支持多设备同步;
- 增加多语言实时翻译提词;
- 利用摄像头实现「眼神控制滚动」。
Rokid Glasses 不只是一副眼镜,更是通往空间计算未来的入口。而 CXR-M SDK,正是我们开发者手中的钥匙。
更多推荐
所有评论(0)