joywayer
|
d76064c4c5
|
添加multishare配置,用来开启关闭3分享
|
2026-07-03 22:20:48 +08:00 |
|
 joywayerandClaude Opus 4.7
|
04e702a99b
|
Phase 1.F: WebView 加载从 file:// 迁到 ylgame://h5 自定义 scheme
为未来 Cocos 子游戏 H5 build 适配铺路(file:// 下 Cocos XHR/fetch 受
null-origin 限制几乎必踩坑),同时保留大厅 + 子游戏跨页 localStorage
共享语义(用单虚拟 host `h5` 让所有 H5 same-origin)。
变更:
- 新增 AppSchemeHandler(WKURLSchemeHandler 单例 + Range/MIME/异步 IO/
取消语义;闭包只携 Sendable ObjectIdentifier,不捕获 task)
- SandboxPaths 加 lobbyIndexAppURL / subGameIndexAppURL builders
- BridgedWebView 注册 scheme handler(WKWebView init 前)
- WebContainerViewController / SubGameViewController 的 loadFileURL
→ webView.load(URLRequest),OverlayViewController 不变
文档:
- Plan 新增 Phase 1.F (1.18-1.21) + ADR-010 决策记录 + 进度勾选
- Design 新增 §7.6 包含 URL 结构 / 实现要点 / 等价性表 / Cocos 预检脚本
- Contract §0.2 / §4.1 / §10 验收清单同步切换说明(H5 可观察差异:
location.protocol "file:" → "ylgame:",项目方已 grep 确认现网 H5
不依赖此字面)
存量影响:file:// → ylgame:// origin 切换时老用户 localStorage 一次性
清零,已与项目方确认业务可接受、不做迁移补偿。
BuildProject 通过。Plan 进度已勾选 1.18/1.19/1.20。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-29 08:58:00 +08:00 |
|
 joywayerandClaude Opus 4.7
|
83d9502dee
|
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>
|
2026-06-27 21:07:55 +08:00 |
|
 joywayerandClaude Opus 4.7
|
8125dd4d11
|
1.11 修订:VersionResolver 改单链 4 层 fallback,删除双子树合并算法(契约影响)
【契约影响】
- RemoteConfig 模型:Agent 节点移除 channellist 字段(线上 JSON 实际只挂 gamelist;此前误读 chulishengji 引入的 channellist 是空 schema)
- VersionResolver 解析算法:从"双子树 + 字段级合并"改为"agentlist → gamelist → channellist → marketlist 单链 4 层 fallback",行为按 daoqi NewRootVC.m:689-810 主路径
- 对外 API ResolvedVersion / resolve(config:agentId:channelId:marketId:gameId:) 签名零变化,WebContainerViewController / SubGameViewController 调用点未动
【设计要点】
- 4 节点类型 conform 同一 private protocol RemoteConfigNode
- 5 字段共用 pickString / pickInt 两个倒序 fallback 工具,不允许为某字段单独写 if 链
- buildChain 集中处理"任一层 id 不匹配立刻截断"语义
【文档同步】
- Design §6.3.2 整段重写
- Plan ADR-008 顶部追加"第三轮修订(2026-06-27)"小节 + 第二轮误读复盘
- Plan ADR-008-D 替换为单链 4 层算法说明 + 保留修订史
- Plan §1.11 / ADR-008-I / 最后更新日期 / Verification-Checklist L73 同步
参考契约章节:docs/H5-Native-Implementation-Design.md §6.3.2、docs/Development-Plan.md ADR-008-D
BuildProject 通过。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-27 20:04:19 +08:00 |
|
joywayer
|
06b7686e17
|
启动文字提示,h5调试加入
|
2026-06-24 21:20:05 +08:00 |
|
 joywayerandClaude Opus 4.7
|
4986f36967
|
业务期 app_getbattery / app_getnetwork 改为 evaluateJavaScript 重新赋值
按用户指示调整变化时机制:
启动期(保持):loadFileURL 之前写 4 个 app_*.js 文件,H5 同步
<script src> 引入读到实际值
业务期(调整):变化时**不重写文件**,改为
webView.evaluateJavaScript("window.app_getbattery=N;") 直接重新赋值
全局变量。原因:H5 已加载完后 <script src> 不会再 fetch,重写文件
对当前页面无影响(仅影响下次 reload),改 evaluateJavaScript 即时
生效 + 无文件 IO 开销。
与 §3.2 反向 callback 双轨同时执行:
- evaluateJavaScript 让 H5 业务期同步读 app_xxx 永远拿到最新值
- bridge.call 让 H5 注册的 callback handler 收到事件主动响应
WebContainerViewController.writeAppDataFiles 改动:
- BatteryMonitor.onChange:Task @MainActor await
webView.evaluateJavaScript("window.app_getbattery=N;") + bridge.call
- NetworkMonitor.onChange:同款 evaluateJavaScript + bridge.call
- AppLifecycleObserver:appservice 无对应 app_* 全局变量,只走 bridge.call
文档同步:
- Design §7.5.2 改为「两阶段」表述:启动期写文件 + 业务期 evaluateJavaScript
- Design §7.5.4 接入点代码示例同步
- Contract §4.2 app_battery.js / app_network.js 子节更新时机段
- Contract §4.2 修订记录加一行
- Plan §6.4 里程碑加一行 + 前两轮 commit hash 补充
BuildProject 通过
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-22 18:50:53 +08:00 |
|
 joywayerandClaude Opus 4.7
|
0a313afe8e
|
app_appversion 业务语义纠正:审核切换标志 0/1(非版本号)
调研 daoqi/msext NewRootVC.m:1190-1208 initJSdata 发现 app_appversion
真实业务语义是审核切换标志,**不是 App 的版本号**:
if (远端 ResolvedVersion.appVersion >= 本地 BundleConfig.appVersion) {
app_gameconfig = BundleConfig.gameConfig; // 正常业务接口
app_appversion = '0'; // 标志:正常
} else { // 远端 < 本地(罕见,审核期 / IPA 已升远端未跟上)
app_gameconfig = BundleConfig.appleConfig; // 苹果审核期接口
app_appversion = '1'; // 标志:审核期
}
H5 端 if (app_appversion === '1') 切苹果审核期分支;99% 时间下都是 '0'
+ gameconfig。
当前代码两处错误:
❌ app_appversion 写成 "43"(版本号字符串)
❌ app_gameconfig 永远是 BundleConfig.gameConfig 硬编码
不符合契约(H5 拿到错误标志会走错分支)。按 CLAUDE.md 原则 A 第一准则
必须 1:1 等价 msext。
修复(Source/WebView/AppDataWriter.swift writeAppData):
- 加 result 计算:localAppVer = Int(bc.appVersion), remoteAppVer =
resolvedVersion?.appVersion ?? localAppVer;result = remoteAppVer >=
localAppVer ? 0 : 1
- 加 gameConfigStr 切换:result == 0 ? bc.gameConfig : bc.appleConfig
- app_appversion 写字面 '\(result)' 单引号包裹(与 msext "var
app_appversion='%d';" 等价)
- Logger 输出加 result 说明 + local/remote 版本号便于调试
Contract §4.2:新增详细业务语义说明段(含 msext 原 ObjC 代码 + result
0/1 含义解读 + app_gameconfig 动态切换说明),修订记录加一行。
Design §7.5.1 表格:#2 app_gameconfig 数据源改为"动态切换",#6
app_appversion 数据源改为"审核切换标志"。
Plan §6.4 里程碑加一行。
BuildProject 通过
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-22 18:28:08 +08:00 |
|
 joywayerandClaude Opus 4.7
|
13cc24b463
|
§7.5 路径回退到 writeToFile:撤销 evaluateJavaScript 路径
CLAUDE.md 原则 A 升级为第一准则(H5 端零修改不可妥协)后,重新评估
上一轮 commit 246f215 引入的 evaluateJavaScript 路径:
- WKUserScript(.atDocumentStart) 注入会被 H5 自带 var app_xxx 声明
覆盖回退
- WKUserScript(.atDocumentEnd) 又太晚,H5 业务顶层 <script> 已经
读过默认值
- 没有"在 <script src> 之后、业务 <script> 之前"的精确时机
- 任何"让 H5 改一行 / 改一个文件"的妥协方案违反原则 A 第一准则
- 详细分析见 CLAUDE.md「典型案例 3」
撤销方案:回到原 msext writeToFile 路径,原生在 loadFileURL 之前写
4 个 app_*.js 文件到沙盒,H5 启动时 <script src> 同步引入即可读到
实际值,时序 100% 等价 msext。
Design §7.5 全面回退(-285 / +126 行):
- §7.5 头部:标题 / 简介改回写文件路径;中间走过两次弯路的完整决策
链记录在头部(commit f68b0db → 246f215 → 本次 commit)
- §7.5.2 注入时机表 → 4 个文件写入时机表,附"为什么不要照搬
WKUserScript 注入"警告段
- §7.5.3 删除 AppDataInjector + .legacy 标注;AppDataWriter 升回主路径
(保留 logger debug 输出 / msext 字面对齐细节 / 转义 / 大小写)
- §7.5.4 接入点:writeInitial + writeBattery + writeNetwork 三阶段,
addObserver 持续监听
- §7.5.5 大厅 / 子游戏 / 弹层差异表回到 "app_data.js / app_gamesname.js
/ app_battery.js / app_network.js" 维度
- §7.5.6 与 msext 差异表回到"writeToFile 等价化"对比
- §7.5.7 与 §3.4.1 polyfill 关系:§7.5 文件预写为主路径;
WKUserScript + evaluateJavaScript "探索后撤回"
- §7.5.8 联调路径恢复 cat 文件路径,加 4 种现象诊断表
Contract §4.2 同步:
- 头部说明改回 "原生 writeToFile 写文件" + 撤销中间 evaluateJavaScript
路径的复盘段
- 子节标题回到 "写到 {gamedir}/{gamestart}/app_*.js"
- 子节"更新时机"段回到 loadFileURL 前 / addObserver / 前台切换
- 删除"H5 团队 zip 自带 + 默认占位"约定(不再适用,原生重新负责写入)
- 修订记录新增一行"路径再次调整(最终)"
Contract §10 验收清单同步:
- "H5 zip 自带 4 个 .js" → "沙盒下 4 个 .js 存在(xcrun simctl + cat 验证)"
- 删"原生 WKUserScript 覆盖生效"项 → 加"值是实际渠道值而非占位"
- "阶段 B 动态覆盖" → "battery/network 变化重写文件"
Plan §6.4 里程碑加两行:CLAUDE.md A 升级 + §7.5 最终回退。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-22 12:40:07 +08:00 |
|
 joywayerandClaude Opus 4.7
|
246f215d6f
|
§7.5 重大路径调整:app_* 改为 evaluateJavaScript 覆盖 window.app_xxx
H5 团队新约定:app_*.js 4 个文件由 H5 团队自带在 gamehall.zip 内(含
默认占位值),原生**不再写文件**,只用 WKUserScript(.atDocumentEnd) +
evaluateJavaScript 覆盖 window.app_xxx 全局变量的实际值。
Design 三处大改 (+339/-91 净 +248 行):
§7.5 标题 / 头部:
- 标题:H5 app_*.js 预注入文件机制 → 修改 H5 端 app_*.js 全局变量值
(evaluateJavaScript 路径)
- 新增「2026-06-22 重大方向调整」说明段:3 条理由 + 旧路径降级为
§7.5.3.legacy
§7.5.2 注入时机:
- 旧:4 个文件写入时机表
- 新:两阶段注入表(A 首次 documentEnd UserScript / B 动态
evaluateJavaScript)+ 为什么必须 documentEnd 不能 documentStart
(H5 的 var 声明会回退我们的值)+ 为什么不直接走异步 callHandler
(违反契约原则 A)
§7.5.3 Swift 骨架:
- AppDataWriter (writeToFile) → AppDataInjector (UserScript +
evaluateJavaScript)
- 阶段 A makeInitialUserScript:拼装 (function(){window.app_xxx=...})()
documentEnd 注入;包含 13 项启动期已知字段
- 阶段 B injectBattery / injectNetwork:async evaluateJavaScript 单条覆盖
- Logger.debug 保留所有 key=value 打印(联调可观察性)
- 旧 AppDataWriter 保留为 §7.5.3.legacy(明示不要实施)
§7.5.4 接入点:
- configuration.userContentController.addUserScript(阶段 A)
- addObserver(batteryLevelDidChange) → injectBattery
- networkMonitor.stateDidChange → injectNetwork
- bridgedWebView.didFinishOnce 首次补一次 battery + network
§7.5.5 / .6 / .7 / .8 同步调整:差异表 / msext 对比 / 联调路径
- §7.5.8 路径 2 从「沙盒 cat .js 文件」改为「Safari Web Inspector 看
window.app_xxx 实时值」(不再写文件无文件可 cat)
- 加阶段 B 手动触发验证(模拟器 Battery State / Network Link Conditioner)
Contract §4.2 同步:
- 新增 msext 旧契约 vs 新契约对比表(3 维度:文件来源 / 赋值机制 / 路径感知)
- 子节标题从「app_battery.js(写到 ...)」改为「H5 zip 包内,含
app_getbattery 默认占位」+ 更新时机改写为 evaluateJavaScript 时机
- 「H5 团队保证 zip 内 4 个 app_*.js 存在 + 合理默认占位」约定
- 修订记录加一行路径调整
Contract §10 验收清单调整:
- 文件验收:4 个 .js 由 H5 zip 自带(不是原生生成)
- 新增「原生覆盖生效」验收:Web Inspector 读 window.app_channel 必须
是 ChannelConfig.plist 实际值,不是 H5 默认占位
- app_Launchtype 类型修正为数字 0/1(不是字符串)
- 新增「阶段 B 动态覆盖」验收:模拟器手动触发 battery/network 变化
Plan §6.4 里程碑加新一行记录本次路径调整。
至此 H5↔Native 通讯 5 条路径全部按新契约对齐:
1. WVJB 异步 callback(22 项)
2. Native→H5 反向 callback(15 项)
3. **window.app_xxx evaluateJavaScript 覆盖(15 项)** ← 本次重写
4. 弹层 settings.* polyfill(4 项)
5. WKUIDelegate alert/confirm(2 项)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-22 08:19:53 +08:00 |
|
 joywayerandClaude Opus 4.7
|
9f4ccb762e
|
Design §7.5.3/.8:AppDataWriter 加 os.log 调试输出 + 联调可观察性
用户在 Phase 1.17 联调准备时反馈:app_*.js 写入时应该有控制台输出,
方便调试。本 commit 在 §7.5 蓝图层落实可观察性,Phase 2 实施按此骨架
就有完整 debug log。
§7.5.3 AppDataWriter 改动(同时修正若干与 msext 字面不一致的细节):
- 引入 os.Logger(subsystem: ylgamehall, category: AppDataWriter)
- writeAppData / writeGamesName / writeBattery / writeNetwork 全部打印
{ContainerRole} + 文件路径 + 每个 key=value 一行,便于和 H5
console.log(app_xxx) 逐项对账
- ContainerRole 实现 CustomStringConvertible("lobby" / "subGame(name)")
- Logger.debug 级别:Debug 出 Xcode 控制台,Release 自动过滤
- privacy: .public 标注(确保字符串值不被 Logger 模糊化为 <private>)
**字面修正**(对照 daoqi/msext 实际代码二次校对):
- 字符串包裹符 " → '(msext 用 "var x='%@';" 单引号)
- escape 转义对象从 \" 改为 \'(与单引号包裹配套)
- 数值字段(version / Launchtype / getwifisignalLevel / appversion)
去掉引号,沿用 msext "var app_version=1;" / "var app_appversion='%d';"
- app_gamesname 从 JS array literal [...] 改为 new Array(...),
var 后两空格,严格 AppDelegate.m:259 字面
§7.5.8 新增「联调时的可观察性(Phase 1.17 调试手段)」:
- 路径 1:Xcode 控制台 — 原生 os.log 输出格式样例
- 路径 2:沙盒文件直接 cat — xcrun simctl get_app_container 命令 +
4 个 .js 文件 cat 验证
- 路径 3:H5 console — Safari Web Inspector 逐项 console.log(app_xxx)
样例,标注 ⚠️ 大小写硬约束(Launchtype L 大写 / battery 带 get 前缀)
- 路径 4:真机 Safari 调试启用方法
- Release 注意事项:os.log .debug 自动过滤避免性能开销和敏感字段外泄
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-22 08:09:57 +08:00 |
|
 joywayerandClaude Opus 4.7
|
0cdd709e66
|
中优 3 项收尾:Plan §6.4 里程碑 + Design §20.1 拆分 + Contract §10 验收清单
补完本轮 audit 与 Design 大改后的文档边界,避免后续 Phase 实施者
按陈旧描述走弯路。
1. Plan §6.4 文档同步段新增「Design 接口骨架覆盖里程碑」表:
- 4 行时间线记录 Phase 1 闭环 / Design 全 51 项接口骨架 / Contract §4.2
按 daoqi 原项目修订 / CLAUDE.md 加典型案例的 commit hash
- 末尾澄清「§3.4.1 撤销说明」与 §7.5 主路径关系,避免新人疑惑
2. Design §20.1 LobbyHandlers 加架构说明段:
- 明示实际拆为 AudioHandlers / DeviceHandlers / LocationHandlers /
ShakeHandlers / OpenurlTitleDataHandler 5 个 sub-struct(§8.1.1 /
§8.4.1 / §8.6 / §8.7 / §3.4.2 各自归属)
- LobbyHandlers 成为聚合点,依次调子 .register()
- 保留 monolithic register 速查表作为与 Contract §3.1 编号对账用
- 每行注释 §3.1 [N] 编号便于追溯
3. Contract §10 验收清单加 5 项硬约束:
§A 启动新增:
- app_*.js 4 个文件存在
- 15 个 app_* 全局变量命名 100% 正确(大小写硬约束)
- 大厅 vs 子游戏 app_Launchtype = "0"/"1" 字面差异
- app_gameid / app_compareCode 必须 undefined(早期 Contract 误列)
§B 桥接新增:
- H5 alert(msg) → UIAlertController 单按钮
- H5 confirm(msg) → 取消/确定 双按钮 + 正确返回 bool
至此 Plan / Design / Contract 三文档完全对齐 51 项接口(含 §7.5 app_*.js
15 个、§3.7 WKUIDelegate 2 个)。Phase 2 实施可直接对照 Contract §10
验收清单做契约测试。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-22 08:02:24 +08:00 |
|
 joywayerandClaude Opus 4.7
|
f68b0dba93
|
Design §7.5:补 H5 app_*.js 预注入文件机制(15 个变量),§3.4.1 polyfill 撤销
按 CLAUDE.md「先看原项目」规则深度审查 daoqi/msext NewRootVC.initJSdata /
gameController.initJSdata / AppDelegate 写入逻辑后发现:
**关键纠正**:H5 在 iOS 9+ 路径下的真实读值机制是 §4.2「写 app_*.js 文件
+ H5 <script src> 同步引入」,不是早期 commit 82bad8a 实现的
§3.4.1 window.settings.getXxx() polyfill(那是 §附录 A 旧桥 JSExport
路径,契约明示「新外壳如最低系统 ≥ iOS 14 可不实现」,本项目最低
iOS 15.6 → 无需实现)。
§3.4.1 处理:标题改为「⚠️ 撤销」+ 完整说明撤销原因;旧 polyfill 代码
骨架保留为 §3.4.1.legacy 作为数据源映射参考(不删除以保 git log 整洁,
也方便 Phase 2 实施者了解 9 项 getter 的等价数据来源)。
§7.5 新章节覆盖 15 个变量(用户列 14 + audit 发现 app_invitationcode):
- §7.5.1 完整映射表:变量名 / 大厅值 / 子游戏值 / 数据源 / 文件
- §7.5.2 4 个文件写入时机(一次性 vs 事件驱动)+ 为什么写文件不
evaluateJavaScript(保证 <script src> 同步引入时机)
- §7.5.3 AppDataWriter struct Swift 骨架(escape 4 种特殊字符避免
渠道字段含引号导致 H5 JS 解析错)
- §7.5.4 WebContainerViewController 接入点:loadFileURL 前 writeInitial
+ writeBattery + writeNetwork;持续监听 batteryLevelDidChange /
NWPathMonitor 触发增量重写
- §7.5.5 大厅 / 子游戏 / 弹层 4 维度差异(弹层不写 app_*)
- §7.5.6 与 msext 6 维度差异表(单一真相 / 转义 / 大小写严格)
- §7.5.7 §7.5 vs §3.4.1 vs §3.4 OverlayBridge vs §3.2 callback 四条
路径关系澄清
大小写严格契约:app_Launchtype(L 大写)/ app_getwifisignalLevel(wifi
小写、signal/Level 区分大小写)— 任何拼写错误会让 H5 业务读到 undefined。
至此 H5 端 JS 与原生通讯的完整 5 条路径全部覆盖:
1. WebViewJavascriptBridge 异步 callback(§5/§8/§3.1,22 项 handler)
2. Native→H5 反向 callback(§3.2,15 项)
3. app_*.js 文件预注入全局变量(§7.5,15 项)
4. 弹层 window.settings 同步 polyfill(§3.4,3 项 + §3.4.2 OpenurlTitleData)
5. WKUIDelegate alert / confirm(§3.7,2 项)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-22 07:51:13 +08:00 |
|
 joywayerandClaude Opus 4.7
|
33574a1cc2
|
Design §3.7:补 WKUIDelegate alert / confirm 2 项接口
覆盖契约 §4.3 H5 alert(msg) / confirm(msg) 触发原生弹窗的硬约束。
WKWebView 默认行为是直接吞掉 H5 的 alert/confirm 不弹任何窗口,必须实现
WKUIDelegate 才有响应。不实现的代价:H5 业务里 alert("登录失败")
之类的提示用户完全看不见,业务哑火无可视化报错。
§3.7 实现骨架:
- runJavaScriptAlertPanelWithMessage → UIAlertController .alert,
标题 appDisplayName,单"确定"按钮,completionHandler() 必须调一次
- runJavaScriptConfirmPanelWithMessage → "取消"/"确定" 两按钮,
completionHandler(false/true) 必须调一次
- 接入点:bridgedWebView.webView.uiDelegate = self 在 viewDidLoad
与 navigationDelegate 一起设置
§3.7.1 与 msext 4 维度差异表(标题来源 / 按钮顺序 / 样式 / 并发)+
明示"未实现导致的现象"提醒,方便 1.17 真机联调时排查。
至此契约 §3 + §附录 A + §4.3 共 51 项接口(22 异步 handler + 15 反向 callback
+ 3 弹层 polyfill + 9 同步 getter polyfill + 2 WKUIDelegate)的 Design 实现
骨架全部覆盖完整。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-22 07:33:33 +08:00 |
|
 joywayerandClaude Opus 4.7
|
5f5f6a9ff9
|
Design §3.4.2:补 OpenurlTitleData handler — 大厅打开 threeView 弹层
覆盖 §3.1 [15]OpenurlTitleData,是大厅 WVJB 桥的异步 handler,作用是
触发新的 OverlayViewController push 到导航栈。补在 §3.4 弹层桥章节内
(与 §3.4 settings polyfill 一脉相承),叫 §3.4.2。
§3.4.2 OpenurlTitleDataHandler:
- 节流:throttle final class 持 lastOpen Date,3 秒内重复调用被吞掉但
cb 仍要回(否则 H5 会等)
- 入参解析:url 必填;"title " 末尾有空格(msext 历史契约硬约束,必须
obj["title "]);data 透传;orientation 0/1 但本项目固定横屏
- 调 LobbyCoordinator.pushOverlay 打开 OverlayViewController
OverlayViewController 接入:
- WKWebViewConfiguration + UserScript 注入:
1. §3.4 OverlayBridge.polyfill(settings.backgameData/browser/finishweb)
2. window.app_data = "<escaped data>" 把业务数据透传到 H5
- 等价于 msext threeView 的 JSContext setObject:forKey:@"settings" 行为
§3.4.3 与 msext 5 维度差异表:UIWebView → WKWebView / "title " 末尾空格
严格保持 / 节流类替代静态变量 / UserScript atDocumentStart 注入避免 race
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-22 07:32:30 +08:00 |
|
 joywayerandClaude Opus 4.7
|
a06a18c3aa
|
Design §8.7:新增 ShakeKit + 4 项接口实现骨架
覆盖 §3.1 [7]startshake / [8]stopshake / [9]SwitchShake +
§3.2 [5]shakeEnd 反向 callback 共 4 项接口。
§8.7.1 ShakeKit module 骨架:
- canShake / canVoice 开关位(@MainActor 实例属性,取代 msext 全局变量)
- handleMotionEnded(.motionShake) 集中处理:判 canShake → 播音效 → 触发 callback
- shake_sound_male.mp3 复用 AudioKit.AudioPlayer.playOnce 统一路径
§8.7.1 接入 VC:
- WebContainerViewController.canBecomeFirstResponder = true
- viewDidAppear 调 becomeFirstResponder(必要,否则 motionEnded 不触发)
- motionEnded(_:with:) 转发到 shakeKit.handleMotionEnded
§8.7.2 H5 handler 实现:
- 【7】startshake : canshake=YES + cb "startshake from accreditlogin"
(字面字符串带 "from accreditlogin" 后缀沿用历史)
- 【8】stopshake : canshake=NO + cb 同上
- 【9】SwitchShake : data int → canvoice = (1==YES) + cb "SwitchShake"
- 反向 [5]shakeEnd: data=nil,由 motionEnded → onShakeEnded 触发
§8.7.3 与 msext 6 维度差异表(全局变量 → 实例属性 / 音效统一 /
motionEnded 集中处理 / canBecomeFirstResponder 基类统一 / responseCallback 字面保留)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-06-22 07:31:08 +08:00 |
|
 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 |
|
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
|
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 |
|