Commit Graph
22 Commits
Author SHA1 Message Date
joywayerandClaude Opus 4.7 d48ecc0473 Design §8.6:新增 LocationKit + 2 项接口实现骨架
覆盖 §3.1 [20]startlocation + §3.2 [6]getlocationinfo 反向 callback。

§8.6.1 LocationService module 骨架:
  - AMapServices.bootstrap:privacy + key 启动期完成
  - locateOnce() async/await 包装 AMapLocationManager.requestLocation
  - startContinuous / stopContinuous + onContinuousUpdate 闭包钩子
  - LocationInfo struct 转契约 §3.2 表 B 9 字段(latitude/longitude string
    化用 String(format: "%f"),province 小写 p)
  - LocationError.permissionDenied(code: 12)

§8.6.2 H5 handler(LocationHandlers.startLocation):
  - 入参 data: int 1=持续 / 其他=一次性,与 msext RootVC 沿用
  - 持续模式:onContinuousUpdate 挂钩 → 每次位置变化推 getlocationinfo
  - 一次性:await locateOnce → 单次推
  - responseCallback: "startlocation"
  - 失败 callback 数据结构 errorCode 数字 12 不是 string(契约硬约束)

§8.6.3 与 msext 6 维度差异表(SDK 接入 / 隐私合规集中 / async wrapper /
入参解析 / latitude string / province 小写 p)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 07:30:06 +08:00
joywayerandClaude Opus 4.7 c6221d30ca Design §8.4.1:补 DeviceKit 9 项接口实现骨架
覆盖 §3.1 异步 handler 6 项 + §3.2 反向 callback 3 项,含本轮全文 audit
新发现的 3 项反向 callback(前一轮 audit 漏列):

§3.1 异步 handler 6 项(DeviceHandlers.register):
  - 【10】vibrator           — AudioServicesPlaySystemSound + cb "vibrator"
  - 【11】repeatvibrator     — 同 vibrator(msext RootVC.m:1820 沿用历史)
  - 【12】canclevibrator     — AudioServicesDisposeSystemSoundID + cb "canclevibrator"
  - 【13】gamepastetext      — UIPasteboard.general.string → cb 返回内容
  - 【14】gameCopytext       — UIPasteboard.general.string = data + cb "gameCopytext"
  - 【21】getphoneInfo       — cb "getphoneInfo"(大写 I)+ bridge.call("getphoneinfo"
                              小写 i!,data: 表 A 6 字段)
                              ※ 大小写 i 不一致是 msext 历史契约,严格保持

§3.2 反向 callback 3 项(DeviceHandlers.bindReverseCallbacks):
  - 【2】 getBattery   — UIDevice.batteryLevelDidChangeNotification
                        data: String(format: "%.2f", level) 0~1
  - 【3】 getnetwork   — NWPath 变化 data: "1"无网/"2"WiFi/"3"蜂窝
  - 【4】 appservice   — App 前后台 data: "1"=后台/"2"=前台(命名错位沿用)

辨析 polyfill 与 callback 同名问题:契约 §3.4.1 polyfill 的同步 getter
`getbattery()` / `getnetwork()` 与 §3.2 反向 `getBattery` / `getnetwork`
名字重合但语义不同(前者 H5 同步问当前值,后者 Native 事件推变化),
两条路径并存互不矛盾。在 §8.4.1 新增辨析段澄清。

支撑组件骨架:BatteryMonitor / AppLifecycleMonitor(NetworkMonitor 已在
§8.4 现有);§8.4.2 与 msext 6 维度差异表。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 07:28:34 +08:00
joywayerandClaude Opus 4.7 82bad8a85d Design §3.4.1:补 window.settings 同步 getter polyfill(9 项含 getothername)
audit 第二轮发现:Contract §附录 A 旧桥 JSExport 共 28 方法,与 §3.1
异步主桥去重后多出 9 项 H5 同步只读 getter。前一轮 audit 只覆盖 §3.1
主表的 22 项异步 handler,这 9 项 getter 在 Design 完全无覆盖:

  - getchannelName / getmarketname / getOther / getothername(name)
  - getcompareCode / getbattery / getnetwork
  - getGameinstall(name) / getGameplay(jsondata)

这些接口 H5 端形式是同步表达式(var ch = window.settings.getchannelName()),
WKWebView 无法同步返回 JS 值。唯一不破契约(H5 端零修改)的路径:
documentStart 注入数据快照 + 纯 JS getter polyfill,本地查询零延迟。

§3.4.1 新增覆盖:
  - 9 项 getter 业务语义 + 数据源映射表(驳到 BundleConfig / DeviceKit /
    SandboxPaths.installedSubGames)
  - 数据快照时机:静态字段(11 项渠道注入)启动期一次;动态字段
    (battery / network / installedGames)每次 loadFileURL 前重新快照
  - SettingsBridgePolyfill.makeUserScript 完整 JS 注入骨架
  - WebContainerViewController 接入点(runBootPipelineSteps 末尾、
    loadFileURL 前调 installSettingsPolyfill)
  - 与原 msext JSExport 5 维度差异表

待 Phase 2 实施时查清:getcompareCode 在 msext RootVC.m:1560 附近的真实
返回值语义(业务校验码,可能与 zip 版本号或固定值相关)。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 07:24:01 +08:00
joywayerandClaude Opus 4.7 92298b657e Design §8.1:补 AudioKit 4 项 handler 完整实现骨架(方案 A 示范)
H5↔Native 接口实现层缺口补全启动(用户选 A:分散到各 module 章节补)。
本 commit 作为风格示范,后续 commit 按相同模板补 DeviceKit / Location /
Shake / OpenurlTitleData 共 11 项 handler。

§8.1 末尾新增两小节:

§8.1.1 — H5 audio handlers 实现骨架(185 行)
  - AudioHandlers struct 集中注册 4 项 handler,便于发现 / 单测
  - 【3】srcIsloop  入参解析 src/isloop → SandboxPaths.lobbyAssets/wav
        + AudioPlayer.playOnce / loopBackground / stopBackground 三态
        + responseCallback "Response from srcIsloop"
  - 【4】prepareaudio  权限三态分支(denied → bridge.call alertMessage
        而非原生弹窗,契约 §6.2 ifauth 语义)+ recordAndUpload
        + getaudiourl 反向 callback(time 字段必须 string,契约硬约束)
  - 【5】mediaTypeAudio  voiceCenter 总开关短路 + 下载 → AMR→WAV
        → playVoice with onStart/onEnd 桥到 gameui_play_voice/
        gameui_stop_voice;失败也补 stop_voice 避免 H5 UI 卡"播放中"
  - 【6】voicePlaying  actor VoiceCenter 隔离 isEnabled 状态

§8.1.2 — 与原 msext 的差异(不要照抄的部分)
  - 录音 UI / 上传后端 / 状态共享 / 总开关 / 路径拼接 5 维度对照表

骨架级别(结构 + 关键调用 + 注释 + 契约引用),不是产品代码 — 实施
Phase 2 时按此骨架落地真实代码。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 07:14:15 +08:00
joywayerandClaude Opus 4.7 c95e80df9c Phase 1.16:SceneDelegate 接 WebContainer + 退役 RootViewController
- SceneDelegate.scene(_:willConnectTo:options:) 中 rootViewController
  从 M0 占位 RootViewController() 改为 WebContainerViewController()
- 删除 ylgamehall/RootViewController.swift(M0 + Phase 1.2–1.13 烟雾测试
  整体退役);所有 print 验证记录在 git log,留着是死代码
- File System Synchronized Group 自动适应文件删除,无需改 pbxproj
- BuildProject 通过

至此 Phase 1.16 完成;启动链路:
  SceneDelegate → WebContainerViewController.viewDidLoad
    → setupBridgedWebView + setupSplash + registerBridgeHandlers
    → runBootPipeline (ensureReady → fetch → resolve → upgrade → loadFileURL)
    → didFinish 淡出 splash

Plan 进度已勾选(§5 Phase 1.16 + §8)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 04:23:52 +08:00
joywayerandClaude Opus 4.7 6c943e2924 Phase 1.15:VibratorHandler 单次振动 handler
新增 ylgamehall/Source/Bridge/Handlers/VibratorHandler.swift:
- 无状态 public enum VibratorHandler,static func register(on:)
- 入参忽略(参考原 msext RootVC.m:1816-1818:time 参数实际不读取)
- 副作用:AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
- responseCallback:.string("vibrator"),与契约 §3.1 [10]一致
- 模拟器无振动硬件、调用静默忽略;真机才能感知

WebContainerViewController.viewDidLoad 新增 registerBridgeHandlers()
单一聚合点,Phase 2+ 在此追加更多 handler,便于发现 / 调试。

repeatvibrator / canclevibrator 严格守住 Plan §5 Phase 2.2 范围,不
提前实现。

BuildProject 通过

Plan 进度已勾选(§5 Phase 1.15 + §8)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 04:02:33 +08:00
joywayerandClaude Opus 4.7 0ecfa4fb69 修复 SplashImage 方向:素材逆时针旋转 90° 改为真正横屏
源素材 docs/res/Res/Default-568h@2x~iphone.png 是 CgBI PNG,物理 640×1136
但画面内容是"横躺"在竖向容器里 —— msext 旧 LaunchImage 系统依赖 device
orientation 自动旋转,现代 LaunchScreen.storyboard 没有这个魔法,直接显示
会看到躺倒的画面(用户反馈:启动图的横竖方向错误)。

处理:
- 用 sips -r -90 -s format png 一次性把素材逆时针旋转 90° 输出为标准
  PNG(顺便去掉 CgBI 优化标志),物理像素 1136×640,覆盖到
  ylgamehall/Assets.xcassets/SplashImage.imageset/SplashImage@2x.png
- LaunchScreen.storyboard 中 <image> 的 width/height 从 640/1136 改为
  1136/640;UIImageView 的 contentMode 从 scaleAspectFill 改为
  scaleAspectFit。aspectFit 在比 16:9 更宽的现代横屏 iPhone(如 16 Pro
  ≈2.17:1)上左右补黑边(黑底无视觉违和),保画面完整不裁切 logo
- WebContainer 的 SplashOverlay 用同款 scaleAspectFit,避免启动 → 容器
  视觉过渡时出现裁切方式跳变
- BuildProject 通过

Plan 进度已勾选(§5 Phase 1.14.b + §8 同步修订)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 03:10:53 +08:00
joywayerandClaude Opus 4.7 f795957eb1 Phase 1.14.e:webView didFinish 后 0.3s 淡出 splash
把 WKNavigationDelegate.didFinish 里的 splash.isHidden = true 换成
UIView.animate(withDuration: 0.3) 渐变 alpha=0 + completion 内
removeFromSuperview,避免渲染瞬间硬切,也让 view 层级在大厅起来后
完全干净(无空持有的 splash 占位)。

BuildProject 通过

Plan 进度已勾选(§5 Phase 1.14.e + §8)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 02:51:25 +08:00
joywayerandClaude Opus 4.7 f247b81d6d Phase 1.14.d:WebContainerViewController(16:9 letterbox + Splash + 启动流水线)
新增 ylgamehall/Source/WebView/WebContainerViewController.swift:

- 持有 BridgedWebView(间接持 BridgeBus)+ 文件内私有 SplashOverlay
- 16:9 letterbox 布局:required(aspect 16:9 + width/height ≤ superview)
  + low(width/height = superview) + center{X,Y} 居中。屏幕比 < 16:9 → 上下
  黑边,> 16:9 → 左右黑边。Auto Layout 自动选短边贴边、长边居中
- SplashOverlay:SplashImage(scaleAspectFill) + UIProgressView + UILabel;
  update(text:progress:) 切换状态机
- runBootPipeline 串:ensureReady → "拉取配置中..." → RemoteConfigClient.fetch
  → 分支(.shortText / .parsed → showmessage / IPA 升级 / LobbyZipUpgrader
  with onProgress hop 到 MainActor) → "加载大厅..." → loadFileURL(lobbyIndex,
  allowingReadAccessTo: lobbyRoot)
- 三种 alert:showBlockingAlert(短文本/showmessage,永停)/
  showIPAUpgradeAlert(确定→openURL,永停)/ showFatalAlert(重试→重跑 pipeline)
- WKNavigationDelegate.didFinish 暂用 splash.isHidden = true(1.14.e 改为
  0.3s 淡出动画)
- 横屏锁定 + statusBar 显示(与 RootViewController 一致)

不接 SceneDelegate,1.16 才换 rootViewController;本次仅落地容器代码。
BuildProject 通过

Plan 进度已勾选(§5 Phase 1.14.d + §8)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 02:50:16 +08:00
joywayerandClaude Opus 4.7 f3c66b670d Phase 1.14.c:LobbyZipUpgrader 加 0…1 progress 回调
- upgradeIfNeeded 新增 onProgress: @escaping @Sendable (Double) -> Void 参数,
  默认 no-op 兼容仅做版本对比的烟雾测试
- 新增文件内私有 DownloadProgressDelegate(URLSessionDownloadDelegate
  + @unchecked Sendable),在 didWriteData 回调里把 totalBytesWritten /
  totalBytesExpectedToWrite 换算成 0…1 上报,clamp 到 [0,1]
- 通过 session.download(from:delegate:) 注入;下载完成后兜底报 1.0
  (部分 server 不发 Content-Length 或末尾片段晚到,避免进度条停在 99%)
- RootViewController 烟雾测试用 ProgressTicker 把回调节流到 10% 阶梯打印,
  避免几百行刷屏(NSLock 保护单 Int 状态,@unchecked Sendable)
- BuildProject 通过

Plan 进度已勾选(§5 Phase 1.14.c + §8)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 02:46:11 +08:00
joywayerandClaude Opus 4.7 ba34854133 Phase 1.14.b:LaunchScreen 替换为启动图(SplashImage)
- 将 docs/res/Res/Default-568h@2x~iphone.png(msext 时代竖图 640×1136
  CgBI 压缩,29708 字节)拷入 ylgamehall/Assets.xcassets/SplashImage.imageset/,
  Contents.json 声明 universal idiom @1x/@2x/@3x(仅 @2x 提供物理文件)
- 改写 LaunchScreen.storyboard:黑底 + 单个 UIImageView(image="SplashImage",
  contentMode=scaleAspectFill),四边约束到 superview 完成全屏铺满
- 启动瞬间用户看到的是启动图而非黑屏;竖图在横屏设备上会被 aspectFill
  上下裁剪,启动只展示 0.x s,接受此折衷,Phase 10 polish 时再考虑做
  专门的横屏素材
- BuildProject 通过(55s)

Plan 进度已勾选(§5 Phase 1.14.b + §8)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 02:43:14 +08:00
joywayer 45a8f483bc Phase 1.14.a:替换 AppIcon 为 docs/res 内 msext 旧版图标
从 docs/res/Images.xcassets/AppIcon-1.appiconset 拷贝 9 个 png +
Contents.json 到 ylgamehall/Assets.xcassets/AppIcon.appiconset,替换
Xcode 默认空 universal 1024 模板。

- 9 个 png 覆盖 iPhone 29x29 / 40x40 / 57x57 / 60x60 三档分辨率 ×
  @1x/@2x/@3x 组合(msext 历史素材,分辨率名 "129x29" 等是文件名
  artifact,实际对应规格表里的 29x29)
- Contents.json 沿用旧版 iPhone-specific idiom,含 iOS marketing
  1024 占位(无文件名)
- BuildProject 通过,actool 3 个 warning 暂不处理(iPad 76/83.5
  缺失 → iOS 自动用 iPhone 缩放;1024 marketing 缺失 → App Store
  上架要求,企业签不强制);Phase 10 上线前 polish 时补齐
- 顺手发现 BridgedWebView.swift:88 用 WKProcessPool 在 iOS 15+ 被弃用,
  Phase 1.14.d 实施 WebContainer 时一并清理

Plan §5 1.14.a / §8 进度已勾选
2026-06-22 02:36:59 +08:00
joywayer 2280462a22 docs:Plan + Design 扩展 Phase 1.14 为 5 子项(含 AppIcon / LaunchScreen / progress / splash UI)
原 Phase 1.14 仅含"WebContainer 16:9 letterbox + 串接整链路",
漏掉了用户实际能看到的三件事:AppIcon / LaunchScreen 启动图 / zip
下载进度条。msext 上线时这三件都有,新外壳上线必须对齐。按用户偏好
方案 A 合并到 Phase 1.14,避免做两遍 WebContainer。

- Plan §5 Phase 1.14 拆为 1.14.a–e 五个子项
  - 1.14.a AppIcon:拷贝 docs/res/Images.xcassets/AppIcon-1.appiconset
    (9 个 png + Contents.json) 到 ylgamehall/Assets.xcassets
  - 1.14.b LaunchScreen:Default-568h@2x~iphone.png → SplashImage
    imageset;改写 LaunchScreen.storyboard 横屏铺满 UIImageView
  - 1.14.c LobbyZipUpgrader 加 onProgress 回调(@Sendable (Double) -> Void)
  - 1.14.d WebContainerViewController:splash 覆盖层(启动图 +
    UIProgressView + 状态文字)+ 16:9 letterbox + 启动流水线串接
  - 1.14.e webView didFinish 淡出 splash(0.3s 动画 + removeFromSuperview)
- Plan §8 进度追踪同步:5 个子项独立勾选条目
- Design §6.3.5 WebContainer 调用串完整重写:
  - Splash UI 6 状态切换表(拼命启动中... / 拉取配置中... /
    下载更新中 XX% / 加载大厅... / 淡出)
  - runBootPipeline 完整 swift 骨架:含 .shortText 短文本响应处理 /
    showmessage 阻塞处理 / IPA 升级 alert / zip 升级 onProgress 回调
  - 所有失败 / 阻塞终态都用 UIAlertController(非 splash 文字):
    短文本 / showmessage / IPA 升级 / 网络错误 / zip 下载失败
    各场景的按钮文案 + tap 行为表
2026-06-22 02:35:37 +08:00
joywayer 87304552c3 docs:勾选 Plan §5 / §8 Phase 1.10-1.13 进度 + CLAUDE.md 新增「进度同步规范」
把 Plan 任务清单和进度追踪 checklist 同步到当前实际进度(1.10-1.13
均已完成 + 实测验证),并在 CLAUDE.md 写入"每完成 Phase 子项必须立即
更新 Plan 进度"的硬约束。

- Plan §5 Phase 1.10-1.13 任务清单 [ ] → [x]
- Plan §8 进度追踪同步:标注算法名 / 端到端实测结果(260→261 验证)
- CLAUDE.md 新增「进度同步规范」节,规定:
  - Plan §5 + §8 每完成子项立即勾选,与 commit 同 commit 内完成
  - 任务描述与实现有差异时同步修订(不允许 Plan 与代码长期不一致)
  - commit message 末尾备注"Plan 进度已勾选"
  - 理由:Plan 是项目记忆的唯一权威进度视图,新人 clone 后看 Plan
    §8 即可知整体进度;与 commit log 双写互为校验

Plan 进度已勾选
2026-06-22 02:30:31 +08:00
joywayer 1bc287bafc Phase 1.10:RemoteConfigClient 完整版(HTTPS + cache-busting + 短文本 + FlexibleString)
第二轮调研 daoqi/NewRootVC.m 全文核对后,把对原项目远程配置流程的精确
理解固化进 ADR-008 + Design §6.3.2,并补齐 RemoteConfigClient 缺失的
3 个契约(cache-busting query、短文本响应识别、字段类型混乱兼容)。

核心修正:线上热路径是 chulishengji 双子树合并算法(NewRootVC.m:1372-1538),
不是 onnet 简单 4 层覆盖。viewWillAppear 与 gonet 都会强制把当前 agent 的
gamelist 提到 self.gamelist,只要服务器 JSON 含 agent.gamelist(线上 100% 都有),
self.gamelist 就非 nil,走 else 分支 → chulishengji。本次烟雾测试实测:
agent[0].gamelist = 7 个,完美印证 chulishengji 必要性。

- RemoteConfigClient 新增 cache-busting query:?vXXXXXXXXYYYYYYYY(两段 8 位 hex
  连写,无 =,照搬 msext NewRootVC.m:1226 契约),每次重试都重新生成
- 新增 RemoteConfigOutcome enum:.parsed(RemoteConfig) 与 .shortText(String)
  两种成功状态。短文本响应(trim 后 utf16.count ≤ 100)是服务端运营杀手锏 #1,
  msext 当 alert 文本弹窗 + 停止重试(NewRootVC.m:1239-1243)
- UTF-8 解码 + trim 跟 msext NewRootVC.m:1237-1238 严格对齐
- 所有 String? 字段改用 decodeFlexibleStringIfPresent 扩展(兼容 number-as-string):
  agentid / channelid / marketid / gameid / showmessage / appVersion / appDownload
  / gameVersion / gameZip 全部 9 字段。msext 用 NSNumber.intValue/description 静默
  吞下 number,新外壳 Codable 严格类型必须显式处理
- 远端 URL 从 http 改为 https(后台已切,无需 ATS 例外)
- Plan ADR-008 修订为含 9 个子节(A-I)的精确决策记录,含 chulishengji
  双子树算法、agent 子树结构、game 子树结构、字段级合并优先级、决策顺序、
  与 msext 差异表
- Design §6.3.2 VersionResolver 重写:从"简单 4 层 reduce"改为"chulishengji
  双子树合并 + 字段级合并",附 13 项单测覆盖矩阵
- RootViewController 烟雾测试切换为 outcome enum switch case,覆盖 .parsed
  与 .shortText 两条路径
- 实测烟雾:HTTPS 拉到 30 KB JSON 解析 .parsed 成功(耗时 2.7s 含 TLS 握手),
  agent[0].gamelist 含 7 个 game 节点,证明 chulishengji 路径是热路径
2026-06-22 02:14:57 +08:00
joywayer 5f032342e7 docs:Plan / Design 补 Phase 1 远程配置 + zip 升级流水线(ADR-008)
调研 daoqi/msext 原项目 NewRootVC.m:1551-1621 viewWillAppear、1372-1492
chulishengji、1789-1869 downFileFromServer 三段核心代码后发现 Plan 初版
Phase 1 漏掉了启动流程里最关键的一环——从 gameconfig 拼远端 .txt 拉
真实配置、做 agent → channel → market 4 级覆盖、对比本地版本、必要时
下载并替换 H5 zip。不做的代价是:上线后用户永远停留在 IPA 内打包瞬间
的 H5 旧版本,H5 团队任何更新都到达不了。

- Plan Phase 1 任务清单从 13 项扩为 17 项,插入 4 个新子项:
  - 1.10 RemoteConfigClient(actor,URLSession async + 指数退避)
  - 1.11 VersionResolver(纯函数 + 单测,reduce 实现 4 级覆盖)
  - 1.12 LocalVersionReader(解析 version.xml)
  - 1.13 LobbyZipUpgrader(actor,原子 rename)
  原 1.10-1.13 后移为 1.14-1.17。已完成的 1.1-1.9 标记为 
- Plan 新增 ADR-008 完整记录决策背景 / 触发事件 / 与 msext 实现差异
  对照表 / 守护条款 / 子游戏复用规划
- Design §6.3 整节重写:从原"ConfigService 一锅端"扩为完整 4 模块流水线
  (§6.3.1-6.3.7),含 Codable RemoteConfig 模型、纯函数 VersionResolver、
  nonisolated LocalVersionReader、actor LobbyZipUpgrader、WebContainer
  调用串、与 msext 差异表、子游戏 Phase 6 复用规划
- 关键设计纠正:
  - 远端 URL 不带 SERVERNew 前缀,仅 gameconfig.replace("-","/") + ".txt"
  - 4 级覆盖:顶层 → agent → channel → market 深层胜出 + game 子树覆盖
    agent 子树
  - 解压策略:staging-{uuid}/ 临时目录 + 原子 moveItem rename,不学
    msext "目录名 +1" 累积 hack
2026-06-22 00:42:30 +08:00
joywayer 8c2ffa3106 Phase 1.1:渠道注入用 ChannelConfig.plist 替代 msext 目录树(ADR-007)
契约 §0.3 描述 msext 把 11 个渠道值编码为 Bundle 根的 11 个空目录
子文件夹名(目录名本身就是值)。在 Xcode 26.5 默认的 synchronized
group 下,此机制不兼容(子目录被扁平化、11 个 .gitkeep 撞名;
folder reference 拖入流程失效;Run Script Phase 受 sandbox 阻碍且
默认 Based on dependency analysis 让 clean build 也不跑)。

CLAUDE.md 原则 B 落地——原生内部自由重构,不照搬 msext。改用单一
plist 存储等价语义,H5 端通过 app_data.js 看到的 11 个 JS 全局变量
行为完全不变(契约边界在 BundleConfig.shared.xxx,与底层无关)。
多渠道分发用 plutil -replace + 重签 + 重打包,工作量与 mv 目录名
重签完全相同。

- 新增 ylgamehall/Resources/ChannelConfig.plist:11 个 string key
  含母包默认值(沿用 msext 现网值);synchronized group 自动入 Bundle
- Design §7.0 / §7.2 重写为 plist 方案;BundleConfig 代码骨架改为
  PropertyListSerialization + init(bundle:) 可注入式
- Plan §5 Phase 1.1 任务清单从 4 个子项简化为 1 项;ADR-004 文字
  同步;新增 ADR-007 完整记录决策背景 / 触发事件 / 工程兼容性分析
  / 理由 / 守护条款
- pbxproj:ENABLE_USER_SCRIPT_SANDBOXING 残留为 NO(前期 Run Script
  方案探索时关闭,plist 方案下不再需要,但未恢复以避免再次 UI 操作;
  无 Run Script 故无实际安全暴露面,未来可随时改回 YES)
- BuildProject 验证:plist 已落在 .app 根,plutil -p 输出 11 个键值
  完整
2026-06-21 23:41:25 +08:00
joywayer cabdc1ed42 docs:剥离 docs/res/ 为私人素材池,废止仓库根 Resources/ 假设
明确 docs/res/ 是项目维护者的私人原始素材池,与项目架构无关;项目
代码 / 构建脚本 / Xcode 工程都不感知它的存在,需要时从中拷一份到
项目按现代实践规划的位置。原 ADR-004「Resources/ 在仓库根 +
Build Phase 引入」语义已崩塌(gamehall.zip / Images.xcassets / Res/
均被挪入 docs/res/),修订为「项目内资源目录由各 Phase 按需落地」:
静态 Bundle 资源走 ylgamehall/Resources/、原生 Asset Catalog 走
ylgamehall/Assets.xcassets/、渠道注入产物走 ylgamehall/ChannelInjection/
(.gitignore + Scripts/inject_channel.sh 生成)、闭源 SDK 走 Vendor/。

- CLAUDE.md 原「Resources/ 目录约定」节改写为「docs/res/ 与项目
  资源的关系」,禁止把 docs/res 当项目资源目录使用
- Design §7.0 整节重写为「项目资源目录约定」三小节(docs/res
  与项目无关 / 项目内资源目录在 Phase 实施时按需落地 / 渠道注入
  运行时路径)
- Plan ADR-004 修订为「项目资源目录由各 Phase 按需落地」;ADR-002
  / §2.2 / Phase 1.1.a-d / 1.5 同步调整为 docs/res → ylgamehall/Resources
  的拷贝模型;Phase 1 任务清单细化渠道注入由 Scripts/inject_channel.sh
  生成
- 物理迁移:仓库根 Resources/gamehall.zip / Images.xcassets / Res/
  全部 rename 到 docs/res/(git rename detection 自动识别)
2026-06-21 22:32:38 +08:00
joywayer 17a8b96cf8 docs:依赖管理改为纯 SPM + Vendor,移除 CocoaPods(ADR-006)
调研发现 Qiniu SDK 已官方支持 SPM(https://github.com/qiniu/objc-sdk
v8.9.x),AMap 仍仅支持 CocoaPods 或手动 XCFramework;CocoaPods 1.15.2
不兼容 Xcode 26 的 PBXFileSystemSynchronizedRootGroup,需绕道 Bundler
才能升到 1.16+。综合性价比决定不引入 CocoaPods 工具链,所有闭源 SDK
(含 AMap)统一走 Vendor .xcframework 手动接入。

- Design §14.1 三层策略改写为两层(SPM + Vendor),新增 Vendor 接入
  标准流程 6 步法
- Design §14.2 AMap 接入方式从 CocoaPods 改为 Vendor,Qiniu 标注 SPM
  URL 与版本
- Plan §2.3 / §5 Phase 5.1 / §6.1 / §8 同步 AMap Vendor 化
- Plan 新增 ADR-006 完整决策记录
- CLAUDE.md 新增「依赖管理约定」节,禁止引入 CocoaPods
2026-06-21 21:46:19 +08:00
joywayer 2a3d985dd7 调整极光 2026-06-21 20:48:41 +08:00
joywayer d18ea4f1c5 新增所需资源,修改优化文档 2026-06-21 20:40:46 +08:00
joywayer beb05ab451 添加文档和CLAUDE.md 2026-06-21 19:39:22 +08:00