3.E 修复:首次启动权限请求与浮层 touchObserver 死锁

## 问题

首次启动 app,H5 按住麦克风按钮触发 prepareaudio:
1. 主动调 AVAudioSession.requestRecordPermission 弹系统权限对话框
2. 用户为了点"允许"必须松手
3. 松手被 RecordingAwareWindow.touchObserver 立刻捕获 → recorder.stop()
4. 浮层瞬间关闭,录音失败
5. 用户感受:"按一次没反应,再点也没用"

## 根因

我之前用 `requestRecordPermission` 主动请求权限(会同步弹系统对话框),
与 daoqi `FuncPublic.ifauth`(只读 `AVCaptureDevice.authorizationStatus`,
不主动请求)行为不一致。主动请求 + 按住状态 + touchObserver 全局监听
三者形成死锁。

## 修复

改用只读状态 + 三分支处理:

- `.denied / .restricted`:弹 Alert + return(对齐 daoqi)
- `.notDetermined`(首次):**主动弹权限对话框但不启动录音浮层**。
  用户做完选择后 return,不触发 cb。第二次按录音按钮时走 .authorized
  分支正常录音
- `.authorized`:直接启动录音浮层

## 与 daoqi 行为对比

daoqi 在 .notDetermined 时 ifauth 返回 1(继续启动录音),但实测此路径
也有体验问题——浮层弹出 + 系统对话框遮挡 + 用户松手立刻触发 touchEnded
→ 录音空文件 → 转码失败 → silent return。最终用户体验也是"按一次没
反应"。

新外壳的修复让首次行为更明确(不启动录音 = 不会有空文件上传),与 daoqi
真实终态(不触发 getaudiourl)等价,UX 等价(首次启动需按两次)。

## H5 契约影响

无。"不触发 cb" 与 daoqi 转码失败 silent return 等价;H5 收不到
getaudiourl 反向 callback 时本来就要兼容(daoqi 各类失败路径都不触发 cb)。

## 验证

BuildProject 通过 0 错误。
This commit is contained in:
joywayer
2026-06-24 01:50:04 +08:00
parent df2a099fb5
commit 97749ac177
@@ -85,16 +85,39 @@ public enum RemoteAudioHandler {
isSubGame: Bool,
callback: BridgeCallback?
) async {
// 1.
let granted: Bool = await withCheckedContinuation { cont in
AVAudioSession.sharedInstance().requestRecordPermission { ok in
cont.resume(returning: ok)
}
}
guard granted else {
// Alert + callback daoqi NewRootVC.m:314-319
// 1. **** daoqi FuncPublic.m:1144-1170 ifauth
// requestRecordPermission iOS
// H5 ""
// RecordingAwareWindow.touchObserver stop
// app
let status = AVCaptureDevice.authorizationStatus(for: .audio)
switch status {
case .denied, .restricted:
// Alert + cb daoqi NewRootVC.m:314-319
showMicrophonePermissionAlert(on: hostVC())
return
case .notDetermined:
// **** touchObserver
// / .authorized
//
// daoqi ifauth .notDetermined 1 daoqi
// NotificationCenter touchObserver
// daoqi "" return
// " = = "
_ = await withCheckedContinuation { cont in
AVAudioSession.sharedInstance().requestRecordPermission { granted in
cont.resume(returning: granted)
}
}
// / cbH5 cb
return
case .authorized:
break //
@unknown default:
return
}
// 2.