Plan 进度同步:Phase 3.6 / 4.1 / 4.3-4.10 / 5.1-5.6 勾选

按 CLAUDE.md「进度同步规范」要求,把已落地的子项在 Development-Plan.md
§5 / §8 中同步勾选。同时修正几处描述与当前实现的差异:

- 4.1 微信 SDK:xcframework 2.0.5 入库 Vendor(不是 Embed Frameworks),
  Universal Links 不接(企业签分发不需要)
- 4.3 WeChatSDK:新 SDK 2.x 无 MMAPP_SUPPORT_* flag,简单 registerApp
- 4.6 WeChatAuth:客户端直拼 sns/oauth2/access_token + sns/userinfo,
  接受 msext 同款 secret 路径(不走后台 /wechat/login)
- 5.1 AMap:高德官方不出 xcframework,回退 fat .framework,M Mac 模拟器
  链接失败是接受的现状(详见 Vendor/AMap/README.md「已知限制」)
- 5.3 AMapWrapper:updatePrivacyShow/Agree 是 AMapLocationManager 类方法
- 5.4 LocationService:仅 requestOnce + stop,未实现持续模式(msext 也
  只是单次,H5 未要求持续)
- 3.6 Qiniu:CryptoKit HMAC-SHA1 自签 token + QNUploadManager 走
  initWithConfiguration + defaultConfigurationV2

Phase 4.11 / 4.12(截图 / 远端图分享)下个 commit 实现。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
joywayer
2026-06-23 01:33:05 +08:00
co-authored by Claude Opus 4.7
parent f137618070
commit d9d9554d9f
+56 -55
View File
@@ -433,9 +433,11 @@ Contract Design Plan(本文档)
- [ ] **3.5** `Source/Audio/AudioRecorder.swift`actor
- `record() async throws -> AudioFile``AVAudioRecorder` 录 WAV
- 麦克风权限:Info.plist 加 `NSMicrophoneUsageDescription = "{gamehallname}需要访问您的麦克风录制语音消息"`
- [ ] **3.6** 七牛 SPM 依赖(v8++ `Source/Network/QiniuUploader.swift`
- `upload(_:token:) async throws -> UploadedFile`
- 单测:mock token,模拟上传成功 / 失败
- [x] **3.6** 七牛 SPM 依赖(`https://github.com/qiniu/objc-sdk` v8.9.2,传递依赖 happy-dns 1.0.4 自动解析)+ 客户端自签 token 路径
- `Source/Network/QiniuConfig.swift`4 项常量(AccessKey / SecretKey / BucketName / cdnDomain+ publicURL,沿用 msext,整体 nonisolated
- `Source/Network/QiniuTokenSigner.swift`CryptoKit HMAC-SHA1 + Base64URL 自签,等价 msext QiniuManager.m:200-230
- `Source/Network/QiniuUploader.swift`actor`upload(_:timeSec:) async throws -> UploadedFile``QNUploadManager(configuration: defaultConfigurationV2)` 路径
- 真机上传单测待 Phase 3.C 完成(依赖 AudioRecorder 录音输入)
- [ ] **3.7** `prepareaudio` handler:拉起录音 → 停止录音 → AMR 转码 → 上传 → 反向 callback `getaudiourl` + `recordSuccess`(仅子游戏触发)
##### 3.D 远程语音回放
@@ -476,9 +478,9 @@ Contract Design Plan(本文档)
##### 4.A SDK 接入
- [ ] **4.1** `Vendor/WechatSDK/` 拷贝微信 SDK
- Info.plist URL Scheme`wx586a9b321e56efb7`+ `LSApplicationQueriesSchemes``weixin` / `weixinULAPI` / `weixinURLParamsAPI`
- Entitlement 加 Associated DomainsUniversal Links
- [x] **4.1** `Vendor/WechatSDK/` 入库微信 SDK`WechatOpenSDK-NoPay.xcframework` 2.0.5,入 git
- Info.plist URL Scheme `wx586a9b321e56efb7` + LSApplicationQueriesSchemes `weixin` / `weixinULAPI` / `weixinURLParamsAPI` 三项已就位
- Universal Links / Associated Domains 暂不接入:企业签分发,不上 App Store,无审核合规需求;`WXApi.registerApp(_, universalLink: "")` 空串即可
- [x] **4.2** **SharePanel 三选一面板 + SharePlatform 框架**4.B 完成)
- `Source/Share/SharePlatform.swift`SharePlatform 协议(name / isInstalled / share async+ ShareContent structnonisolated Sendable+ ShareResult enumsuccess / cancelled / notInstalled / failed+ ShareScene enumfriend / timeline
- `Source/Share/SharePanel.swift`:底部弹出三按钮(微信 / QQ / 抖音)+ 半透明背景点击关闭 + 0.25s 滑入/滑出动画;与 msext SharePanel.m 等价行为
@@ -504,29 +506,27 @@ Contract Design Plan(本文档)
5. 调起即视为 success
- Info.plist 加 `NSPhotoLibraryAddUsageDescription` 文案
- BuildProject 通过
- [ ] **4.3** `Source/SDK/WeChat/WeChatSDK.swift` 启动注册(Design §4.2 `registerFull` + 全部 12 个 `MMAPP_SUPPORT_*` flag
- [ ] **4.4** `Source/SDK/WeChat/WeChatManager.swift`@MainActor
- 持久 delegate
- `authorize() async throws -> WXAuthCode`state UUID 配对)
- `share(_:scene:) async throws`FIFO 串行)
- 详见 Design §8.5
- [ ] **4.5** `SceneDelegate.openURLContexts` 接入 QQ → WXApi 顺序
- [x] **4.3** `Source/SDK/WeChat/WeChatSDK.swift` 启动注册(`WXApi.registerApp("wx586a9b321e56efb7", universalLink: "")`;新 SDK 2.x 无 `MMAPP_SUPPORT_*` flag 概念,简单注册即可
- [x] **4.4** `Source/SDK/WeChat/WeChatManager.swift`@MainActor
- 持久 delegateWXApiDelegateonResp nonisolated 跳 MainActor
- `authorize() async throws -> WXAuthCodePayload`state UUID 配对)
- `shareLink(_:scene:) async throws`FIFO 串行type=2/3 截图/远端图待 4.11 / 4.12 Phase 4.F
- [x] **4.5** `SceneDelegate.openURLContexts``WXApi.handleOpen`QQ 走 URL Scheme 不依赖 SDK,无 SDK 顺序问题)
##### 4.B 授权登录
- [ ] **4.6** `Source/Login/WeChatAuth.swift`actor
- `authorize() async throws -> WeChatUser`:内部调 `WeChatManager.authorize()` 拿 code → 转给后台 `/wechat/login`(或客户端 fallback)→ 拿到 7 字段 user
- 后台未就绪时的 fallback:客户端直拼 `api.weixin.qq.com/sns/oauth2/access_token` —— 文件头标 `// FIXME: 待后台 /wechat/login 就绪后切换为后台中转`
- [ ] **4.7** `accreditlogin` handler:触发 OAuth → 反向 callback `sharelogin`7 字段,注意 `Province` 大写 P
- **关键契约测试**`sharelogin` payload 字段名严格 1:1
- [x] **4.6** `Source/Login/WeChatAuth.swift`客户端直拼 sns/oauth2/access_token + sns/userinfo
- 接受 msext 同款客户端持 secret 路径(父项目 CLAUDE.md 已识别但接受;后台 `/wechat/login` 中转)
- 7 字段 user 包含 `openid` / `headimgurl` / `nickname` / `sex` / `city` / `Province`(大写 P/ `unionid`
- [x] **4.7** `accreditlogin` handler:触发 OAuth → 反向 callback `sharelogin`7 字段,Province 大写 P
##### 4.C 分享
- [ ] **4.8** `Source/Share/SharePlatform.swift` 协议 + `WeChatShare` / `NoopSharePlatform(name:"xianliao")`
- [ ] **4.9** `Source/Share/ShareCenter.swift`策略分发(type=1/2/3 × sharetype=1/2/3,共 9 种组合
- [ ] **4.10** `friendsSharetypeUrlToptitleDescript` handler:参数解析 → ShareCenter.dispatch → 反向 callback `sharesuccess({success:"2", type:<原 sharefriend>})`
- [ ] **4.11** 截图分享`getImageWithFullScreenshot` Swift 等价实现(`UIGraphicsImageRenderer`
- [ ] **4.12** 远程图片分享URLSession 下载 → 重打包
- [x] **4.8** `Source/Share/SharePlatform.swift` 协议 + `WechatShare` / `QQShare` / `DouyinShare`(闲聊不接,参 ADR-006
- [x] **4.9** `Source/Share/ShareCenter.swift`sharefriend=1 弹 SharePanel=2 直接微信朋友圈(msext gameController.m:585 等价
- [x] **4.10** `FriendsShareHandler.swift` → ShareCenter.dispatch → 反向 callback `sharesuccess({success:"2", type:<原 sharefriend>})`
- [ ] **4.11** 截图分享type=2):`captureScreenshot` → WXImageObject + thumbImage 0.4xmsext gameController.m:637-658 等价)— Phase 4.F
- [ ] **4.12** 远程图片分享type=其它):`downloadRemote` → WXImageObject + thumbImage 0.4x — Phase 4.F
#### 验收
@@ -554,16 +554,17 @@ Contract Design Plan(本文档)
#### 任务清单
- [ ] **5.1** 从 [高德官方下载页](https://lbs.amap.com/api/ios-location-sdk/download) 拉取最新 `AMapLocationKit.xcframework` + `AMapFoundationKit.xcframework`,放 `Vendor/AMap/`Target → General → Embed Frameworks 加入;按 Design §14.1 Vendor 接入标准流程操作;`Vendor/AMap/README.md` 记录版本号 / 下载日期
- [ ] **5.2** Info.plist `NSLocationWhenInUseUsageDescription = "{gamehallname}需要访问您的位置以提供本地化服务"`
- [ ] **5.3** `Source/SDK/AMap/AMapWrapper.swift`启动期 `updatePrivacyShow` + `updatePrivacyAgree` + `apiKey` 设置
- [ ] **5.4** `Source/Location/LocationService.swift`actor
- `requestOnce() async throws -> LocationPayload`
- `startContinuous(onUpdate:)` / `stop()`
- [ ] **5.5** `startlocation` handler`data=1` 持续 / 其他一次性 → 反向 callback `getlocationinfo` 9 字段
- **关键契约**`latitude` / `longitude`**string**`stringWithFormat:%f` 等价产物)
- **关键契约**`province` 是小写 p(与 `sharelogin.Province` 大写不同
- [ ] **5.6** 失败路径:`getlocationinfo({errorCode:12, errorMsg:"缺少定位权限"})`
- [x] **5.1** 高德官方至今**不提供 xcframework**,回退为 fat `.framework` `Vendor/AMap/`AMapFoundationKit 1.9.0 + AMapLocationKit 2.12.0);Target Do Not Embed(静态库);M Mac 模拟器链接失败是接受的现状,开发期跑真机,详见 `Vendor/AMap/README.md` 「已知限制」
- [x] **5.2** Info.plist `NSLocationWhenInUseUsageDescription = "进贤聚友棋牌需要访问您的位置以提供本地化服务"`
- [x] **5.3** `Source/SDK/AMap/AMapWrapper.swift``AMapLocationManager.updatePrivacyShow` + `updatePrivacyAgree` + `AMapServices.shared().apiKey`(注意:隐私 API 在 AMapLocationManager 类方法上,不在 AMapServices
- [x] **5.4** `Source/Location/LocationService.swift`actor
- `requestOnce() async throws -> LocationPayload`
- `stop()` 清理钩子 ✅
- 持续模式 `startContinuous(onUpdate:)` 未实现(msext 实际只有 H5 一次性 startlocation;如未来 H5 用 data=1 持续,再补)
- [x] **5.5** `startlocation` handler:单次定位 → 反向 callback `getlocationinfo` 9 字段
- latitude/longitude 是 string`String(format: "%f", ...)`
- province 是小写 p(与 sharelogin.Province 大写不同)
- [x] **5.6** 失败路径:`getlocationinfo({errorCode:12, errorMsg:"缺少定位权限"})`
#### 验收
@@ -911,36 +912,36 @@ H5 调 `OpenurlTitleData` 打开弹层 WebView,弹层内 H5 用 `window.settin
- [ ] 2.13 ExternalSubscriptions
### Phase 3 音频体系
- [ ] 3.1 AudioPlayer
- [x] 3.1 AudioPlayerSource/Audio/AudioPlayer.swiftsrcIsloop / stopBackground / volume 全路径)
- [ ] 3.2 本地音频真机验证
- [ ] 3.3 opencore-amr Vendor 接入
- [ ] 3.3 opencore-amr Vendor 接入(详见 docs/SDK-Integration-Guide.md §C,需手动)
- [ ] 3.4 VoiceCoder Swift wrapper
- [ ] 3.5 AudioRecorder + 麦克风权限
- [ ] 3.6 七牛 SPM + QiniuUploader
- [ ] 3.5 AudioRecorder + 麦克风权限NSMicrophoneUsageDescription 已就位)
- [x] 3.6 七牛 SPMobjc-sdk 8.9.2+ QiniuConfig + QiniuTokenSignerCryptoKit HMAC-SHA1 自签)+ QiniuUploader actorinitWithConfiguration + defaultConfigurationV2
- [ ] 3.7 prepareaudio handler
- [ ] 3.8 mediaTypeAudio handler
### Phase 4 分享 + 登录
- [ ] 4.1 微信 SDK Vendor + URL Scheme
-~~4.2 QQ SDK Vendor~~ **不需要**QQ 走 URL Scheme,详见 Phase 4.2 任务清单
- [ ] 4.3 WeChatSDK registerFull
- [ ] 4.4 WeChatManagerstate map + FIFO
- [ ] 4.5 SceneDelegate openURL 顺序
- [ ] 4.6 WeChatAuth后台中转或 fallback
- [ ] 4.7 accreditlogin → sharelogin
- [ ] 4.8 SharePlatform 协议
- [ ] 4.9 ShareCenter 9 种组合
- [ ] 4.10 friendsShare... handler
- [ ] 4.11 截图分享
- [ ] 4.12 远程图片分享
- [x] 4.1 微信 SDK Vendor + URL SchemeWechatOpenSDK-NoPay.xcframework 2.0.5 入库 Vendor/WechatSDK/Info.plist CFBundleURLTypes + LSApplicationQueriesSchemes 3 项)
-~~4.2 QQ SDK Vendor~~ **不需要**QQ 走 URL Scheme,详见 §5 Phase 4.A 任务清单
- [x] 4.3 WeChatSDK registerSource/SDK/WeChat/WeChatSDK.swift;新 SDK 2.x 无 MMAPP flag 概念,registerApp + universalLink 即可)
- [x] 4.4 WeChatManagerstate map + FIFOSource/SDK/WeChat/WeChatManager.swift
- [x] 4.5 SceneDelegate openURLQQ 走 URL Scheme 不依赖 SDK,仅微信 WXApi.handleOpen
- [x] 4.6 WeChatAuth客户端直拼 sns/oauth2/access_token + sns/userinfo,沿用 msext 安全模型
- [x] 4.7 accreditlogin → sharelogin7 字段,Province 大写 P
- [x] 4.8 SharePlatform 协议Phase 4.B 完成)+ WechatSharetype=1 链接 donetype=2/3 见 4.11/4.12
- [x] 4.9 ShareCentersharefriend=1 弹 SharePanel=2 直接微信朋友圈;Phase 4.B 完成)
- [x] 4.10 friendsShare... handlerFriendsShareHandler.swiftsharesuccess 反向 callback
- [ ] 4.11 截图分享Phase 4.Ftype=2
- [ ] 4.12 远程图片分享Phase 4.Ftype=3
### Phase 5 定位
- [ ] 5.1 AMap Vendor 接入(XCFramework
- [ ] 5.2 定位权限文案
- [ ] 5.3 AMapWrapper 启动注册
- [ ] 5.4 LocationService
- [ ] 5.5 startlocation handlerlatitude/longitude stringprovince 小写)
- [ ] 5.6 失败回包 errorCode 12
- [x] 5.1 AMap Vendor 接入(高德官方不提供 XCFramework,回退为 fat `.framework`;M Mac 模拟器链接失败是接受的现状,详见 Vendor/AMap/README.md
- [x] 5.2 定位权限文案NSLocationWhenInUseUsageDescription
- [x] 5.3 AMapWrapper 启动注册updatePrivacyShow / updatePrivacyAgree 是 AMapLocationManager 类方法,apiKey 在 AMapServices.shared
- [x] 5.4 LocationService actorrequestOnce 异步 + stop 清理钩子)
- [x] 5.5 startlocation handlerlatitude/longitude stringprovince 小写 p
- [x] 5.6 失败回包 errorCode 12(缺少定位权限)
### Phase 6 子游戏
- [x] 6.1 AppCoordinator 栈深节流(2s + viewControllers.count < 2