# iOS PiP 语音会话保活规划 > **文档状态**:产品与架构规划(待验证,未进入实现) > **适用范围**:iOS 主 App + 键盘扩展 + Live Activity > **目标版本**:待产品验证后确定 > **创建日期**:2026-07-26 --- ## 1. Executive Summary ### 1.1 目标 在不要求 OSGKeyboard 长时间占用麦克风的前提下,尽量保持主 App 可响应键盘扩展的听写指令,降低用户在宿主 App 与 OSGKeyboard 之间反复切换的频率。 核心方向是将两个当前耦合的能力拆开: 1. **会话可用性**:主 App 仍可接收键盘命令。 2. **麦克风采集**:仅在用户明确开始听写时启用,完成后立即释放。 PiP(画中画)只承担系统可见的多任务会话载体,不绕过麦克风授权,也不应使用静音音频循环伪造后台活动。 ### 1.2 核心结论 | 决策 | 规划选择 | |------|----------| | 产品定位 | 将 PiP 作为可选的「免切换模式」,不替代普通 Flow | | 麦克风策略 | PiP 空闲时关闭;键盘点按听写后按需激活 | | 默认策略 | 保留当前隐私友好的 5 分钟 Flow;PiP 由用户主动开启 | | 降级路径 | PiP 不可用或失效时回落到现有 `startflow` 冷启动流程 | | 状态展示 | PiP 显示有意义的语音会话状态;Live Activity 继续负责锁屏与灵动岛 | | 禁止方案 | 不播放静音文件保活,不使用定位或 VoIP 等无关后台模式 | | 上线方式 | 先做真机技术验证和 TestFlight 审核验证,再决定正式产品化 | ### 1.3 非目标 - 不让键盘扩展直接访问麦克风;这是 iOS 平台限制。 - 不承诺 App 被用户强制退出后仍可免切换听写。 - 不承诺电话、Siri、相机或其他录音 App 抢占音频设备时继续录音。 - 不用 PiP 绕过麦克风权限、隐私提示或系统音频策略。 - 第一阶段不重写 ASR、润色、App Group 或 Darwin 通知管线。 --- ## 2. 问题定义 ### 2.1 平台约束 iOS 键盘扩展无法直接申请或使用麦克风。系统级语音键盘因此必须采用: ```text 键盘扩展 → 发送开始/停止命令 → 主 App 采集并转写 → App Group 返回结果 → 键盘插入文本 ``` 当主 App 被系统挂起或终止时,键盘无法即时启动录音,只能打开主 App 重新建立会话。当前 Flow 通过持续运行 `AVAudioEngine` 输入链路换取后台可用性,但会带来麦克风长期占用、橙色隐私指示、电量消耗和音频冲突。 ### 2.2 用户问题 | 用户感知 | 当前根因 | 目标变化 | |----------|----------|----------| | 频繁跳转主 App | 后台主进程不可响应 | PiP 有效时直接响应键盘命令 | | 麦克风指示长时间亮起 | Flow 会话级连续采集 | 空闲时释放麦克风 | | 耗电或发热 | 音频引擎持续采样和处理 | 仅听写期间采样 | | 其他 App 无法使用麦克风 | OSGKeyboard 持有输入设备 | 听写结束后主动释放 | | 不知道会话是否可用 | Flow、麦克风和进程状态混为一体 | 分开展示「免切换已就绪」和「正在录音」 | ### 2.3 成功定义 PiP 模式下,用户应能: 1. 在 OSGKeyboard 主 App 中主动开启免切换模式。 2. 将 PiP 小窗收纳到屏幕边缘。 3. 回到微信、邮件等宿主 App。 4. 点击键盘麦克风后直接开始听写。 5. 停止听写后收到文本,同时麦克风在短时间内释放。 6. PiP 失效时收到明确提示,并能通过现有冷启动路径恢复。 --- ## 3. 竞品与行业模式 ### 3.1 Typeless Typeless iOS 1.9.0 将该能力命名为 Picture in picture / Skip app switching: - 用户先在主 App 中主动开启。 - PiP 可拖到屏幕边缘收纳。 - 用户在其他 App 的 Typeless 键盘中开始说话。 - 官方产品说明强调麦克风空闲时关闭,以降低电量消耗。 其公开资料无法证明具体内部实现,因此本规划只借鉴产品模型,不假定其私有代码结构。 ### 3.2 Wispr Flow、TypeWhisper 与同类开源项目 常见架构是主 App 持有 `AVAudioEngine`,键盘通过 App Group 与 Darwin 通知控制句子开始和停止。优点是首字延迟低,缺点是会话期间通常持续占用音频输入。 OSGKeyboard 当前 Flow 已属于此模式,并已具备: - 主 App 会话所有权; - 键盘与主 App IPC; - 连续采集与 utterance gate; - App Group 结果回传; - Live Activity; - 冷启动与恢复流程。 因此 PiP 应作为会话生命周期的新载体,而不是重建整条语音管线。 ### 3.3 SuperWhisper / App Intents 路线 更保守的方案是不做长期后台保活,使用 App Intents、Action Button、快捷指令或显式 App 切换启动录音。该方案最符合系统预期,但无法完全满足键盘内即时听写。 OSGKeyboard 应保留这类入口作为稳定降级,而不是依赖 PiP 达到 100% 可用。 ### 3.4 合规边界 以下方式不应采用: - 循环播放静音音频以防止挂起; - 声明与产品无关的定位、VoIP 后台能力; - 使用不可见或无实际产品意义的伪视频,仅为延长进程生命; - 在用户未明确开启会话时自动恢复麦克风。 PiP 内容需要能被解释为真实的语音会话控制面,例如展示: - 「免切换已就绪」; - 「正在聆听」及音量反馈; - 「正在转写」; - 暂停、结束或返回 App 操作。 --- ## 4. 目标产品模型 ### 4.1 三层可用性 ```text 层级 0:冷启动 主 App 不可用 → 键盘打开 startflow → 主 App 建立语音会话 层级 1:短时 Flow AVAudioEngine 会话保持 → 最低首字延迟 → 默认 5 分钟无活动后结束 层级 2:PiP 免切换模式 PiP 保持用户可见的多任务会话 → 空闲时麦克风关闭 → 键盘命令触发按需开麦 ``` 三个层级必须共用同一份 `FlowSessionBridge` 状态合约,键盘不应根据实现细节分别写三套逻辑。 ### 4.2 用户入口 建议在首页提供独立状态卡,而不是继续扩张设置开关: - 未开启:`开启免切换模式` - 启动中:`正在准备画中画` - 已就绪:`免切换已就绪 · 麦克风未使用` - 录音中:`正在聆听` - 失效:`会话已断开,点击恢复` 首次开启时应明确说明: 1. 屏幕上会出现可收纳的 PiP 小窗。 2. 空闲时不会使用麦克风。 3. 用户关闭 PiP、强制退出 App 或系统回收进程后,需要重新开启。 ### 4.3 键盘状态 键盘麦克风状态应从「主 App 是否活着」升级为明确能力状态: | 状态 | 表现 | 点击结果 | |------|------|----------| | 不可用 | 灰色 | 引导权限或 Full Access | | 需恢复 | 橙色 | 打开主 App 恢复会话 | | PiP 就绪、麦克风关闭 | 绿色 | 请求主 App 按需开麦 | | 正在激活麦克风 | 绿色加载态 | 等待真实音频 proof | | 正在录音 | 红色/波形 | 发送停止命令 | | 正在转写 | 处理中 | 等待结果 | --- ## 5. 目标架构 ### 5.1 组件边界 ```text Keyboard Extension └─ FlowSessionBridge / Darwin command ↓ Host App ├─ VoiceSessionCoordinator │ ├─ FlowSessionManager │ ├─ PiPVoiceSessionController │ └─ AudioCaptureLifecycle ├─ FlowContinuousCapture ├─ ASR + Polish pipeline └─ Live Activity ``` 规划职责: - `PiPVoiceSessionController`:只管理 PiP 生命周期和展示状态。 - `AudioCaptureLifecycle`:管理按需激活、音频 proof、停止及释放。 - `FlowSessionManager`:继续负责命令、ASR、润色和结果回传。 - `FlowSessionBridge`:发布跨进程能力快照,不让键盘猜测主 App 状态。 ### 5.2 状态机 ```text inactive → preparingPiP → pipReadyMicOff → activatingMic → recording → processing → releasingMic → pipReadyMicOff 任意状态 → interrupted → recovering 或 inactive ``` 重要不变量: 1. `pipReadyMicOff` 必须确认音频输入已停止并释放。 2. 键盘只有在收到 `recording` 和真实 audio proof 后才显示正在录音。 3. PiP 存活不能等价于麦克风可用。 4. 电话/Siri 中断后不得静默恢复录音。 5. 任何超时都要回收麦克风并写入明确错误。 ### 5.3 PiP 内容方案 技术验证阶段应比较两类 Apple 官方能力: 1. 基于 `AVPlayerLayer` 的媒体 PiP; 2. 基于 `AVSampleBufferDisplayLayer` / 视频通话内容源的实时 PiP。 选择标准不是「哪种最容易保活」,而是: - 是否符合 OSGKeyboard 的真实产品用途; - 能否展示动态语音会话状态; - 麦克风激活/释放是否稳定; - 收纳、锁屏、音频中断行为是否可预测; - App Review 是否能清楚理解其用途。 在完成真机和审核验证前,不冻结具体 AVKit 实现。 --- ## 6. 实施阶段 ### Phase 0:技术与审核可行性验证 目标:证明「PiP 存活 + 闲时关麦 + 键盘触发按需开麦」在目标 iOS 版本可行。 验证项: - PiP 启动、收纳、恢复与关闭; - 空闲 30 分钟后主 App 是否仍能响应; - 空闲期间系统麦克风指示是否消失; - 键盘命令到首个有效音频帧的延迟; - 连续 20 次开始/停止是否稳定; - 电话、Siri、蓝牙切换、锁屏、低电量模式; - 用户关闭 PiP 后的降级行为; - TestFlight / App Review 说明是否被接受。 退出标准: - 空闲时没有麦克风占用; - P95 命令到有效音频帧小于 1 秒; - 20 次连续听写无僵尸录音或失联状态; - 失败后都能回到冷启动路径; - 没有使用静音循环或无关后台能力。 ### Phase 1:内部可用版本 - 新增 PiP 会话控制器; - 将持续采集改造成可重复激活/释放; - 扩展跨进程状态快照; - 键盘增加激活中、PiP 就绪和失效状态; - 复用现有 ASR、润色、结果回传和 Live Activity; - 添加状态机与 IPC 单元测试。 ### Phase 2:产品化 - 首页免切换状态卡; - 首次开启说明与 PiP 收纳引导; - 中英文文案与隐私说明; - 诊断页增加 PiP、音频会话和最近中断原因; - 增加遥测指标,但不采集音频内容。 ### Phase 3:灰度与决策 - TestFlight 小流量开启; - 比较 PiP 与普通 Flow 的成功率、首字延迟和耗电; - 根据审核反馈决定默认入口和长期支持范围; - 若 PiP 不稳定或审核风险不可接受,保留为实验功能或停止上线。 --- ## 7. 测试矩阵 ### 7.1 功能场景 | 场景 | 预期 | |------|------| | PiP 空闲 | 主 App 可响应,麦克风未占用 | | 键盘开始听写 | 按需激活并获得真实音频帧 | | 停止听写 | 完成转写并及时释放麦克风 | | 连续多句 | 每句均重新激活成功,无第二句无音频 | | PiP 被关闭 | 键盘切为需恢复,不显示假就绪 | | App 被强退 | 清除旧 generation 和僵尸状态 | | 电话/Siri 中断 | 当前句失败并提示,不自动偷录 | | 蓝牙设备变化 | 音频格式重建,不崩溃 | | 网络失败 | 本地 ASR 保留;润色按现有策略降级 | ### 7.2 设备与系统 - 最低支持 iOS 版本、当前稳定版和最新 beta; - 刘海机、灵动岛机型、iPad; - AirPods、普通蓝牙耳机、车载音频、有线设备; - 微信、信息、邮件、Slack、Notes 及自定义文本输入控件; - 锁屏、横竖屏、多窗口、低电量和后台刷新关闭状态。 --- ## 8. 指标与验收 ### 8.1 核心指标 | 指标 | 定义 | 目标 | |------|------|------| | 免切换成功率 | PiP 就绪时无需打开主 App完成听写 | ≥ 98% | | 麦克风空闲占用 | 非录音期间仍占麦的时长比例 | 接近 0 | | 首帧延迟 P95 | 键盘点击到真实音频 proof | < 1 秒 | | 结果回传成功率 | 停止后键盘收到最终结果 | ≥ 99% | | 僵尸状态率 | 键盘显示可用但主 App无法响应 | < 0.5% | | 恢复成功率 | 失效后通过冷启动恢复 | ≥ 99% | ### 8.2 观察指标 - 每日 PiP 开启人数与启用留存; - PiP 被用户主动关闭的比例; - 每小时耗电和温升相对普通 Flow 的变化; - 音频中断类型分布; - 用户因橙色麦克风指示或隐私产生的反馈; - App Review 反馈和政策变化。 --- ## 9. 风险与应对 | 风险 | 等级 | 应对 | |------|------|------| | PiP 被认定与媒体用途不匹配 | 高 | 提供真实会话 UI、明确审核说明;先 TestFlight/审核验证 | | 系统版本改变 PiP 行为 | 高 | 保持冷启动降级;按系统版本做兼容验证 | | 按需开麦首字丢失 | 中 | 激活态 + audio proof + 预录缓冲,不提前向键盘宣告录音 | | 频繁激活导致音频路由异常 | 中 | 串行状态机、格式重建、媒体服务重置恢复 | | PiP 与 Live Activity 状态冲突 | 中 | 单一 coordinator 发布状态,两个 UI 只消费 | | 用户误解 PiP 仍在监听 | 中 | 空闲状态明确写「麦克风未使用」,隐私说明可验证 | | 其他 App 抢占麦克风 | 中 | 显式中断提示,不承诺并发录音 | --- ## 10. 产品决策门 进入代码实现前,需要确认: 1. 是否接受 PiP 作为用户主动开启、系统可见且可收纳的产品形态; 2. 是否优先「空闲关麦」而接受约数百毫秒的重新激活延迟; 3. PiP 中展示哪些真实功能,确保它不是纯保活黑窗; 4. 是否将现有「跳过 App 切换」重命名并拆为普通 Flow / PiP 两种模式; 5. 最低支持系统和目标测试设备; 6. 技术验证失败或审核风险过高时,是否接受回退到短 Flow + App Intents。 在上述决策和 Phase 0 证据完成前,不建议直接进入正式实现。