# 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/<SDKName>/`，每个目录附 `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/<SDK>/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`）不一致即视为契约违反。
