Friend(Omi)iOS 集成指南:Ray-Ban Meta DAT 全功能构建、配对与验证
【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend
Friend(Omi)iOS 客户端默认只支持 Ray-Ban Meta 的纯音频模式(通过蓝牙 HFP 采集眼镜麦克风),而本文将讲解如何构建并验证全功能(full)DAT 模式——它额外启用 Meta Wearables Device Access Toolkit(DAT)的相机/照片拍摄能力,是创始人验收(founder acceptance)的硬性前置条件。读完本文,你将掌握:DAT target 的隔离原理、无需开发者中心凭据的 Developer Mode 测试流程、rayban_dat.sh构建脚本的事务性用法、眼镜配对授权步骤,以及从麦克风路由、照片回传到会话来源标注的完整验证清单。
背景:两种构建模式与getAvailabilityMode()
Friend 的 iOS 工程为 Ray-Ban Meta 支持设计了两个互斥的构建产物:
- audio_only(默认):不链接任何 Meta SDK,不携带凭据。仅通过 AVAudioSession 的蓝牙 HFP 路由采集眼镜麦克风,相机相关调用一律返回不可用。
- full(DAT 全功能):链接
MWDATCore与MWDATCamera,支持相机/照片拍摄 + HFP 音频,是本文档所描述的目标构建。
模式判定逻辑位于 RayBanMetaHostApiImpl.swift:getAvailabilityMode()通过#if canImport(MWDATCore)编译期条件返回"full",否则返回"audio_only"。这意味着模式完全由是否链接了 SDK 决定,而不是由是否配置了凭据决定——这一点是理解后续凭据章节的关键。
前置条件
按 rayban-meta-dat-setup.md 的清单,完整 DAT 构建需要:
- 硬件:Ray-Ban Meta(Gen 1/Gen 2)或 Oakley Meta 眼镜,在测试 iPhone 上通过Meta AI app配对,并更新到当前眼镜固件。
- 开发者模式:在 Meta AI app 中为本地测试开启眼镜 Developer Mode。Meta Wearables Developer Center 的 app、
MetaAppID、ClientToken仅在未来的 beta 渠道分发构建中才需要。 - 发布限制:截至文档写作时,DAT 应用尚不能通过 App Store 上架,本检查清单使用本地开发构建。
- 工具链:Xcode 26(含 iOS 26 SDK)、CocoaPods 1.16.2、Flutter 3.44.5、iOS 15.2+ 真机。当前源码使用的
.allowBluetoothHFPAPI 需要 iOS 26 SDK 才能编译,但应用仍可后向部署到 iOS 15.2。
Step 1 — 确认隔离的 DAT target
工程将 Facebook 的meta-wearables-dat-ios包精确锁定在 0.8.0(源码中的锁定 revision 为2e30f1253ab76ee3c448a29dce39114ab09763c3)。MWDATCore和MWDATCamera两个产品只属于RunnerRayBanDattarget(对应raybanDatflavor);它们绝不能混入默认的Runnertarget,因为默认Runner仍链接mcumgr_flutter用于 Omi 吊坠(pendant)固件 OTA 升级。
无需打开 Xcode,可直接运行提交到仓库的图结构校验测试验证这一点:
ruby app/ios/test/rayban_dat_xcode_graph_test.rb该测试 rayban_dat_xcode_graph_test.rb 会断言:
- 默认
Runnertarget 不包含MWDATCore/MWDATCamera产品; RunnerRayBanDattarget 的 package 产品恰好是MWDATCamera与MWDATCore两个;- 远程包被钉在
meta-wearables-dat-ios的精确0.8.0版本并核对Package.resolved中的 revision; - DAT target 使用独立的
Debug-raybanDat/Profile-raybanDat/Release-raybanDat配置,并强制DEVELOPMENT_TEAM = 9536L8KLMP、PRODUCT_BUNDLE_IDENTIFIER = com.friend-app-with-wearable.ios12.development、IPHONEOS_DEPLOYMENT_TARGET = 15.2、SWIFT_VERSION = 5.0; - 共享 Flutter scheme 只构建
RunnerRayBanDat; - CocoaPods 的 Podfile 中声明了独立的
RunnerRayBanDataggregate target。
在源码侧,RayBanMetaHostApiImpl.swift 用#if canImport(MWDATCore)/#if canImport(MWDATCamera)包裹 SDK 导入,只有在该 target 内才激活完整路径;未链接 SDK 时全部相机与注册 API 抛出camera_unavailable/dat_unavailable错误,不会伪装成功。MWDATMockDevice有意不链接进默认产物,仅在需要临时无硬件测试时加到RunnerRayBanDat。
Step 2 — 凭据:仅分发构建需要(Developer Mode 直接跳过)
Developer Mode 测试完全不需要 Developer Center 配置。Meta 官方的 DAT 示例流程是:在 Meta AI app 中打开眼镜 Developer Mode → 启动本地构建的 app → Connect。Developer Center 的 “Mobile app configuration”(Team ID / Bundle ID / 凭据)只对 Meta beta 渠道分发生效。
已知的分发阻塞点:Meta 的 Bundle ID 字段拒绝连字符(hyphen),而 Omi 的 iOS bundle id(com.friend-app-with-wearable.ios12[.development])均含连字符——未来若要走 Meta 渠道分发,需要申请一个不含连字符的专用 bundle identifier。在 beta 发布前应跟踪此问题。
分发凭据的暂存位置(将来需要时)
Info.plist已经携带了 Developer Mode 安全的MWDAT字典:omirayban://回调 scheme 与DAMEnabled(见 Info.plist 与 Info-Dev.plist)。它刻意不包含MetaAppID或ClientToken,因为 Meta 的 Developer Mode 流程要求不带这两个凭据键运行。仓库中的 xcconfig 模板(git-ignored)是未来 beta/分发工作的暂存位置:
cd app/ios/Flutter cp RayBanMetaCredentials.xcconfig.template RayBanMetaCredentials.xcconfig # 从 Developer Center 填入 META_APP_ID 与 META_CLIENT_TOKEN模板文件 RayBanMetaCredentials.xcconfig.template 内的注释明确提醒:当前 Xcode 工程并不会消费META_APP_ID/META_CLIENT_TOKEN,除非同时为分发构建增加专用的 Info.plist/build-setting 映射。
再次强调一个容易误解的点:getAvailabilityMode()只要链接了 DAT SDK 就返回full,凭据不参与模式判定。真正的分发集成路径是:通过专用 build configuration 或 plist overlay 把MetaAppID/ClientToken加入MWDAT字典,然后在 Wearables Developer Center 的 app 设置中注册精确的omirayban://scheme 与你的 iOS bundle id。
无需额外操作的内容:Omi 的 Info.plist 已包含NSMicrophoneUsageDescription、NSBluetoothAlwaysUsageDescription、NSCameraUsageDescription以及后台模式audio。
Step 3 — 构建:rayban_dat.sh的 DAT-only 依赖图
建议在新 clone 的检出中先执行一次标准的bash setup.sh ios以生成 Firebase 文件与 Dart 源码,然后停止其默认启动动作;之后再设置.dev.env——DAT 的 xcconfig 会强制使用精确的 development team 与 bundle ID,即使 setup 生成了机器相关的Custom.xcconfig也不会覆盖它。
若使用本地后端,先启动它并把打印的局域网地址写入app/.dev.env,让 iPhone 可达:
cd backend ./scripts/dev-serve.sh cd ../app # .dev.env # API_BASE_URL=http://<mac-lan-ip>:<printed-port>/ # USE_WEB_AUTH=true # USE_AUTH_CUSTOM_TOKEN=true FLUTTER_BIN=/path/to/flutter-3.44.5/bin/flutter \ scripts/rayban_dat.sh run -d <physical-iphone-id>包装脚本做了什么
rayban_dat.sh 是整个 DAT 构建的核心事务性包装器,支持run、build [ios|ipa]、restore三个子命令:
- 前置校验:以
--enforce-lockfile运行pub get,并通过assert_default_generated_state确认当前处于默认(非 DAT)图:Podfile.lock含mcumgr_flutter与SwiftProtobuf,插件元数据与GeneratedPluginRegistrant.m中都有 mcumgr 条目,且生成的 xcconfig 中没有任何raybanDat/OMI_RAYBAN_DAT泄漏。 - 快照:备份
Podfile.lock、Flutter/Generated.xcconfig、Flutter/flutter_export_environment.sh(含“原本就不存在”的占位标记)到.dart_tool/rayban_dat_build。 - DAT-only 插件变换:以
OMI_RAYBAN_DAT=1调用 rayban_dat_plugin_boundary.rb 的prepare——从.flutter-plugins-dependencies的iOS插件列表中移除mcumgr_flutter条目(Android 列表刻意保留),并从GeneratedPluginRegistrant.m中删除对应的 import 与注册调用;若发现生成文件被外部改动,会拒绝覆盖。 - CocoaPods 安装:在
OMI_RAYBAN_DAT=1下执行pod install,此时 Podfile 走RunnerRayBanDat分支(静态链接 + modular headers + TwilioVoice),而非默认的Runner分支(后者保留mcumgr_flutter固件 OTA)。 - 运行/构建:
flutter run(或build ios|ipa)带--flavor raybanDat --dart-define=OMI_RAYBAN_DAT=true --no-pub。 - 退出清理:无论成功失败,
trap EXIT都会触发restore_default_state——恢复插件生成文件、以原锁文件为准重新pod install默认图、还原Generated.xcconfig与flutter_export_environment.sh的字节级原貌,并再次断言默认图完好。
若清理过程被中断(如强杀进程导致 EXIT 陷阱未执行),用scripts/rayban_dat.sh restore手动恢复;脚本启动时检测到.dart_tool/rayban_dat_build残留也会强制你先 restore。默认的flutter run --flavor dev仍是纯音频构建,与 DAT 完全隔离。
构建产物的 xcconfig(如 raybanDatDebug.xcconfig)固定了DEVELOPMENT_TEAM=9536L8KLMP、APP_BUNDLE_IDENTIFIER=com.friend-app-with-wearable.ios12.development、IPHONEOS_DEPLOYMENT_TARGET=15.2与ASSET_PREFIX=dev等值。
运行中的 DAT 构建里,getAvailabilityMode()返回full。
Step 4 — 在 Omi 内授权与配对
按 rayban-meta-dat-setup.md 的步骤:
- 在装有 Meta AI app 且已配对眼镜的 iPhone 上启动 Omi。
- 主页 → 电量胶囊 →Connect(或 onboarding 设备列表)。
- 列表中出现Ray-Ban Meta→ 点击它。
- 设置面板会打开 Meta AI(Connect through Meta AI);在 Meta AI 中批准授权;Meta AI 通过 deep link 返回 Omi。
- 面板请求时授予眼镜相机权限(用于照片拍摄),或跳过以获得纯音频行为。
- 眼镜连接成功并成为当前激活的采集设备。
从源码看,配对链路由 RayBanMetaHostApiImpl.swift 实现:startRegistration()调用Wearables.shared.startRegistration()并监听registrationStateStream();Meta AI 的回调 URL 通过handleUrl(_:)进入——它以MWDAT字典里的AppLinkURLScheme(默认回退omirayban)做 scheme 匹配后异步交给 SDK 消费,绝不阻塞主线程;连接则通过AutoDeviceSelector创建DeviceSession,用stateStream()把connecting → connected → disconnected状态推回 Flutter 端。音频路由、照片回传等事件统一经 Pigeon 生成的RayBanMetaFlutterAPI上行通知。
验证清单
- 麦克风路由:开始采集后,已连接设备页显示 “Microphone ready”;iOS 控制中心显示输入源为眼镜;说话后数秒内 Omi 中出现 transcript 片段。底层实现见 RayBanMetaAudioCapture.swift:
AVAudioSession以.playAndRecord+.allowBluetoothHFP选择眼镜 HFP 输入端口,AVAudioEngine安装 tap 后经AVAudioConverter输出 PCM16 单声道 16 kHz 帧;路由丢失、通话中断、引擎配置变更都会主动停止并上报错误,避免静默录错音源。 - 照片:已连接设备页 →Capture Photo;眼镜的拍摄 LED 亮起;约 10 秒内照片出现在进行中的会话中(后端记录
photo_described事件)。拍摄进行期间还会每 30 秒自动拍一张。源码侧startCamera()遵循 Meta 的顺序约束——HFP 音频必须先完全就绪再启动 DAT 相机流,否则音频路由会静默失败;相机流以raw编码、low分辨率、2 fps 的最低帧率运行,仅为武装照片拍摄与硬件隐私 LED,不承担视频传输职责;photoDataPublisher收到 JPEG 后回传(DAT 0.8 不暴露方向元数据,统一按 orientation 0 解码)。 - 会话来源标注:结束的会话携带
source=rayban_meta,可通过GET /v1/conversations或来源标签查看。后端侧 conversation_enums.py 定义了rayban_meta来源枚举,message_event.py 定义了photo_described事件类型,test_rayban_meta_source.py 专门回归验证该来源在 /v4/listen 流中不被后续照片处理覆盖。
MockDevice:无硬件测试
将MWDATMockDevice加入RunnerRayBanDat的 Debug 配置,并参照 Meta 的 MockDeviceKit 文档,可模拟已配对设备、权限状态与照片拍摄。它适合在没有 CI 的环境下演练配对面板与照片流水线;但创始人验收仍必须使用真实眼镜。
从源码结构看,mock 接入点与真实链路完全一致——同样走registrationStateStream/devicesStream/ 相机权限与photoDataPublisher通道,因此可以用它先行验证 Flutter 侧 UI 与 Pigeon 桥接,再切换到真机验收。
【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考