3.F 修复:mediaTypeAudio.user 字段兼容 number 与 string

## 问题

实测 H5 调 mediaTypeAudio 传入:
  {audiourl: "http://...amr", user: 0, type: 1}

user 是 number(0),不是 string。我之前用 obj["user"]?.asString 严格
要求 string,导致解析失败 → silent return,远端语音无法播放。

## 根因

daoqi 用 `[data objectForKey:@"user"]` 后 `[NSString stringWithFormat:
@"%@", userid]` 容忍 NSNumber(ObjC `%@` 对 NSNumber 调 description
自动转 string)。新外壳走 Swift 强类型解析,丢了这个隐式兼容。

## 修复

给 BridgeData 加 `asLooseString` 扩展:
  - string → 原样
  - number → 整数样 double 转 Int 字符串(0.0 → "0"),其它走 String(d)
  - bool   → "true"/"false"
  - null/array/object → nil

mediaTypeAudio handler 把 `obj["user"]?.asString` 改为
`obj["user"]?.asLooseString`。`audiourl` 保持 asString(URL 永远是
string)。

`asLooseString` 也可供其它 H5 字段类型不严格的 handler 复用。

## 验证

BuildProject 通过 0 错误。真机重试 mediaTypeAudio 应能正确解析
user=0 / user=12345 / user="abc" 等各种 H5 传入形态。
This commit is contained in:
joywayer
2026-06-24 02:12:21 +08:00
parent c3a0ddbf8b
commit b058990862
2 changed files with 27 additions and 3 deletions
@@ -109,6 +109,27 @@ extension BridgeData {
return nil
}
/// 宽松字符串:string 保持原样、number 自动转 String、bool 转 "true"/"false"。
///
/// 用于 H5 字段类型不严格的场景(如 mediaTypeAudio.user 实际可能传 number
/// 0/1/userId 或 string)。对齐 daoqi `[NSString stringWithFormat:@"%@",
/// data[@"user"]]` 的容忍行为—— ObjC `%@` 对 NSNumber 调用 description 自动
/// 转字符串。
nonisolated public var asLooseString: String? {
switch self {
case .string(let s): return s
case .number(let d):
// 整数样的 double 转 Int 字符串(如 0.0 → "0",避免无意义的 .0 尾巴)
if d == d.rounded(), d.isFinite, abs(d) < Double(Int.max) {
return String(Int(d))
}
return String(d)
case .bool(let b): return b ? "true" : "false"
case .null: return nil
case .array, .object: return nil
}
}
nonisolated public var asDouble: Double? {
if case .number(let d) = self { return d }
return nil
@@ -247,11 +247,14 @@ public enum RemoteAudioHandler {
bridge: any BridgeProtocol,
callback: BridgeCallback?
) async {
// 1. 解析入参(只有 audiourl + user 两个字段,对齐 daoqi
// NewRootVC.m:326-328 / gameController.m:435-437)
// 1. 解析入参(核心字段 audiourl + user,对齐 daoqi NewRootVC.m:326-328 /
// gameController.m:435-437;H5 实测也会带 type 字段但 daoqi 注释掉、不用)。
//
// ⚠️ user 字段在 H5 实测中是 number(如 0、12345),不是 string;用
// asLooseString 兼容两种类型(对齐 daoqi `%@` 格式化容忍 NSNumber 行为)
guard let obj = data?.asObject,
let urlString = obj["audiourl"]?.asString,
let user = obj["user"]?.asString,
let user = obj["user"]?.asLooseString,
let downloadURL = URL(string: urlString)
else {
log.error("mediaTypeAudio: bad params \(String(describing: data), privacy: .public)")