Omi React Native SDK 接入指南基于 BLE 连接可穿戴设备并实现实时音频流与转写【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend本篇指南围绕开源仓库中的 React Native SDK 文档 展开系统讲解如何通过omiai/omi-react-native在 iOS / Android 跨平台移动应用中连接 Omi 智能可穿戴设备从环境安装、平台权限配置到设备扫描、BLE 连接、音频码流订阅、电量读取再到 Deepgram / Parakeet / Whisper 实时语音转写。读完本文你将掌握一套可直接复制运行的完整接入流程并能理解 SDK 底层基于react-native-ble-plx的 BLE 协议实现与对应的 GATT 服务特征。一、SDK 概览与核心能力omiai/omi-react-native当前仓库版本 1.0.1见 package.json是一个 TypeScript 实现的 React Native SDK用于通过**蓝牙低功耗BLE**连接并交互 Omi 设备帮助开发者构建 iOS 与 Android 双端移动应用。其核心能力包括扫描附近的 Omi 设备并获取设备名、ID 与信号强度RSSI建立 / 断开 BLE 连接并监听连接状态变化读取设备当前音频编解码格式PCM16 / PCM8 / Opus订阅设备实时音频字节流读取设备电池电量0–100%集成 Deepgram、Parakeet、Whisper 三种流式语音转写引擎。从源码结构看SDK 采用纯 TypeScript 实现对react-native-ble-plx的BleManager进行封装将设备交互收敛为单个OmiConnection类见 src/OmiConnection.ts并提供类型化枚举与 STT 引擎工厂见 src/index.ts。二、安装与依赖在项目中通过 npm 或 yarn 安装 SDKnpm install omiai/omi-react-native # 或 yarn add omiai/omi-react-nativeSDK 依赖react-native-ble-plx完成底层 BLE 通信作为 peerDependency 声明要求^3.4.2需要单独安装npm install react-native-ble-plxiOS 特别提醒安装依赖后必须在 ios 目录下执行 Pod 安装否则会出现原生模块相关构建错误cd ios pod install从 omi-react-native.podspec 可见SDK 的 iOS 原生侧以 CocoaPods 形式发布platform :ios 13.0依赖React-Core因此pod install是 iOS 端正常链接 SDK 的必要步骤。SDK 同时通过react-native-builder-bob构建出commonjs/module/typescript三套产物见 package.json 中react-native-builder-bob配置package.json的react-native与source字段指向src/index的 TypeScript 入口。三、平台专属配置iOSInfo.plist 蓝牙权限在 iOS 工程的Info.plist中添加如下两个键值示例工程配置可参考 example/ios/OmiSDKExample/Info.plistkeyNSBluetoothAlwaysUsageDescription/key stringThis app uses Bluetooth to connect to Omi devices/string keyNSBluetoothPeripheralUsageDescription/key stringThis app uses Bluetooth to connect to Omi devices/string说明iOS 模拟器不支持蓝牙扫描调试 BLE 功能时必须使用真机。同时应打开.xcworkspace工作区文件而非.xcodeproj。AndroidAndroidManifest.xml 权限在 Android 工程的AndroidManifest.xml中声明蓝牙与定位权限示例见 example/android/app/src/main/AndroidManifest.xmluses-permission android:nameandroid.permission.BLUETOOTH/ uses-permission android:nameandroid.permission.BLUETOOTH_ADMIN/ uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION/ !-- 适用于 Android 12 -- uses-permission android:nameandroid.permission.BLUETOOTH_SCAN / uses-permission android:nameandroid.permission.BLUETOOTH_CONNECT /权限说明BLUETOOTH/BLUETOOTH_ADMINAndroid 11 及以下版本的基础蓝牙访问权限ACCESS_FINE_LOCATIONAndroid 11 及以下执行蓝牙扫描所必需的定位权限BLE 扫描被系统归类为位置相关操作BLUETOOTH_SCAN/BLUETOOTH_CONNECTAndroid 12 的运行时蓝牙权限。除清单声明外运行时还需在应用内请求权限。示例应用 example/App.tsx 展示了完整流程监听BleManager.onStateChange等待蓝牙PoweredOn随后通过一次空扫描触发系统权限弹窗若权限被拒或蓝牙关闭UI 会展示橙色状态横幅并提供 Open Settings 跳转系统设置、Request Permission 重新申请等交互。四、快速开始连接生命周期完整示例以下代码覆盖了从扫描到断开连接的完整生命周期取自 README 快速开始import { OmiConnection, DeviceConnectionState, BleAudioCodec } from omiai/omi-react-native; // 创建 OmiConnection 实例 const omiConnection new OmiConnection(); // 扫描设备回调中可拿到设备名与 ID const stopScan omiConnection.scanForDevices((device) { console.log(Found device:, device.name, device.id); }, 10000); // 扫描 10 秒 // 连接设备 async function connectToDevice(deviceId) { const success await omiConnection.connect(deviceId, (id, state) { console.log(Device ${id} connection state changed to: ${state}); }); if (success) { console.log(Connected successfully!); // 读取音频编解码格式 const codec await omiConnection.getAudioCodec(); console.log(Device audio codec:, codec); // 订阅音频字节流 const subscription await omiConnection.startAudioBytesListener((bytes) { console.log(Received audio bytes:, bytes.length); }); // 读取电量 const batteryLevel await omiConnection.getBatteryLevel(); console.log(Battery level:, batteryLevel); // 停止音频监听 await omiConnection.stopAudioBytesListener(subscription); // 断开连接 await omiConnection.disconnect(); } }生命周期管理要点scanForDevices返回一个停止扫描函数同时内部用setTimeout在超时后自动停止扫描见 src/OmiConnection.ts 第 35–67 行无论正常结束还是主动调用都应执行返回的 stop 函数以清理定时器。connect内部带有isConnecting重入保护连接进行中再次调用会直接返回false。连接成功后 SDK 通过device.onDisconnected注册断连监听设备意外断开时会自动清空内部状态并将DeviceConnectionState置为DISCONNECTED回调给上层。每次startAudioBytesListener都会返回一个Subscription停止监听必须调用stopAudioBytesListener(subscription)移除订阅避免泄漏。五、OmiConnection API 详解与底层 BLE 协议5.1 方法总览方法说明返回scanForDevices(onDeviceFound, timeoutMs)扫描附近 Omi 设备默认超时 10000ms停止扫描的函数connect(deviceId, onConnectionStateChanged)连接 Omi 设备Promisebooleandisconnect()断开当前设备PromisevoidisConnected()查询连接状态booleangetAudioCodec()获取设备音频编解码格式PromiseBleAudioCodecstartAudioBytesListener(callback)开始接收音频字节流PromiseSubscriptionstopAudioBytesListener(subscription)停止接收音频字节流PromisevoidgetBatteryLevel()获取电池电量百分比0–100Promisenumber另有只读属性connectedDeviceId返回当前已连接设备的 ID便于 UI 层做当前设备高亮等判断示例应用即用它判断按钮应显示 Connect 还是 Disconnect。5.2 GATT 服务与特征 UUIDSDK 与设备通信所依赖的 BLE GATT 契约与 sdks/device/PROTOCOL.md 中定义的共享协议一致由src/OmiConnection.ts第 6–12 行硬编码角色UUIDOmi 服务19b10000-e8f2-537e-4f6c-d104768a1214音频数据流特征notify19b10001-e8f2-537e-4f6c-d104768a1214音频编解码特征read19b10002-e8f2-537e-4f6c-d104768a1214电池服务0000180f-0000-1000-8000-00805f9b34fb电池电量特征00002a19-0000-1000-8000-00805f9b34fb补充设备端还存在按钮服务23ba7924-0000-1000-7450-346eac492e92与按钮触发特征23ba7925-0000-1000-7450-346eac492e92可用于按钮状态读取与按压事件监听详见 omi_connection_doc.md。5.3 连接过程connect从源码实现看connect的关键步骤是Android 请求更大 MTU连接时传入{ requestMTU: 512 }仅 Android以规避 GATT 传输错误iOS 不传该选项connectToDevice建立链路层连接discoverAllServicesAndCharacteristics()发现全部服务与特征注册onDisconnected断连监听并回调CONNECTED状态。5.4 音频编解码协商getAudioCodec设备通过音频编解码特征的首字节上报编解码 IDSDK 读取并 base64 解码后按如下映射转换为BleAudioCodec枚举与 sdks/device/PROTOCOL.md 的 Codec ID 表一致ID编解码说明0PCM1616-bit PCM对应BleAudioCodec.PCM161PCM88-bit PCM对应BleAudioCodec.PCM8默认编解码20 /0x14OPUSOpusDevKit 固件160 采样 PDM 帧10ms 100fps21 /0x15Opus FS320Omi CV1 固件320 采样 PDM 帧20ms 50fps解码后同为 Opus 契约需要注意默认回退值为 PCM8——当特征缺失、读取失败或读到未知 ID 时getAudioCodec会返回BleAudioCodec.PCM8而非抛出异常见 src/OmiConnection.ts 第 202–267 行。这一点有专门的回归测试覆盖codec id 0零值字节必须解析为 PCM16 而非错误回退到 PCM8见 src/tests/zero-value.test.ts。mapCodecToName工具函数src/codecs.ts可将枚举映射为PCM 16-bit、PCM 8-bit、Opus等可读名称。5.5 音频字节流订阅startAudioBytesListener音频数据通过 notify 特征持续下发SDK 的实现要点定位 Omi 服务的音频数据流特征19b10001-...先尝试读取一次初始值确认特征可访问失败不阻断流程调用characteristic.monitor()建立通知订阅每次通知将 base64 数据解码为字节数组裁掉前 3 字节的音频包头部帧结构为[3-byte header][codec payload...]与 sdks/device/PROTOCOL.md 定义的协议一致再将剩余载荷通过回调上抛。回调收到的是number[]形式的音频载荷可直接送入 STT 引擎或 Opus/PCM 解码器。设备默认输出16-bit 小端序单声道 16kHz PCM数据。注意3 字节帧头与编解码映射均为固件耦合项协议明确要求修改时必须与其他设备 SDKPython / Swift / Go / Rust 等同步变更。5.6 电量读取getBatteryLevel通过标准电池服务0000180f-...的电量特征00002a19-...读取首字节作为百分比。读取失败或特征缺失时返回-1表示未知测试同样覆盖了零值字节应返回 0 而非 -1的边界情况。六、实时语音转写三种 STT 引擎除 BLE 连接能力外SDK 还提供与 Python、Swift 等 SDK 对等的流式语音转写能力见 src/stt/index.ts通过统一的createTranscriber工厂创建统一接口StreamingTranscriber只包含appendPcm(chunk)与stop()两个方法见 src/stt/types.ts。type SttEngine deepgram | whisper | parakeet; interface StreamingTranscriber { appendPcm(chunk: Uint8Array | ArrayBuffer): void; stop(): void; }6.1 Deepgram云端流式转写createDeepgramTranscriber通过 WebSocket 连接wss://api.deepgram.com/v1/listen默认参数为punctuatetruemodelnovalanguageen-USencodinglinear16sample_rate16000channels1默认采样率 16000见 src/stt/deepgram.ts。实现上有两个工程细节值得注意必须注入createWebSocketReact Native 与浏览器环境无法在 WebSocket 构造后再附加Authorization头因此调用方需自行提供能携带 header 的 WebSocket 工厂如react-native的 WebSocket 实现支持传入{ headers }优雅关闭stop()会先发送{type:CloseStream}再关闭连接且对发送失败、已关闭等异常路径做了容错有专项测试 src/tests/deepgram-stop.test.ts 验证 CloseStream 发送顺序与关闭行为。6.2 Parakeet自托管流式转写createParakeetTranscriber连接自托管 Parakeet 服务的 WebSocket 端点URL 由parakeetWsUrl生成将http(s)协议替换为ws(s)并拼接/v3/stream?sample_rate16000。其协议约定服务端先发送{type:ready}表示就绪此后才接受音频帧返回结果支持text、transcript或segments[].text多种字段形态见 src/stt/parakeet.ts。API 地址可通过options.apiUrl显式传入或由环境变量HOSTED_PARAKEET_API_URL提供。6.3 Whisper本地离线转写createWhisperTranscriber面向完全离线的本地场景需要注入一个whisperRunner回调如原生模块、whisper.rn等来将 PCM 数据转换为文本。SDK 内部按batchSeconds默认 5 秒聚合音频以约 5 秒 × 16000Hz × 2 字节的批量窗口切分并通过串行队列保证推理顺序见 src/stt/whisper.ts。6.4 完整转写流程示例应用实践example/App.tsx 展示了与 Deepgram 联动的完整链路关键顺序约束与 README 的 Troubleshooting 一致先启动音频监听再开启转写——转写依赖音频回调推入缓冲开启转写时通过WebSocket连接 DeepgramURL 参数为sample_rate16000encodingopuschannels1modelnova-3languageen-USsmart_formattrueinterim_resultsfalsepunctuatetruediarizetrue每 250ms 将累积的音频缓冲批量发送给 WebSocket收到channel.alternatives[0].transcript后带时间戳与说话人标签[Speaker n]追加到转写列表仅保留最近 5 条停止音频监听或关闭转写开关时同步关闭 WebSocket 并清空处理定时器与缓冲。七、完整可运行的示例应用仓库提供了基于 Expo 的完整示例工程sdks/react-native/example覆盖 SDK 全部能力的真实交互。启动方式cd sdks/react-native/example npm install # 或 yarn install npm start # 启动 Expo 开发服务器 npm run ios # 运行到 iOS 真机BLE 在模拟器不可用 npm run android # 运行到 Android 设备需开启 USB 调试示例应用包含如下功能模块对应 example/README.md蓝牙状态横幅蓝牙未开启 / 权限未授予 / 不可用时展示提示并提供打开系统设置与重新申请权限的入口设备扫描默认 30 秒超时自动停止也可手动停止扫描结果列表展示设备名与 RSSIdBm连接管理Connect / Disconnect 按钮随连接状态切换连接成功后自动停止扫描设备功能读取并展示音频编解码格式、电池电量带百分比进度条、启动 / 停止音频监听并实时统计收到的音频包数量采用 500ms 批量更新避免高频 setStateDeepgram 转写开关式启用输入 API Key 后一键开始 / 停止实时转写结果带时间戳与说话人标签显示在页面底部。UI 层在ScrollView底部预留了paddingBottom: 200的内边距用于防止键盘弹出遮挡输入框——这正是 README Troubleshooting 中键盘遮挡输入框条目的实现出处。八、工程质量与测试SDK 配套了针对关键边界的回归测试npm test配置见 jest.config.issue12979.jszero-value.test.ts覆盖 issue #12979——合法零值 BLE 特征不得被当作缺失。验证 codec 字节0x00必须解析为 PCM16而非回退 PCM8、电量字节0x00必须返回 0而非 -1、空载荷仍保持原有回退逻辑、非零 codec ID如 20 → OPUS映射不变deepgram-stop.test.ts验证 Deepgram 转写器stop()的 CloseStream 发送顺序、发送失败容错与重复关闭防护whisper-stop.test.ts覆盖 Whisper 本地转写器的停止与批量刷新行为entrypoint-resolution.test.ts回归 issue #13151——确保 Metro 的 JS 优先解析不会加载遗留的src/index.js旧桥接代码遮蔽 TypeScript 入口验证最终解析到index.ts且导出集合完整单元测试通过 jest/mock.js 提供的OmiConnectionMock 支撑无需真实蓝牙硬件即可编写测试。九、故障排查指南以下为 README 官方 Troubleshooting 的完整整理按问题分类给出解决步骤1. iOS 构建报原生模块错误确认已在 ios 目录执行过pod install尝试清理构建产物Product → Clean Build Folder确保打开的是.xcworkspace文件而不是.xcodeproj。2. 扫描不到设备确认手机蓝牙已开启检查是否已授予必要权限iOS 的蓝牙权限、Android 的位置 蓝牙权限确保 Omi 设备已开机且在有效范围内iOS 模拟器不支持蓝牙扫描必须使用真机调试。3. 连接失败尝试重启 Omi 设备确认设备未被其他应用占用连接检查 Omi 设备电量是否充足。4. 收不到音频数据确认设备支持音频服务Omi 服务19b10000-...及音频数据流特征存在检查回调中对音频字节数组的处理是否正确回调收到的是已剥离 3 字节帧头的载荷。5. 转写不工作确认 Deepgram API Key 有效必须先启动音频监听再开启转写确认网络连接稳定转写依赖 WebSocket 长连接。6. 键盘遮挡输入框示例应用已在ScrollView底部加入内边距paddingBottom: 200确保键盘弹出时输入框可见你自己的应用可参照同样做法。十、相关资源导航SDK 类型与枚举定义sdks/react-native/src/types.tsBleAudioCodec、DeviceConnectionState、OmiDevice、AudioProcessingOptions、AudioDataEvent、ConnectionStateEvent核心连接实现sdks/react-native/src/OmiConnection.tsSTT 引擎工厂与实现sdks/react-native/src/stt/index.ts、sdks/react-native/src/stt/deepgram.ts、sdks/react-native/src/stt/parakeet.ts、sdks/react-native/src/stt/whisper.tsBLE 设备协议契约GATT 表、Codec ID、音频帧结构sdks/device/PROTOCOL.md设备连接功能补充文档sdks/react-native/omi_connection_doc.md示例应用sdks/react-native/example/App.tsx、sdks/react-native/example/README.mdSDK 官方文档源文件docs/doc/developer/sdk/ReactNative.mdx适用前提与限制本 SDK 为 TypeScript 实现需配合 React Native 0.79.x / React 19 环境见 package.json devDependenciesNode 要求 16BLE 能力依赖react-native-ble-plx ^3.4.2iOS 侧要求 iOS 13.0蓝牙相关功能均需真机验证模拟器无法使用。【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
