# ylgamehall 进贤聚友棋牌 iOS 新外壳(greenfield 重写)。原生外壳 + 内置 H5(`gamehall.zip` 解压到沙盒)+ WebViewJavascriptBridge 桥接,企业签 / 超级签 / TF 渠道分发,**不上架 App Store**。 > 同仓库 `../daoqi/` 是已上线多年的旧外壳 `msext`(Objective-C / MRC / iOS 9.0+),作为本项目的"工作参照实现"。本项目按现代 iOS 标准重写,但 **H5 端零修改** 是不可妥协的第一准则。 --- ## 技术栈 | 项 | 值 | |---|---| | 语言 | Swift 6.0(`SWIFT_APPROACHABLE_CONCURRENCY=YES`,`SWIFT_DEFAULT_ACTOR_ISOLATION=MainActor`) | | UI | SwiftUI + UIKit 互操作(按需) | | 最低 iOS | 15.6 | | 设备 | iPhone + iPad,仅横屏,`UIRequiresFullScreen=true` | | Xcode | 26.5+(`objectVersion=77`,File System Synchronized Group) | | 工程入口 | `ylgamehall.xcodeproj`(**无 CocoaPods**,不使用 workspace) | | 依赖管理 | SPM(首选)+ Vendor `.xcframework`(闭源 SDK) | | Bundle ID | `com.skyapp.ylgamehall` | | 并发模型 | Swift async/await + actor 隔离(**不使用 Combine**) | ### SPM 依赖 - `ZIPFoundation` — H5 zip 解压 - `HappyDNS` — 七牛 SDK 配套 - `Qiniu`(`qiniu/objc-sdk` v8.9.x) — 七牛对象存储 ### Vendor 闭源 SDK 放在 `Vendor//`,每个目录附 `README.md` 记录版本来源: - `Vendor/WechatSDK/` — 微信开放平台 - `Vendor/AMap/` — 高德定位 - `Vendor/OpenCoreAMR/` — AMR 编解码(`libopencore-amrnb.a` / `libopencore-amrwb.a`) --- ## 目录结构 ``` ylgamehall/ ├── CLAUDE.md # AI 助手协作约定(第一权威) ├── README.md # 本文件 ├── ylgamehall.xcodeproj # Xcode 工程 ├── ylgamehall/ # App target │ ├── AppDelegate.swift │ ├── SceneDelegate.swift │ ├── Info.plist │ ├── ylgamehall-Bridging-Header.h │ ├── Assets.xcassets │ ├── Base.lproj/ # LaunchScreen.storyboard │ ├── Resources/ │ │ ├── gamehall.zip # 内置 H5 包 │ │ ├── ChannelConfig.plist # 渠道配置(gameid / channel / agent / market 等) │ │ ├── AppSecrets.plist # SDK 凭证(微信 AppID / 高德 Key / 七牛 等) │ │ └── JS/ │ │ └── WebViewJavascriptBridge.js │ └── Source/ │ ├── Audio/ # AMR 编解码、录音 / 播放、录音浮窗 │ ├── Bridge/ # WebViewJavascriptBridge + 各 Handler │ │ └── Handlers/ # 39 项 H5↔Native 桥接 handler │ ├── Coordinator/ # AppCoordinator 启动流水线 │ ├── Location/ # 高德定位封装 │ ├── Login/ # 微信登录 │ ├── Network/ # RemoteConfig、版本解析、七牛上传 │ ├── Resource/ # 沙盒路径、H5 zip 升级、解压、子游戏下载 │ ├── SDK/ # 微信 / 高德 SDK 包装 │ ├── Share/ # 微信 / QQ / 抖音分享 + 分享面板 │ └── WebView/ # WKWebView 容器、Splash、子游戏 VC ├── Vendor/ # 闭源 SDK │ ├── WechatSDK/ │ ├── AMap/ │ └── OpenCoreAMR/ └── docs/ # 项目文档(见下节) └── res/ # 维护者私人素材池(项目代码不感知) ``` --- ## 文档体系 所有架构决策、契约定义、执行计划、验收清单都在 `docs/` 下。**任何代码修改前先读对应文档**。 | 文档 | 角色 | 何时读 | |------|------|--------| | [`CLAUDE.md`](./CLAUDE.md) | 项目协作约定、契约边界声明、两条核心原则 | **每次对话先读** | | [`docs/H5-Native-Contract.md`](./docs/H5-Native-Contract.md) | H5 ↔ 原生 桥接**契约**(黑盒可观察行为) | 涉及桥接接口必读 | | [`docs/H5-Native-Implementation-Design.md`](./docs/H5-Native-Implementation-Design.md) | 新外壳实施蓝图(架构、模块、代码骨架) | 实现新外壳必读 | | [`docs/Development-Plan.md`](./docs/Development-Plan.md) | 开发执行计划(Phase 0–10、依赖图、进度追踪) | 排期 / 进度更新必读 | | [`docs/Verification-Checklist.md`](./docs/Verification-Checklist.md) | 功能验证清单(统一验收的操作手册) | 阶段验收时勾选 | | [`docs/SDK-Integration-Guide.md`](./docs/SDK-Integration-Guide.md) | 微信 / 高德 / opencore-amr / 七牛 接入手册 | 接 SDK 时按章节落地 | | [`docs/H5-Debug-Guide.md`](./docs/H5-Debug-Guide.md) | H5 端调试(Safari Web Inspector) | 调试 H5 console / Network / 断点时 | | `../daoqi/` | 原项目 `msext` 工作参照实现 | 遇到行为差异 / 渠道注入 / SDK 时序等不确定问题时优先参考 | > 文档优先级冲突时:**Contract > Design > Plan**。 --- ## 核心原则(两条,原则 A 是第一准则) ### 原则 A:H5 端零修改(不可妥协) H5 端 **一行代码、一个字符、一个文件名、一个调用时机都不许改**。遇到契约边界冲突时,**回到原 msext 老路**、由原生 Swift 端硬扛,哪怕代码看起来"不现代"。 必须 1:1 与现网一致的五类内容: 1. 桥接接口名(handler 字符串,含历史驼峰 / 下划线大小写) 2. 参数字段名(含 `"title "` 末尾空格、`Province` 大写 P 等历史包袱) 3. 参数数据结构(类型、嵌套、fallback) 4. H5 端注册方式(`WebViewJavascriptBridge` JS 协议 / 弹层 `window.settings.xxx`) 5. 空实现接口也必须保留注册(`opensaoma`、`getGameplay` 等) 详见 [`docs/H5-Native-Contract.md`](./docs/H5-Native-Contract.md)。 ### 原则 B:原生内部自由重构 原生内部一切自由——技术栈、模块结构、状态管理、SDK 选型、并发模型按现代 iOS 标准重新设计,不照搬旧项目实现细节。 **冲突时无条件选 A**:原生多一层适配 / 一段"看似过时"的代码可接受;契约破裂不可接受。 --- ## 构建 ### 前置 - macOS + Xcode 26.5+ - 项目方提供的 SDK 凭证(按 [`docs/SDK-Integration-Guide.md`](./docs/SDK-Integration-Guide.md) 填到 `Resources/AppSecrets.plist`) - Vendor 闭源 SDK 二进制(按 `Vendor//README.md` 放置) ### 构建步骤 ```bash open ylgamehall.xcodeproj ``` Xcode → Product → Run(或 ⌘R)。 > **不要**新建 `Podfile` / `.xcworkspace`。本项目通过 SPM + Vendor 两层管理依赖,禁止引入 CocoaPods(ADR-006)。 ### 渠道配置 `ylgamehall/Resources/ChannelConfig.plist` 是渠道注入入口(替代 msext 时代的"空目录名注入"机制): | key | 说明 | |---|---| | `gameid` | 游戏 ID | | `channel` / `gamedir` | 渠道标识 / H5 解压子目录名 | | `gamestart` | H5 启动入口目录名(默认 `gamehall`) | | `gameconfig` | RemoteConfig 拉取地址 | | `market` | 市场标识 | | `agent` | 代理标识 | | `appversion` | 当前外壳版本号(用于 RemoteConfig 升级判断) | --- ## 提交与协作 - commit message 使用中文短句,描述"做了什么 + 为什么" - 改动通过最小验证(BuildProject / 关键路径手测 / 单测)后可直接 commit,不必每次确认 - 涉及桥接接口名 / 参数字段名 / 数据结构的改动必须在 commit message 中明示 **"契约影响"** 并附 [`docs/H5-Native-Contract.md`](./docs/H5-Native-Contract.md) 对应章节 - 每完成一个 Phase 子项立即同步勾选 [`docs/Development-Plan.md`](./docs/Development-Plan.md) §5 / §8 - 不在未授权情况下执行 `git push --force` / `git reset --hard` / `git rebase` 等不可逆操作 --- ## 验收 新外壳完成后,**在不修改 H5 任何一行代码** 的前提下,逐项跑 [`docs/H5-Native-Contract.md`](./docs/H5-Native-Contract.md) §10 的 26 项验收清单。任意一项 H5 表现与现网(`../daoqi/msext`)不一致即视为契约违反。