§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>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
9f4ccb762e
commit
246f215d6f
+43
-16
@@ -690,18 +690,31 @@ _webView.scrollView.showsHorizontalScrollIndicator = NO;
|
||||
- LocalStorage 由 H5 自管(WKWebView 默认走 WebsiteDataStore)
|
||||
- 加载方式:**`loadFileURL:fileURL allowingReadAccessToURL:dirURL`**(file://),不走 HTTP
|
||||
|
||||
### 4.2 JS 注入(**已按原项目代码全面修订** — 见底部"修订记录")
|
||||
### 4.2 JS 注入(**2026-06-22 重大路径调整:原生不写文件,只覆盖 `window.app_xxx` 全局变量**)
|
||||
|
||||
H5 业务通过 `<script src="app_*.js">` 同步引入 4 个预生成的 `.js` 文件,文件内全是 `var app_xxx=...` 全局变量声明。原 msext 写入位置:`NewRootVC.m:1204`(大厅 initJSdata)/ `gameController.m:2160`(子游戏 initJSdata)/ `gameController.m:1191` `NewRootVC.m:1706`(battery 更新)/ `gameController.m:1198` `NewRootVC.m:1714`(network 更新)/ `AppDelegate.m:259` `gameController.m:197`(gamesname 更新)。
|
||||
H5 业务通过 `<script src="app_*.js">` 同步引入 4 个 `.js` 文件,文件内是 `var app_xxx = "<默认占位>"` 形式的全局变量声明。
|
||||
|
||||
**⚠️ 关键约束:文件名 ≠ 变量名**
|
||||
**契约调整**(与原 msext 行为差异):
|
||||
|
||||
| 文件名(不带 get) | 文件内变量名(带 get) |
|
||||
| 阶段 | msext 旧契约 | 新契约 |
|
||||
|---|---|---|
|
||||
| `app_*.js` 文件来源 | 原生 `NewRootVC.initJSdata` 用 `writeToFile:` 每次启动时写入沙盒 | **H5 团队随 `gamehall.zip` 一起打包**(带默认占位值),原生不写 |
|
||||
| `app_xxx` 全局变量赋值 | H5 引入文件后由文件内的 `var` 声明赋值 | H5 引入文件后默认占位生效;原生用 `WKUserScript(.atDocumentEnd)` + `evaluateJavaScript` 覆盖 `window.app_xxx` 为实际值 |
|
||||
| 路径变量 (`{gamedir}/{gamestart}/`) | 原生需知道写入路径 | 由 H5 zip 包结构自带,原生不感知 |
|
||||
|
||||
新契约下原生侧的工作:
|
||||
1. 在 `WKWebViewConfiguration` 装配阶段 addUserScript 一段 `(function(){ window.app_version=1; window.app_gameconfig='...'; ... })()`,injectionTime `.atDocumentEnd`
|
||||
2. battery / network 变化时用 `webView.evaluateJavaScript("window.app_getbattery=...")` 单条覆盖
|
||||
3. 不再 `writeToFile`,不再关心文件路径
|
||||
|
||||
**⚠️ 命名约束:文件名 ≠ 变量名**(沿用 msext 历史)
|
||||
|
||||
| 文件名(不带 get) | 文件内变量名(带 get),原生需覆盖的 `window.xxx` |
|
||||
|---|---|
|
||||
| `app_battery.js` | `var app_getbattery=...` |
|
||||
| `app_network.js` | `var app_getnetwork=...` |
|
||||
| `app_battery.js` | `app_getbattery` |
|
||||
| `app_network.js` | `app_getnetwork` |
|
||||
|
||||
H5 端 `<script src="app_battery.js">` 引入后读到的是 `app_getbattery`(带 get 前缀),**不是** `app_battery`。任何拼写错误都会让 H5 业务读到 undefined。
|
||||
H5 业务读 `app_getbattery`(带 get 前缀),**不是** `app_battery`。任何拼写错误都会让 H5 业务读到 H5 端的默认占位值(不是实际值)。
|
||||
|
||||
#### `app_data.js`(写到 `{gamedir}/{gamestart}/app_data.js`)
|
||||
|
||||
@@ -727,31 +740,42 @@ var app_invitationcode = "<tuiguang_id>"; // 推广码 / 邀请码
|
||||
> - `app_gamedir`:大厅 = `self.gamedir`(即 BundleConfig.gameDir)/ 子游戏 = `self.gamefilepath`(子游戏目录)
|
||||
> - `app_gamestart` + `app_gamename`:大厅 = `self.gamestart` / 子游戏 = `self.game_name`(子游戏名)
|
||||
|
||||
#### `app_battery.js`(写到 `{gamedir}/{gamestart}/app_battery.js`)
|
||||
#### `app_battery.js`(H5 zip 包内,含 `app_getbattery` 默认占位)
|
||||
|
||||
H5 端默认形式:
|
||||
```js
|
||||
var app_getbattery = 0.85; // ⚠️ 变量名带 get!msext "var app_getbattery=%lf" double 字面
|
||||
```
|
||||
|
||||
更新时机:`viewWillAppear` + `UIDeviceBatteryLevelDidChangeNotification` + 前台切换通知。
|
||||
原生覆盖时机(每次写一行 `window.app_getbattery = N;`):
|
||||
- 首次 `webView didFinish` 后补一次(保证页面就绪即可读到当前电量)
|
||||
- `UIDevice.batteryLevelDidChangeNotification` 触发
|
||||
- `UIApplication.willEnterForegroundNotification`(前台切换补 retroact)
|
||||
|
||||
#### `app_network.js`(写到 `{gamedir}/{gamestart}/app_network.js`)
|
||||
#### `app_network.js`(H5 zip 包内,含 `app_getnetwork` 默认占位)
|
||||
|
||||
H5 端默认形式:
|
||||
```js
|
||||
var app_getnetwork = 2; // ⚠️ 变量名带 get!msext "var app_getnetwork=%d" int 字面:1 无网 / 2 WiFi / 3 蜂窝
|
||||
```
|
||||
|
||||
更新时机:`viewWillAppear` + 网络变化(msext 用 AFNetworkReachability,新外壳用 NWPathMonitor)+ 前台切换通知。
|
||||
原生覆盖时机:
|
||||
- 首次 `webView didFinish` 后补一次
|
||||
- `NWPathMonitor` 状态变化(msext 用 AFNetworkReachability,新外壳用 NWPathMonitor)
|
||||
- 前台切换
|
||||
|
||||
#### `app_gamesname.js`(写到 `{gamedir}/{gamestart}/app_gamesname.js`)
|
||||
#### `app_gamesname.js`(H5 zip 包内,含 `app_gamesname` 默认占位)
|
||||
|
||||
H5 端默认形式:
|
||||
```js
|
||||
var app_gamesname = new Array('game1','game2',...); // ⚠️ var 后面两个空格,沿用 msext AppDelegate.m:259 字面
|
||||
```
|
||||
|
||||
更新时机:`AppDelegate.applicationDidFinishLaunching`(首次写入)+ 子游戏 `gameController.viewInit`(新装一个子游戏后追加;msext gameController.m:197 注释掉了实际写入逻辑,仅 AppDelegate 首次写入是活的)。
|
||||
原生覆盖时机(合并进首次 documentEnd UserScript,即阶段 A):
|
||||
- 首次启动覆盖
|
||||
- 新装一个子游戏后下次进入大厅时覆盖(msext `gameController.m:197` 历史上注释掉了实际写入,仅 `AppDelegate` 首次有效;新外壳每次进入大厅都覆盖一次,更稳)
|
||||
|
||||
> H5 模板里 `index.html` 通过 `<script src="app_data.js">` 等同步引入这 4 个文件。新外壳必须保证这些文件**在 loadFileURL 之前**就写好,否则 H5 启动时变量未定义直接崩。
|
||||
> ⚠️ **新外壳约定**:H5 团队保证 `gamehall.zip` 内 4 个 `app_*.js` 都存在,并提供合理默认占位(即使原生注入失败,H5 至少能读到默认值不崩)。原生不再保证"loadFileURL 之前文件已存在"——这是 H5 端打包责任。
|
||||
|
||||
#### 修订记录
|
||||
|
||||
@@ -760,6 +784,7 @@ var app_gamesname = new Array('game1','game2',...); // ⚠️ var 后面两
|
||||
| 2026-06-22 | 删 `app_gameid` / `app_compareCode`:原项目 grep `var app_` 在 `NewRootVC.m:1204` / `gameController.m:2160` 字面字符串里没有这两项 | daoqi 原项目代码全面 grep 验证 |
|
||||
| 2026-06-22 | `app_battery` 改为 `app_getbattery`、`app_network` 改为 `app_getnetwork`:变量名带 `get` 前缀,与文件名(不带 get)不一致 | daoqi `gameController.m:1191/1198`、`NewRootVC.m:1706/1714` |
|
||||
| 2026-06-22 | 新增 `app_version` / `app_Launchtype` / `app_getwifisignalLevel` / `app_gamename` / `app_invitationcode` / `app_gamesname` 共 6 项 | daoqi `NewRootVC.m:1204`、`gameController.m:2160`、`AppDelegate.m:259` |
|
||||
| 2026-06-22 | **路径调整**:从"原生 `writeToFile` 写 4 个 `.js` 文件"改为"H5 团队 zip 包自带 + 原生 `WKUserScript(.atDocumentEnd)` / `evaluateJavaScript` 覆盖 `window.app_xxx` 全局变量值"。原生不再感知文件路径与字符串包裹符 | H5 团队 / 项目方约定 |
|
||||
|
||||
### 4.3 WKUIDelegate(H5 alert / confirm)
|
||||
|
||||
@@ -979,10 +1004,12 @@ Library/Caches/
|
||||
- [ ] 重装 + 热启动:< 1 秒进入大厅
|
||||
- [ ] 渠道注入:把 `msext/channel/xxx` 目录名改成 `yyy`,重打包后大厅显示的渠道 ID 变为 `yyy`
|
||||
- [ ] iOS 18 / 19 / 26 上启动不卡死
|
||||
- [ ] **`app_*.js` 4 个文件存在**:`{gamedir}/{gamestart}/` 下 `app_data.js` / `app_battery.js` / `app_network.js` / `app_gamesname.js` 全部生成、loadFileURL 前已落盘
|
||||
- [ ] **`app_*.js` 4 个文件由 H5 zip 包内自带**:解压 `gamehall.zip` 后 `app_data.js` / `app_battery.js` / `app_network.js` / `app_gamesname.js` 全部存在(H5 团队打包责任,原生不写)
|
||||
- [ ] **原生 `WKUserScript(.atDocumentEnd)` 覆盖生效**:在 Safari Web Inspector 读 `window.app_channel` 等 13 项启动期变量,必须是**实际渠道值**(来自 `ChannelConfig.plist`),**不是** H5 zip 包里 `app_data.js` 的默认占位值
|
||||
- [ ] **`app_*` 12 + 1 + 1 + 1 = 15 个全局变量命名 100% 正确**(参 §4.2):H5 console 检查 `app_version` / `app_gameconfig` / `app_gamedir` / `app_gamestart` / `app_agent` / `app_appversion` / `app_market` / `app_channel` / `app_Launchtype` / `app_getwifisignalLevel` / `app_gamename` / `app_invitationcode` / `app_getbattery` / `app_getnetwork` / `app_gamesname` 全部 `!== undefined`;尤其大小写 `app_Launchtype`(L 大写)/ `app_getwifisignalLevel`(wifi 小写 + signal/Level 区分)/ `app_getbattery`、`app_getnetwork`(带 get 前缀)必须精确
|
||||
- [ ] **大厅 vs 子游戏字面差异**:大厅 H5 内 `app_Launchtype === "0"`、子游戏 H5 内 `app_Launchtype === "1"`
|
||||
- [ ] **大厅 vs 子游戏字面差异**:大厅 H5 内 `app_Launchtype === 0`(数字 0,非字符串 `"0"`)、子游戏 H5 内 `app_Launchtype === 1`
|
||||
- [ ] **不要存在已撤销的变量**:H5 console 检查 `app_gameid` / `app_compareCode` 应为 `undefined`(早期 Contract §4.2 误列,原项目代码字面字符串里不写)
|
||||
- [ ] **阶段 B 动态覆盖**:模拟器 Features → Battery State 切换电量;Web Inspector 读 `window.app_getbattery` 应实时跟随;同样切换 Network Link Conditioner 验证 `window.app_getnetwork`
|
||||
|
||||
### B. 桥接
|
||||
- [ ] H5 调 `accreditlogin` → 微信弹授权页 → 同意后 H5 收到 `sharelogin` 回调,7 字段完整
|
||||
|
||||
Reference in New Issue
Block a user