ADR-009 凭证集中化:AppSecrets.plist + 七牛运行参数走 RemoteConfig.audio_*(契约影响)

【数据流改造(三分制)】
- 微信 AppID  唯一源 = Info.plist CFBundleURLTypes (URLName=weixin first scheme)
- 应用级凭证 唯一源 = AppSecrets.plist (wxAppSecret/qiniuAccessKey/qiniuSecretKey)
- 七牛运行参数 唯一源 = RemoteConfig 顶层 audio_domain / audio_bucket(远端动态注入)

【契约影响】
- ChannelConfig.plist:11 key → 10 key,移除 qiniudomain(ADR-007 守护规则同步)
- BundleConfig:删除 qiniuDomain 属性
- RemoteConfig:顶层新增可选字段 audioDomain / audioBucket(JSON snake_case 自动归一化)
- 启动期:WebContainerViewController parsed 分支校验 audio_domain/audio_bucket 非空,
  缺失抛 BootError.audioConfigMissing 弹 modal 永停(与 showmessage 同等致命)
- 上线前置:测试 / 生产远端 .txt 配置必须先补 audio_domain / audio_bucket 两个顶层 key
- WeChatSDK.appID / WeChatAuth.appSecret / QiniuConfig.* 调用方零签名变化

【新增】
- ylgamehall/Resources/AppSecrets.plist(3 key)
- ylgamehall/Source/Resource/AppSecrets.swift(单例加载,对齐 BundleConfig 模式)
- QiniuConfig 改 actor:cdnDomain/bucketName 进 actor 状态 + update(...) async;
  accessKey/secretKey 仍 nonisolated(直接读 AppSecrets)
- QiniuTokenSigner.uploadToken() 改 async(bucketName 来自 actor)
- QiniuUploader 预取 cdnDomain 闭包外,SDK 同步 callback 内直接拼 URL

【删除】
- WeChatSDK.swift  static let appID  硬编码 → Info.plist 启动期解析
- WeChatAuth.swift static let appSecret 硬编码 → AppSecrets.shared.wxAppSecret
- QiniuConfig 中 accessKey / secretKey / bucketName / cdnDomain 四处硬编码
- ChannelConfig.plist 的 qiniudomain 字段(plist 与代码双源僵尸字段)

【文档同步】
- Plan:新增 ADR-009 + ADR-007 守护规则改 10 key + §236 BundleConfig 描述
- Design §3.4 多处 "11 项" → "10 项";§7.0.3 plist 示例 + BundleConfig 代码骨架
  + Scripts/inject_channel.sh 同步
- SDK-Integration-Guide §0 凭证位置改三分制 + §尾"七牛域名读取"加新外壳路径
- Verification-Checklist L69 "(11 项)" → "(10 项)"

参考契约章节:docs/Development-Plan.md ADR-009、docs/H5-Native-Implementation-Design.md §7.0.3
BuildProject 通过,Xcode 即时诊断 0 警告。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
joywayer
2026-06-27 21:07:55 +08:00
co-authored by Claude Opus 4.7
parent 8125dd4d11
commit 83d9502dee
15 changed files with 260 additions and 67 deletions
+12 -7
View File
@@ -199,15 +199,20 @@ bridge.register("prepareaudio") { _, callback in
|---|---|---|
| **Bundle ID** | `com.skyapp.ylgamehall` | `daoqi/msext.xcodeproj` Release |
| **App 显示名** | `进贤聚友棋牌` | `SGDefineInfo.h:103 gamehallname` |
| 微信 AppID | `wx586a9b321e56efb7` | `SGDefineInfo.h:105 kAuthOpenID` |
| 微信 AppSecret | `b2792724b9565be23e8f5ba548f117cf` | `SGDefineInfo.h:107 Appsecret` |
| 微信 AppID | `wx586a9b321e56efb7` | **新外壳**:`Info.plist` CFBundleURLTypes (URLName=weixin) 唯一权威源 / msext:`SGDefineInfo.h:105 kAuthOpenID` |
| 微信 AppSecret | `b2792724b9565be23e8f5ba548f117cf` | **新外壳**:`AppSecrets.plist` 的 `wxAppSecret` / msext:`SGDefineInfo.h:107 Appsecret` |
| 微信 AuthScope | `snsapi_message,snsapi_userinfo,snsapi_friend,snsapi_contact` | `SGDefineInfo.h:104` |
| 微信 AuthState | `wechat_sdk` | `SGDefineInfo.h:106 kAuthState` |
| 高德定位 APIKey | `b0d4a8e3fcbbcc0dd96283b7df6a4494` | `daoqi/msext/Class/Common/APIKey.h:14` |
| 七牛 AccessKey | `dQbQLUm1jIuL9PEq4jd6VKB-6pPxPEdg7le9KeBm` | `QiniuConfig.m:12` |
| 七牛 SecretKey | `RCZpwLhAPoQ2sQQyWXzMJc7Po2MyZWfUJeW4Jmfq` | `QiniuConfig.m:13` |
| 七牛 BucketName | `iosaudio` | `QiniuConfig.m:16` |
| 七牛 CDN Domain | `iosaudio.daoqi88.cn` | `daoqi/msext/msext/qiniudomain/` 目录名 |
| 七牛 AccessKey | `dQbQLUm1jIuL9PEq4jd6VKB-6pPxPEdg7le9KeBm` | **新外壳**:`AppSecrets.plist` 的 `qiniuAccessKey` / msext:`QiniuConfig.m:12` |
| 七牛 SecretKey | `RCZpwLhAPoQ2sQQyWXzMJc7Po2MyZWfUJeW4Jmfq` | **新外壳**:`AppSecrets.plist` 的 `qiniuSecretKey` / msext:`QiniuConfig.m:13` |
| 七牛 BucketName | `iosaudio` | **新外壳**:RemoteConfig 顶层 `audio_bucket` 远端注入 / msext:`QiniuConfig.m:16` |
| 七牛 CDN Domain | `iosaudio.daoqi88.cn` | **新外壳**:RemoteConfig 顶层 `audio_domain` 远端注入 / msext:`qiniudomain/` 目录名 |
> **凭证位置三分制(新外壳 ADR-009)**:
> - **微信 AppID** 唯一源 = `Info.plist` 的 `CFBundleURLTypes`iOS 系统级 URL Scheme,运行期不可注入)
> - **应用级凭证**(微信 AppSecret、七牛 AccessKey、七牛 SecretKey)唯一源 = `Resources/AppSecrets.plist`
> - **七牛运行参数**CDN 域名、bucket 名)唯一源 = RemoteConfig 顶层 `audio_domain` / `audio_bucket`(启动期由 `WebContainerViewController` 注入 `QiniuConfig` actor;缺失即抛 `BootError.audioConfigMissing` 启动期致命)
### 0.1 安全权衡(与父项目 CLAUDE.md 同步)
@@ -350,4 +355,4 @@ bridge.register("prepareaudio") { _, callback in
- 高德 9 字段:`daoqi/msext/Class/RootVC/gameController.m:2528 / 2557``getlocationinfo` 字段顺序与类型)
- AMR 转码:`daoqi/msext/Class/Common/VoiceConvert/``VoiceConverter.h/m`、`amrFileCodec.h/m`
- 七牛 token 自签算法:`daoqi/msext/Class/Utils/QiniuManager.m:200-230`putPolicy + HMAC-SHA1 + Base64URL
- 七牛域名读取:`daoqi/msext/AppDelegate.m:142` 用 `FuncPublic filename:@"qiniudomain"` 读 `Resources/qiniudomain/` 下第一个子目录名作为实际 Domain
- 七牛域名读取msext 历史路径)`daoqi/msext/AppDelegate.m:142` 用 `FuncPublic filename:@"qiniudomain"` 读 `Resources/qiniudomain/` 下第一个子目录名作为实际 Domain。**新外壳不再沿用此路径**,CDN 域名 + bucket 名走 RemoteConfig 顶层 `audio_domain` / `audio_bucket` 远端注入到 `QiniuConfig` actorADR-009