- 契约规范 §7:新增屏幕方向约束——默认横屏、不跟随传感器自动旋转; 但遵守 H5 零改动铁律,保留 orientation/SwitchOverGameData webtype/通用网页 orientation 三处 H5 显式方向控制(含竖屏),与原 Android 一致 - 框架指南 §7.4:实现落地——module.json5 orientation:landscape 默认横屏 + 运行时 window.setPreferredOrientation 按 H5 请求动态切换 - 经核对原 Android:上述三处确为真实竖屏切换(非死代码),故定调为 '默认横屏 + 不破坏 H5 方向控制' Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
51 KiB
TSGame 原生 ↔ H5 接口契约与启动流程总规范(跨平台适配版)
文档目的:本规范以现有 Android 工程的真实代码为唯一依据,抽象出"原生容器"与"H5 游戏内容"之间的完整接口契约和启动/资源加载流程。 目标是:在一个全新的原生平台(HarmonyOS)上重新实现"原生容器",使现有 H5 一行代码都不改动即可正常运行。
适配原则:
- 本文档只规定"契约"(协议、接口名、参数结构、调用时机、数据流),不规定原生内部如何实现——原生侧(包括 HarmonyOS)可根据平台能力自由实现,只要对外行为与本契约一致即可。
- 文中所有接口名、参数字段、常量值均来自真实源码,并标注了来源文件与行号,便于核对。
- 凡现有 Android 代码中"未实现/已注释/无回传"的部分,本文明确标注,作为新平台需要补齐或决策的事项。
目录
- 总体架构
- 核心:JS 通信桥协议(WebViewJavascriptBridge)
- 应用启动流程
- 配置体系
- 资源(大厅/子游戏)管理
- H5 数据注入:app_data.js
- WebView 容器能力要求
- 接口契约一:H5 → 原生(入站 Handler 全集)
- 接口契约二:原生 → H5(出站 Handler 全集)
- 原生能力专题
- 子游戏跳转与通用网页容器
- 数据结构汇总
- 关键常量与第三方账号
- HarmonyOS 适配检查清单与待决策项
1. 总体架构
整个 App 本质上是一个多 WebView 容器 + 资源管理器,所有业务逻辑(大厅、棋牌子游戏)都是 H5,原生只提供"启动引导 + 资源下载解压 + 设备能力桥接"。
┌──────────────────────────────────────────────────────────────┐
│ 原生容器(可在任意平台重写) │
│ │
│ [启动引导页] ──► 读本地配置 ──► 请求远程配置 ──► 下载/解压资源 │
│ │ │ │
│ └──────────────► 注入 app_data.js ─────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ WebView 容器(大厅 / 子游戏) │ │
│ │ 加载 file://.../index.html?Launchtype=X │ │
│ │ │ │
│ │ ◄──── JS 通信桥(WebViewJavascriptBridge) ────► │ │
│ │ H5 ⇄ 原生:登录/分享/支付/定位/音频/震动… │ │
│ └────────────────────────────────────────────────────┘ │
│ │ │
│ 设备能力:微信/QQ/抖音分享、微信支付登录、高德定位、 │
│ 录音、音效、摇一摇、扫码、相机、剪贴板、震动… │
└──────────────────────────────────────────────────────────────┘
1.1 容器角色划分(现有 Android 实现)
| 角色 | 现有 Android 类(仅作来源标注,新平台无需同名) | 说明 |
|---|---|---|
| 启动引导页 | weclomeactivity1(Launcher,强制横屏) |
读配置、请求远程配置、下载解压资源、注入 app_data.js,完成后跳大厅 |
| 大厅容器 | webviewActivity |
加载大厅 H5(.../gamehall/index.html) |
| 子游戏/内置网页容器 | openwebActivity1 |
由大厅通过桥接口 OpenurlTitleData 打开任意 H5 url |
| 微信回调容器 | NewwebviewActivity |
与大厅容器接口集几乎完全相同,承担微信 scheme 回调 |
重要说明:
webviewActivity与NewwebviewActivity注册的桥接口(44 个入站 handler)名称、参数结构、回调名几乎完全一致,差异仅 3 处(见 §8.x 标注)。新平台只需实现一套统一的桥接口契约即可同时覆盖大厅与子游戏容器。本文档给出的是这套统一契约。
2. 核心:JS 通信桥协议(WebViewJavascriptBridge)
这是整个适配的重中之重。H5 完全依赖此协议与原生通信,不可更改。新平台必须 1:1 实现此协议,包括其 URL scheme、消息格式、JS 全局对象与注入时机。 来源:
com/tagmae/jsbridge/(BridgeWebView、BridgeWebViewClient、BridgeUtil、Message)。本协议是开源库 lzyzsd/JsBridge 的实现。
2.1 协议总览
⚠️ 重要范围说明:本章描述的
WebViewJavascriptBridge协议适用于大厅容器与子游戏容器(基于BridgeWebView,即webviewActivity/NewwebviewActivity)。 另有一个独立的通用网页容器openwebActivity1(由桥接口OpenurlTitleData打开,用于活动页/收银台/客服等"打开网页"场景),它不使用本协议,而是用传统的"JS 接口对象注入(@JavascriptInterface,对象名settings)+javascript:直接函数调用"。该容器的接口契约见 §11.3,新平台两套机制都要实现。
在基于 BridgeWebView 的两个主容器里,业务通信不使用平台的"JS 接口注入"机制(如 Android @JavascriptInterface、HarmonyOS javaScriptProxy)作为通道——其中所有 addJavascriptInterface(new settings(), "settings") 均已注释失效,仅保留的崩溃监控用途与业务无关。这两个主容器的业务通信 100% 走下述 URL scheme 拦截协议。
另:源码中存在
ShareJavascriptInterface(注入名NativeShare,方法shareToQQ/shareToDouYin),但其注入入口ShareActivityPatch在全工程无任何引用,是死代码,H5 无法依赖,新平台无需实现。
通信靠两条单向通道拼成双向:
- 原生 → H5:原生执行 JS:
WebViewJavascriptBridge._handleMessageFromNative('<消息JSON>')。 - H5 → 原生:H5 改变一个隐藏 iframe 的
src为yy://...触发导航;原生在"资源加载拦截/URL 跳转拦截"里识别yy://前缀并阻断真实导航,转而处理消息。
2.2 URL scheme 约定(必须原样实现)
来源:BridgeUtil.java
| 常量 | 值 | 含义 |
|---|---|---|
| 协议前缀 | yy:// |
H5 发起的所有桥调用 |
| 返回数据前缀 | yy://return/ |
H5 对原生调用的回执 / 取队列回执 |
| 取消息队列 | yy://return/_fetchQueue/ |
原生通知 H5"把待发消息队列交出来" |
原生侧 URL 拦截逻辑(必须复刻):
拦截到 url(需先 URLDecode):
if url 以 "yy://return/" 开头:
→ 解析出 functionName 与 data,执行对应回调,阻断导航
else if url 以 "yy://" 开头:
→ 调用 _fetchQueue()(见下),阻断导航
else:
→ 正常导航
2.3 原生 → H5 的两条 JS 调用(必须原样实现)
来源:BridgeUtil.java
- 下发单条消息:
javascript:WebViewJavascriptBridge._handleMessageFromNative('<JSON字符串>'); - 抽取 H5 待发队列:
javascript:WebViewJavascriptBridge._fetchQueue();- 该调用本身被当作一次"原生→H5"调用,其回执由 H5 通过
yy://return/_fetchQueue/<JSON数组>送回原生。
- 该调用本身被当作一次"原生→H5"调用,其回执由 H5 通过
2.4 消息体(Message)JSON 结构
来源:Message.java。原生与 H5 之间所有消息都序列化为如下结构(字段按需出现):
| 字段 | 类型 | 含义 |
|---|---|---|
handlerName |
String | 目标 handler 名(指定调用哪个已注册的 handler;无则走 defaultHandler) |
data |
String | 业务数据载荷(注意:可能是裸字符串,也可能是 JSON 字符串,逐接口而定) |
callbackId |
String | 本条消息期望对端回执时带回的 id(发起方生成) |
responseId |
String | 回执消息:对应此前收到的 callbackId |
responseData |
String | 回执消息的返回数据载荷 |
原生侧生成 callbackId 的格式:JAVA_CB_<自增id>_<时间戳>(来源 BridgeWebView.doSend)。新平台可用任意唯一字符串格式,H5 不关心其内部格式,只负责原样回带。
2.5 JS 端 API(H5 使用,原生必须保证这些 API 存在且行为一致)
H5 通过全局对象 window.WebViewJavascriptBridge 调用以下方法(由注入的 WebViewJavascriptBridge.js 提供):
| JS API | 作用 |
|---|---|
registerHandler(handlerName, function(data, responseCallback){...}) |
H5 注册一个 handler,供原生调用(即接收"原生→H5"消息)。responseCallback(retData) 用于把结果回给原生。 |
callHandler(handlerName, data, function(responseData){...}) |
H5 调用原生注册的 handler,responseData 回调接收原生的同步返回。 |
init(function(message, responseCallback){...}) |
设置默认 handler(接收未指定 handlerName 的消息)。 |
send(data, responseCallback) |
向原生默认 handler 发消息。 |
H5 监听桥就绪事件后才开始调用(典型写法,原生需保证此事件/回调时序):
function connectBridge(cb){
if (window.WebViewJavascriptBridge) { cb(WebViewJavascriptBridge); }
else { document.addEventListener('WebViewJavascriptBridgeReady',
function(){ cb(WebViewJavascriptBridge); }, false); }
}
新平台需提供与 lzyzsd/JsBridge 同名同行为的
WebViewJavascriptBridge.js,确保 H5 中已有的registerHandler/callHandler调用全部生效。建议直接复用该库的WebViewJavascriptBridge.js原文件。
2.6 JS 注入时机(关键时序)
来源:BridgeWebViewClient.onPageFinished
- 在每个页面加载完成(onPageFinished)时,原生把
WebViewJavascriptBridge.js内容注入页面(作为 JS 执行)。 - 注入后,原生把"启动消息队列"(页面加载完成前积压的待发消息)逐条
_handleMessageFromNative下发。
新平台实现要点:
- 监听页面加载完成事件 → 注入桥 JS。
- 维护"启动前积压消息队列":页面就绪前原生若调用 H5 handler,先入队,页面就绪后补发。
- 注入的 JS 解析时会去除以
//开头的注释行(BridgeUtil.assetFile2Str),新平台若直接读取 js 文件注入,需保持等价(或直接内联完整 js)。
2.7 一次完整调用的数据流示例
H5 调用原生(带返回) —— 例:H5 获取系统时间
H5: bridge.callHandler('getTime', '', function(ret){ /* ret = "1700000000000" */ });
└─ 桥生成 message {handlerName:'getTime', data:'', callbackId:'cb_1'}
入队 → 触发 iframe.src='yy://__queue__'
原生: 拦截 yy:// → _fetchQueue() 取出该 message
→ 找到名为 'getTime' 的 handler 执行 → responseCallback("1700000000000")
→ 原生把 {responseId:'cb_1', responseData:'1700000000000'} 经
_handleMessageFromNative 下发
H5: 桥按 responseId 找到 cb_1 回调并执行
原生调用 H5(推送) —— 例:定位结果推送
原生: callHandler('getlocationinfo', '<MaplocationInfo的JSON>', null)
→ message {handlerName:'getlocationinfo', data:'<json>'} 经
_handleMessageFromNative 下发
H5: 桥查到 H5 用 registerHandler('getlocationinfo', ...) 注册的处理函数并执行
3. 应用启动流程
来源:
weclomeactivity1.java、initwebviewutil、GameupdateUtil.java、webviewActivity.initwebview。 下述为行为时序,新平台按此顺序复刻即可,内部实现自由。
3.1 启动总时序
启动引导页 onCreate
│ 全屏、强制横屏、保持屏幕常亮
▼
读取本地配置(资源目录名编码,见 §4.1)
│ initfile = "gamehall"(gamestart 配置)
│ filestart = "FtJf...ziK"(gamedir 配置)
▼
申请运行时权限(存储 / 电话状态 / 定位)
▼
拼接远程配置 URL(见 §4.3)
│ configUrl = "http://" + (gameconfig 配置去'-'换'/') + ".txt"
▼
首次安装?
├─ 是:把内置预置包(gamehall)拷贝到内部存储并解压
└─ 否:比较内置 version.xml 与已解压 version.xml 版本,必要时重新拷贝
▼
检测网络 → 请求远程配置(HTTP GET,禁缓存,URL 追加 "?a=<时间戳>")
▼
解析远程配置(JSON)
├─ 2.0 格式(含 gamelist):拉取代理二级配置 + 游戏二级配置 → 分层版本计算
└─ 1.0 格式:单文件逐层匹配
▼
版本决策:远程 game_version > 本地 version.xml 的 version ?
├─ 需要更新:下载 game_download 指向的 zip → 删旧目录 → 解压到资源目录
└─ 无需更新:直接用本地资源
▼
(如有)APK 自升级:app_version 高于本地 appversion → 下载 APK 安装
▼
注入 app_data.js(把配置写进大厅资源目录,见 §6)
▼
跳转大厅容器(不带 Intent extra;配置经 app_data.js 与桥接口获取)
▼
大厅容器加载 file://.../gamehall/index.html?Launchtype=0
3.2 阻断式提示
远程配置 JSON 顶层若含非空 showmessage 字段,启动流程会弹窗提示并阻断(用于公告/停服)。配置内容长度过短(< 30 字符)时视为错误文案,直接弹窗。新平台需复刻此"全局公告阻断"行为。
4. 配置体系
4.1 本地配置编码机制(资源目录名编码)
来源:
getAllFilename(String name)(weclomeactivity1/webviewActivity均有同名实现)。
现有 Android 把每个配置项做成一个资源目录,目录下放一个以"配置值"命名的子文件夹(外加一个占位文件 BoolTest.java 需被跳过)。读取逻辑:
列出 assets/<配置名>/ 下的条目
跳过名为 "BoolTest.java" 的占位文件
剩下那个"子文件夹的名字"即为配置值
返回该名字(找不到则为空字符串)
HarmonyOS 适配建议:这种"用目录名编码配置"的做法是历史包袱。新平台推荐改为正规的键值配置文件(如随包内置一个 JSON),只要能提供下表中的同名配置值即可,H5 完全无感知。
4.2 配置项清单(本仓库实测值)
| 配置键 | 本仓库实际值 | 含义 / 用途 |
|---|---|---|
agent |
veRa0qrBf0df2K1G4de2tgfmVxB2jxpv |
代理商 ID(远程配置分层匹配 key) |
channel |
FtJf073aa0d6rI1xD8J1Y42fINTm0ziK |
渠道 ID(分层匹配 key) |
gamedir |
FtJf073aa0d6rI1xD8J1Y42fINTm0ziK |
资源解压父目录名 |
gamestart |
gamehall |
资源解压后的游戏目录名(大厅入口所在目录) |
appversion |
49 |
当前 App 版本号(数字,与远程 app_version 比较决定是否升级 APK) |
market |
3 |
市场 ID(分层匹配 key;也经桥 getmarketname 暴露给 H5) |
gameid |
(空,仅占位) | 游戏 ID(空时回退用 version.xml 中的 game id) |
weburl |
(空) | 大厅 H5 远程地址;空 → 本地 file:// 加载(本仓库走本地) |
gameconfig |
tsgames.daoqi88.cn-config_test-update_jsonv2_test |
远程配置地址(-→/ 后拼 .txt) |
other |
(空) | 业务自定义值,经桥 getOther/getothername 暴露给 H5 |
tuiguang |
(目录不存在 → 空) | 推广/邀请码,写入 app_data.js 的 app_invitationcode |
servertype |
(空,无代码读取) | 历史预留,启动流程不使用,可不实现 |
gameserver |
(空,无代码读取) | 历史预留,启动流程不使用,可不实现 |
4.3 远程配置请求
URL 拼装(来源 weclomeactivity1.init):
gameconfig 值 = "tsgames.daoqi88.cn-config_test-update_jsonv2_test"
→ 把 '-' 替换为 '/' = "tsgames.daoqi88.cn/config_test/update_jsonv2_test"
→ configUrl = "http://" + 上一步 + ".txt"
= "http://tsgames.daoqi88.cn/config_test/update_jsonv2_test.txt"
请求时再追加防缓存参数: configUrl + "?a=" + 当前毫秒时间戳
请求方式:HTTP GET,强制不走缓存
返回体:一个 .txt 文件,内容为 JSON(解析前用 JSON 解析校验;长度 < 30 视为错误提示文案直接弹窗)。存在两套并存格式:
2.0 配置格式(主路径,含 gamelist 字段时)
{
"showmessage": "", // 非空 → 弹窗阻断(公告/停服)
"agentlist": [
{
"agentid": "", "agentname": "",
"app_version": "", "app_download": "", "app_size": "",
"game_version": "", "game_download": "", "game_size": "",
"url": "", // 指向"代理专属二级配置"地址,非空则二次请求
"channellist": [ /* 渠道层,结构含 marketlist */ ]
}
],
"gamelist": [
{
"gameid": "", "url": "", // url 指向"游戏专属二级配置",非空则二次请求
"agentlist": [ /* 内含 channellist → marketlist */ ]
}
]
}
解析流程:
- 用本机
agent值在agentlist命中项;若其url非空 → 二次请求拉代理二级配置。 - 用本机
gameid值在gamelist命中项;若其url非空 → 二次请求拉游戏二级配置。 - 两个二级配置都到齐后,做最终版本决策(见 §4.4)。
1.0 配置格式(兼容老格式,无 gamelist 时)
单文件内嵌全部层级,直接在一个循环里逐层匹配,无二次请求。
4.4 分层覆盖逻辑(agent → channel → market → game)
此分层覆盖逻辑真实存在,来源
GameupdateUtil.agentUtil(已核实)。匹配 key 为{agentid, gameid, channelid, marketid}(来自本地配置)。
- 代理配置树:
agentid 命中→ 遍历channellist(channelid 命中) → 遍历marketlist(marketid 命中,可设 app 升级) → 遍历该市场gamelist(gameid 命中,设 app/game 升级)。越深层越后赋值,覆盖前层。 - 游戏配置树:
gameid 命中→agentlist(agentid) →channellist(channelid) →marketlist(marketid,可设 app+game 升级)。同样后层覆盖前层。 - 最终合并:app 升级与 game 升级各自取"代理树与游戏树中 version 更高"者的下载地址,再分别与本地版本比较。
每层可携带的可覆盖字段:app_version、app_download、app_size、game_version、game_download、game_size、url、showmessage。
与旧参考文档的差异提示:旧版
TSGame_应用启动流程详解.md中给出的配置 JSON(data.agentlist[].channellist[].marketlist[]、config_download、configVersion等字段)是示意性质,与真实字段名不完全一致。请以本节真实字段(agentlist/gamelist两棵树并存、二级url二次请求、game_download/game_version等)为准。
5. 资源(大厅/子游戏)管理
5.1 真实文件系统路径
来源
initwebviewutil.getdate。
内部存储根 = <App内部files目录> // 例如 Android: /data/data/<包名>/files
父目录(upurlpath) = <files>/tsgames/<包名>/<启动毫秒时间戳>
解压根(urlpath) = <父目录>/<gamedir值> // = .../<时间戳>/FtJf073aa0d6rI1xD8J1Y42fINTm0ziK
游戏内容目录 = <解压根>/<gamestart值> // = .../FtJf...ziK/gamehall
大厅入口 = <解压根>/gamehall/index.html
两个路径以键值对持久化(供容器读取):urlpath(解压根)、upurlpath(父目录)。
注意:解压根含启动时间戳,意味着每次全新解压会落到新目录。新平台可沿用或简化为固定目录,对 H5 无影响(H5 只看到自己被以
file://加载)。
5.2 内置预置包(首次安装)
- 现有工程随包内置
gamehall目录,首启时整体拷贝到解压根,并对其中的.zip/.so解压,然后删除压缩包。 - 本仓库内置包
gamehall_42_0527.zip仅 553 字节,里面只有一个version.xml,是占位/演示包——真正可运行的大厅 H5(index.html 等)由远程 zip 下载提供。新平台需注意:不能假设内置包里有完整大厅页面。
5.3 版本文件 version.xml
资源目录与内置包内均含
version.xml,结构如下(实测):
<game>
<agent id="..." name="天盛网络"/>
<game id="..." name="友乐游戏"/>
<channel id="..." name="友乐互动游戏"/>
<version value="42" name="1.42"/>
</game>
version value为整数,用于与远程配置game_version比较(远程更高则下载更新)。agent/game/channel的 id 作为资源自带的归属标识。
5.4 zip 下载与解压
下载 URL = 远程配置 game_download 字段值 + "?a=<时间戳>"
下载到 = <App外部files目录>/dowlod_zip/<时间戳>Projects.zip (目录名拼写即代码原样 "dowlod_zip")
解压步骤:
1. 删除旧的 <解压根>/gamehall 内容
2. 解压 zip 到 <解压根>/ (zip 内顶层即含 gamehall/...)
3. 删除 zip 文件
4. 进入"注入 app_data.js → 跳大厅"收尾
5.5 APK 自升级
- 远程
app_version高于本地appversion时,下载app_download指向的安装包并触发系统安装。 - HarmonyOS 适配:改为对应平台的应用更新方式即可,与 H5 契约无关。
6. H5 数据注入:app_data.js
来源
weclomeactivity1.inith5data。这是把原生配置传给 H5 的关键机制之一,H5 直接读取这些全局变量,必须复刻。
跳转大厅前,原生在大厅资源目录生成/改写 app_data.js:
路径:<解压根>/gamehall/app_data.js
文件内容为一组全局 JS 变量声明(H5 直接引用),字段如下:
| 全局变量 | 来源 | 含义 |
|---|---|---|
app_version |
version.xml 的 version | 资源版本号 |
app_gameconfig |
gameconfig 配置 |
远程配置地址标识 |
app_gamedir |
gamedir 配置 |
资源父目录名 |
app_gamestart |
gamestart 配置 |
游戏目录名(gamehall) |
app_agent |
agent 配置 |
代理商 ID |
app_appversion |
appversion 配置 |
App 版本号 |
app_market |
market 配置 |
市场 ID |
app_channel |
channel 配置 |
渠道 ID |
app_invitationcode |
tuiguang 配置 |
推广/邀请码 |
app_Launchtype |
固定 '0'(大厅) |
启动类型 |
app_gamename |
资源/配置 | 游戏名 |
app_getwifisignalLevel |
运行时 | WiFi 信号等级初值 |
新平台只需在加载大厅页面前,保证大厅目录下存在等价的
app_data.js(同名全局变量、同含义取值)。内部如何生成文件不限。
7. WebView 容器能力要求
来源
webviewActivity.initWebViewSettings/NewwebviewActivity.initWebViewSettings。下列为 H5 正常运行所需的能力要求,新平台用等价配置满足即可。
| 能力 | 要求 | 说明 |
|---|---|---|
| JavaScript | 必须启用 | — |
| DOM Storage / 本地数据库 | 必须启用 | H5 用 localStorage 等持久化 |
| 本地文件访问 | 必须允许 | 加载 file:// 本地页面 |
file:// 跨源访问 |
必须允许(universal access from file URLs) | H5 从 file 页面请求本地/远程资源 |
| 混合内容(http+https) | 允许(always allow) | 本地页面内嵌 http 资源 |
| 明文 HTTP 流量 | 允许 | 远程配置/资源走 http |
| 缓存 | 不使用缓存(每次走网络/本地最新) | — |
| 定位 | 启用(H5 geolocation + 桥定位) | — |
| 缩放 | 关闭(禁缩放、禁内置缩放控件、禁 wide viewport) | 固定布局游戏 |
| 多窗口 | 关闭 | — |
| UserAgent | 未自定义(用平台默认) | H5 不依赖特定 UA |
| Cookie | 未特殊配置 | — |
| 远程调试 | 启用(开发期) | — |
| 屏幕方向 | 默认横屏,不跟随设备传感器自动旋转 | 横屏项目;H5 仍可经方向接口显式切换(见下) |
🔴 屏幕方向约束(横屏项目):本项目为横屏项目,应用默认横屏、不跟随设备重力传感器自动旋转。 但遵守 H5 零改动铁律:H5 经方向接口发起的显式切换行为完全不变,与原 Android 一致——
orientationhandler(§8.4):"1"→ 横屏,非"1"→ 竖屏(原生仍真实切竖屏,对齐 AndroidsetRequestedOrientation);- 子游戏
SwitchOverGameData的webtype(§11.1):"3"横屏 /"2"竖屏;- 通用网页
OpenurlTitleData的orientation(§11.2):"1"竖屏 / 其他 横屏。即"不支持竖屏"指 默认横屏、不随传感器自动转屏,不是禁止 H5 控制方向。原生以"默认横屏 + 按 H5 请求动态切换方向"落地(见框架文档 §7.4),从而既是横屏项目,又不破坏 H5 零改动。
容器还需提供:
- 本机 HTTP 服务:用于"截图分享上传"。容器启动一个本机 HTTP server,把地址(
http://<本机IP>:<端口>/testurl)通过桥setPostUrl推给 H5(见 §9)。新平台需提供等价的本机上传端点能力,否则截图分享链路不通。
8. 接口契约一:H5 → 原生(入站 Handler 全集)
H5 通过
bridge.callHandler('<名称>', '<data>', responseCallback)调用。 data 列标注是裸字符串还是 JSON 字符串;同步返回列标注是否通过responseCallback同步返回(裸字符串/JSON);多数能力的结果是异步通过 §9 的出站 handler 推回。 来源:webviewActivity.initwebjh(行 2185–3012)/NewwebviewActivity.initwebjh(行 2164–3129)。两容器一致,差异在表后标注。
8.1 账号 / 社交
| Handler | data | 同步返回 | 异步回传 | 功能 |
|---|---|---|---|---|
accreditlogin |
裸字符串("1"=QQ,其他=微信;QQ 实为空实现) |
无 | sharelogin |
触发授权登录(实际仅微信) |
friendsSharetypeUrlToptitleDescript |
JSON(sharetypeBean,见 §12) |
无 | sharesuccess(仅微信有结果) |
分享(微信/QQ/抖音) |
getphoto |
裸字符串(图片下载 JSON 数组) | 无 | getphoto |
批量下载图片/头像到本地 |
8.2 支付
| Handler | data | 同步返回 | 异步回传 | 功能 |
|---|---|---|---|---|
paybrowser |
裸字符串(收银台 URL) | 无 | 无(H5 收银台页自理) | 浏览器方式支付(当前生效) |
getGameplay |
JSON(price/body/typeplay/type/user) |
无 | PayuserPaytypePaystate |
App 内微信支付(仅旧版 webviewActivity 生效;NewwebviewActivity 已注释) |
8.3 设备 / 系统信息
| Handler | data | 同步返回 | 异步回传 | 功能 |
|---|---|---|---|---|
getTime |
忽略 | 裸字符串(毫秒时间戳) | — | 获取系统时间 |
getphonestate |
忽略 | 裸字符串 int(0 挂断/1 接起/2…) | — | 获取电话状态 |
getbattery |
忽略 | 无 | getBattery |
主动获取电量 |
getwifiLevel |
忽略 | 无 | getwifiLevel |
主动获取 WiFi 信号 |
getnetwork |
忽略 | 裸字符串(1无网/2WiFi/3移动) |
— | 主动获取网络状态 |
getcompareCode |
忽略 | 裸字符串 int(1=本地版本>网络版本,0=否) | — | App 版本比较结果 |
getphoneInfo |
忽略 | 无 | getphoneinfo |
获取手机配置信息(型号/IMEI 等) |
getmarketname |
忽略 | 裸字符串(market 值) | — | 获取市场 ID |
getothername |
裸字符串(配置名) | 裸字符串(该配置值) | — | 获取任意本地配置值 |
getOther |
忽略 | 裸字符串(other 值) | — | 获取 other 配置值 |
8.4 交互 / 反馈
| Handler | data | 同步返回 | 异步回传 | 功能 |
|---|---|---|---|---|
orientation |
裸字符串("1"横屏,其他竖屏) |
无 | — | 切换屏幕方向 |
vibrator |
裸字符串 long(毫秒) | 无 | — | 震动 |
repeatvibrator |
裸字符串 int(-1否/1重复) |
无 | — | 重复震动 |
canclevibrator |
忽略 | 无 | — | 取消震动 |
gameCopytext |
裸字符串(文本) | 无 | — | 写入剪贴板 |
gamepastetext |
忽略 | 裸字符串(剪贴板内容) | — | 读取剪贴板 |
notification |
裸字符串 | 无 | — | 发送通知(空实现,未落地) |
8.5 摇一摇
| Handler | data | 异步回传 | 功能 |
|---|---|---|---|
startshake |
忽略 | shakeEnd |
开始监听摇一摇 |
SwitchShake |
裸字符串("1"开声音震动/其他关) |
— | 摇一摇声音开关 |
stopshake |
忽略 | — | 停止监听 |
8.6 定位
| Handler | data | 同步返回 | 异步回传 | 功能 |
|---|---|---|---|---|
startlocation |
裸字符串("1"连续/其他单次) |
无 | getlocationinfo |
开启定位 |
getlocationinfo |
忽略 | JSON(MaplocationInfo;未就绪返回错误码 JSON) |
— | 主动取最近一次定位 |
8.7 音频
| Handler | data | 异步回传 | 功能 |
|---|---|---|---|
prepareaudio |
忽略 | — | 准备/开始录音(长按) |
mediaTypeAudio |
JSON(audiourl/type/user) |
gameui_play_voice / gameui_stop_voice |
播放语音消息 |
srcIsloop |
JSON(src/isloop) |
无 | 播放游戏音效/背景乐 |
voicePlaying |
裸字符串("1"开/其他静音) |
— | 语音播放总开关 |
getaudiourl 录音结果 |
(由 prepareaudio 触发) |
getaudiourl |
录音上传后回传地址 |
8.8 扫码 / 相机 / 浏览器 / 网页
| Handler | data | 同步返回 | 异步回传 | 功能 |
|---|---|---|---|---|
opensaoma |
忽略 | 无 | getsaomaData |
打开扫一扫 |
opencamera |
忽略 | 无 | getcameraaAddress |
打开相机拍照 |
browser |
裸字符串(URL) | 无 | — | 系统/QQ 浏览器打开链接 |
OpenurlTitleData |
JSON(url/title/data) |
无 | getWebdata |
打开内置网页容器(子游戏跳转,见 §11) |
openApplyDownloadpath |
JSON(packagename/downloadpath) |
无 | — | 按包名启动 App,失败则浏览器打开下载地址 |
8.9 子游戏切换 / 房间(音视频)
| Handler | data | 同步返回 | 异步回传 | 功能 |
|---|---|---|---|---|
SwitchOverGameData |
JSON(webtype/Gamedirectory/gamedownloadurl/data) |
无 | — | 切换子游戏(容器内切换) |
getGameinstall |
裸字符串(目录名) | 裸字符串(1已装/0未装) |
— | 判断子游戏资源是否已就绪 |
createRoom |
裸字符串(videoinfobean JSON) |
无 | — | 加入/创建音视频房间(声网) |
exitRoom |
裸字符串 | 无 | — | 退出房间 |
getVideoinfo |
裸字符串(Othervideoinfo JSON) |
无 | getVideoinfo |
请求/绑定远端视频窗口 |
DragViewvideoIsshow |
裸字符串("1"显示/其他隐藏) |
无 | — | 视频悬浮框显隐 |
8.10 退出 / 返回
| Handler | data | 异步回传 | 功能 | 备注 |
|---|---|---|---|---|
finsh |
忽略 | — | 退出游戏 | 名字即代码原样(拼写如此) |
backgameData |
裸字符串(data) | — | 子游戏带数据返回大厅 | 仅 NewwebviewActivity 有;以结果码 101 回传给上层容器 |
getAddressBook |
忽略 | (getAddressbook 已注释) |
获取通讯录 | 未实现 |
8.11 两容器差异小结
| 接口 | webviewActivity(大厅) |
NewwebviewActivity(子游戏/微信回调) |
|---|---|---|
getGameplay(App 内微信支付) |
✅ 生效 | ❌ 已注释(改用 paybrowser) |
backgameData(带数据返回) |
❌ 无 | ✅ 有 |
getlocationinfo 错误码 |
未就绪返回裸 null |
返回结构化错误码 JSON(-1 未就绪/-2 权限拒绝) |
| 分享内部分流 | 直连微信 SDK 多分支 | 按 sharefriend 分流到统一分享面板 |
| 其余 ~40 个 handler | 完全一致 | 完全一致 |
适配结论:实现统一一套入站 handler,并对差异项采用更完整的一侧(如
getlocationinfo用结构化错误码、同时支持paybrowser与backgameData)即可兼容两个容器。
9. 接口契约二:原生 → H5(出站 Handler 全集)
原生通过
callHandler('<名称>', '<data>', null)调用;H5 必须用registerHandler('<名称>', ...)注册才能收到。 来源:两容器内callHandler调用点。
| Handler | data | 调用时机 |
|---|---|---|
appservice |
裸字符串("1"前台/"2"后台) |
页面首次加载到 100%、以及前后台切换(resume/pause/stop、息屏/解锁) |
setPostUrl |
裸字符串(http://<本机IP>:<端口>/testurl) |
页面加载完成时,下发截图上传地址 |
getWebdata |
裸字符串(网页回传 text / Intent 透传 data) | 页面首次加载完成;或内置网页关闭回传(结果码 101) |
getphoto |
JSON 数组([{pid, photourl}]) |
图片/头像下载完成 |
sharelogin |
JSON(openid/headimgurl/nickname/sex/city/province/unionid) |
微信授权登录成功后 |
sharesuccess |
JSON({success:int, type:int},success 2 成功/3 取消) |
分享结果回调(仅微信完整) |
shakeEnd |
空字符串 "" |
摇一摇触发后约 1 秒 |
getBattery |
裸字符串 float(0~1) | H5 主动取电量时;或电量变化广播 |
getwifiLevel |
JSON({ssidname:String, signalLevel:int(0~4)}) |
H5 主动取时;或 WiFi 变化广播 |
getnetwork |
裸字符串 int(1断网/2WiFi/3移动) |
网络状态变化广播 |
getaudiourl |
JSON({audiourl:String, time:float};旧容器 webviewActivity 录音成功时额外携带 filepath:String,值与 audiourl 相同;取消时 audiourl="" time=0) |
录音上传完成 / 录音取消 |
gameui_play_voice |
裸字符串(user 透传) |
语音开始播放 |
gameui_stop_voice |
裸字符串(user 透传) |
语音播放完成 / 被打断 |
getphoneinfo |
JSON(phoneInfoBean,见 §12) |
H5 调 getphoneInfo 后 |
getVideoinfo |
裸字符串 int(远端 uid) | 音视频房间其他用户加入时 |
PayuserPaytypePaystate |
JSON({user, state, typeplay, type, data},state 1 成功/0 取消) |
App 内微信支付结果(仅旧版容器) |
getlocationinfo |
JSON(MaplocationInfo;或错误码 JSON) |
定位成功(单次 1 次/连续每 5s);或权限被拒 |
phonestate |
裸字符串 int(来电状态) | 来电状态广播 |
getsaomaData |
裸字符串(扫码结果) | 扫码返回 |
getcameraaAddress |
裸字符串(照片路径) | 拍照返回 |
名称陷阱:
NewwebviewActivity中有一处出站调用名为backgameData-(末尾带连字符,data 为空字符串),用于返回键确认对话框流程;与入站的backgameData(无连字符)是两个不同名字。适配时按代码原样区分。
10. 原生能力专题
本节给出各设备能力的"H5 触发 → 入参 → 回传时机/结构",原生内部如何对接第三方 SDK 不限。
10.1 分享(微信 / QQ / 抖音)
- 触发:
friendsSharetypeUrlToptitleDescript,入参sharetypeBean(§12)。sharefriend=="2"→ 微信朋友圈直发;=="1"→ 弹分享面板由用户选目标(微信好友/QQ/抖音)。type:"1"网页/文本,"2"Canvas 截图(原生实时截当前 WebView 的 canvas 转 base64),"3"图片链接,抖音另有"4"视频。
- 回传:仅微信完整 →
sharesuccess({success,type},2 成功/3 取消)。 - 现状/待补:QQ、抖音当前无结果回传(QQ 回调被注释,抖音仅 Toast / 走外部 App scheme)。若 H5 依赖分享回调,新平台需为三端补齐统一
sharesuccess回传。
10.2 微信登录
- 触发:
accreditlogin(非"1"即微信),scope=snsapi_userinfo。 - 回传:
sharelogin,回传用户资料(openid/unionid/nickname/headimgurl/sex/city/province),非 code。 - 安全提示:现有实现用客户端硬编码 AppSecret 换 token(见 §13),新平台建议改为回传 code、由服务端换取。
10.3 支付
- 当前生效:
paybrowser(data 为收银台 URL,原生开浏览器,无回传,H5 收银台自理)。 - 旧版 App 内支付:
getGameplay→ 微信 SDK →PayuserPaytypePaystate回传结果(仅旧版容器)。PayReq字段:appId/partnerId/prepayId/packageValue("Sign=WXPay")/nonceStr/timeStamp/sign(MD5大写)。
10.4 抖音 / 快手登录
- 未实现:现有
sgapi实为"闲聊(Xianliao)SDK"且整文件注释,无桥接入。新平台如需,须全新对接抖音开放平台/快手 SDK,建议回传 code 给 H5。
10.5 截图 / Canvas
- 截图当前耦合在分享流程内部,无独立 handler。原生注入 JS 调 H5
canvas.toDataURL(默认 image/jpeg 720×405;指定 id 则 png),失败回退原生绘制;结果直接交分享,不回传 H5。 - 待补建议:若 H5 需主动截图,新增 handler(如
getCanvasBase64,入参 canvasId/格式/尺寸,返回纯 base64 或 dataURL)。
10.6 音频
- 远程语音消息:
mediaTypeAudio播放 →gameui_play_voice/gameui_stop_voice回传(透传user)。 - 游戏音效/背景乐:
srcIsloop,src为 wav 文件名(非 URL),路径<解压根>/<game>/assets/wav/<src>;isloop:0播一次 />0循环 /<0停止。无回传。 - 静音总开关:
voicePlaying。 - 录音:
prepareaudio录音 → 上传 →getaudiourl回传{audiourl,time}。
10.7 摇一摇
startshake开始 → 触发后约 1 秒callHandler('shakeEnd','')→ 自动重新监听。SwitchShake控声音,stopshake停止。- 灵敏度等参数原生内部决定(现有实现加速度阈值约 3500)。
10.8 定位(高德)
startlocation("1"连续/5s 间隔,其他单次)→getlocationinfo推MaplocationInfo。getlocationinfo也可同步主动取(一名两用)。- 错误码约定:
0成功 / 高德原始码 /-1未就绪 /-2权限被拒。 - 新平台用本平台定位服务实现,只要回传
MaplocationInfo同结构同字段即可。
11. 子游戏跳转与通用网页容器
H5 从大厅进入"另一个页面"有两条独立路径,机制完全不同,新平台都要实现:
- 路径 A(容器内切换子游戏):
SwitchOverGameData→ 在同一个 BridgeWebView 容器内重载到另一个游戏目录,仍走 §2 Bridge 协议。- 路径 B(打开通用网页):
OpenurlTitleData→ 打开独立的通用网页容器openwebActivity1,该容器用 §11.3 的另一套接口机制(settings对象注入 +javascript:直调)。
11.1 路径 A:容器内切换子游戏(SwitchOverGameData)
来源:
webviewActivity/NewwebviewActivity的SwitchOverGameData→initgame()。
- H5 调用:
bridge.callHandler('SwitchOverGameData', JSON.stringify({webtype, Gamedirectory, gamedownloadurl, data}))webtype:"2"竖屏 /"3"横屏Gamedirectory:目标游戏目录名gamedownloadurl:游戏 id(用于判断/下载)data:交换数据
- 原生在当前 BridgeWebView 容器内重载到
file://<解压根>/<Gamedirectory>/index.html?Launchtype=1(必要时先下载解压该游戏 zip),桥协议与全部 handler 不变,对 H5 透明。
关键结论:本路径下子游戏 H5 通常已包含在 §5 下载解压的整包内;原生按 Gamedirectory 切换目录加载,仍复用同一套 Bridge 接口。
11.2 路径 B:打开通用网页(OpenurlTitleData)
来源:
webviewActivity/NewwebviewActivity的OpenurlTitleData→ 打开openwebActivity1。
大厅/游戏 H5 拼好目标地址(本地 file:// 或远程 http://)
▼
bridge.callHandler('OpenurlTitleData', JSON.stringify({url, title, data}))
▼
原生打开通用网页容器 openwebActivity1,加载该 url(Intent extra:url/title/data/orientation)
│ orientation:"1"=竖屏,其他=横屏
▼
页面加载到 100% → 原生用【javascript: 直调】getWebdata('<data>') 把交互数据交给页面
▼
页面内 H5 调 settings.backgameData('<data>')(或返回键确认)→ 原生 setResult(101, data) 退出
▼
回到上层 Bridge 容器 → 上层收到出站 getWebdata(携带回传 data)
注意:
openwebActivity1不是 BridgeWebView,页面里无window.WebViewJavascriptBridge,H5 在该容器内只能用 §11.3 的settings接口和被原生javascript:直调的全局函数。
11.3 通用网页容器 openwebActivity1 的独立接口契约
来源:
openwebActivity1.java。机制 = 普通 WebView + 注入对象settings(@JavascriptInterface)+ 原生javascript:直接调用全局函数。新平台需为该容器单独实现这套契约(等价于 HarmonyOS 的javaScriptProxy+runJavaScript)。
(1) H5 → 原生:全局注入对象 settings(对象名固定为 settings)
H5 直接调用 window.settings.<方法>(...):
| 方法签名 | 参数 | 功能 |
|---|---|---|
settings.backgameData(data) |
data:String |
带数据返回上层容器(原生 setResult(101,{data}) 并关闭本页) |
settings.loadurl(urls) |
urls:String |
在本容器加载新 url |
settings.browser(browserurl) |
browserurl:String |
用系统/QQ 浏览器打开链接 |
settings.finishweb() |
无 | 直接关闭本页 |
settings.isexitdialogeshow() |
无 | 开启"返回时弹退出确认框"行为 |
settings.isbackfinishweb() |
无 | 设置返回键改为交给 H5(触发下方 gamebackkeydown())而非直接关闭 |
(2) 原生 → H5:javascript: 直接调用的全局函数(H5 需在 window 上定义同名函数)
| 全局函数(H5 须实现) | 参数 | 调用时机 |
|---|---|---|
getWebdata('<data>') |
字符串 data(来自打开时传入的 data) |
页面首次加载到 100% 时 |
gamebackkeydown() |
无 | 按下返回键、且 H5 已通过 settings.isbackfinishweb() 接管返回键、且 WebView 可后退时 |
backgameData() |
无(注意:与 H5→原生的 settings.backgameData(data) 同名但无参、方向相反) |
"返回退出确认框"点确认时,原生回调通知页面即将退出 |
(3) 该容器的 WebView 设置差异(相对 §7 主容器)
- 不注入
WebViewJavascriptBridge.js;无yy://拦截。 - 缓存策略不同:有网时用默认缓存(
LOAD_DEFAULT),无网时用缓存优先(LOAD_CACHE_ELSE_NETWORK);启用 AppCache。 - 同样启用:JavaScript、DOMStorage、文件访问、file:// 跨源访问、定位;禁缩放/禁多窗口。
- WebViewClient 自行拦截
weixin:/alipayqr:/alipays:/tel:等 scheme 跳转到系统处理。
适配要点:新平台需提供两类容器—— ① BridgeWebView 容器(大厅+子游戏,§2 协议 + §8/§9 全部 handler); ② 通用网页容器(§11.3 的
settings注入对象 6 方法 +getWebdata/gamebackkeydown/backgameData三个javascript:直调)。 两类容器都实现到位,现有 H5(含其打开的活动页/收银台/客服等)才能零改动运行。
12. 数据结构汇总
字段名严格对应代码,新平台序列化必须保持同名同语义。
sharetypeBean(分享入参,全 String)
{
"sharefriend": "1", // "1" 好友(弹面板) / "2" 朋友圈(直发微信)
"type": "1", // "1" 网页/文本 / "2" Canvas截图 / "3" 图片链接 / "4" 视频(抖音)
"sharetype": "", // 分享子类型
"webpageUrl": "https://...", // 分享链接 或 图片地址
"title": "标题",
"description": "描述"
}
MaplocationInfo(定位回传)
{
"latitude": 0.0, "longitude": 0.0, // double
"address": "", "country": "", "province": "", "city": "",
"district": "", "street": "", "cityCode": "", "streetNum": "",
"adCode": "", "aoiName": "", // 以上 String
"accuracy": 0.0, // float
"locationType": 0, // int
"errorCode": 0, // int:0 成功 / -1 未就绪 / -2 权限拒绝 / 其他=底层错误码
"errorMsg": "" // String
}
phoneInfoBean(手机信息回传,全 String)
{
"PhoneVersion": "", "PhoneAdresseMAC": "", "PhoneModel": "",
"PhoneDeviceBrand": "", "PhoneProvidersName": "",
"PhoneIMEI": "", "PhoneIMSI": ""
}
savephotoURLBean(图片下载,getphoto 回传数组元素)
{ "pid": "", "photourl": "" }
videoinfobean(createRoom 入参,全 String)
{ "playerid":"", "roomid":"", "agentid":"", "gameid":"",
"left":"", "top":"", "pmw":"", "pmh":"", "width":"", "height":"" }
Othervideoinfo(getVideoinfo 入参)
{ "playerid":"", "left":"", "top":"", "width":"", "height":"", "pmw":"", "pmh":"" }
支付相关
getGameplay入参:{ "price":"", "body":"", "typeplay":int, "type":"", "user":int }PayuserPaytypePaystate回传:{ "user":"", "state":int(1成功/0取消), "typeplay":"", "type":"", "data":"" }
sharelogin(微信登录回传,全 String)
{ "openid":"", "headimgurl":"", "nickname":"", "sex":"", "city":"", "province":"", "unionid":"" }
sharesuccess(分享回传)
{ "success": 2, "type": 1 } // success: 2成功/3取消;type: 1好友/2朋友圈
13. 关键常量与第三方账号
来源:
simcpux/Constants.java、AndroidManifest.xml。新平台需用自己的应用账号重新申请,下列仅说明依赖项。
| 项 | 值 | 说明 |
|---|---|---|
| 微信 AppID | wxd2bd650e06bdfe58 |
分享/登录/支付 |
| 微信商户号 MCH_ID | 1448669802 |
App 内支付 |
| 微信 API_KEY | ClMrQsAcidRa7uJT4TgHgVAOHbzQjdPa |
支付签名(应下沉服务端) |
| 微信 AppSecret | 1934a281c82ad1a059130fe51341b74b |
登录换 token(应下沉服务端) |
| 高德定位 API Key | 4f92bacc16cace69a6045a544d6e3c7d |
定位 |
| 微信回调 scheme | wxd2bd650e06bdfe58 |
第三方回调 |
| 自定义 scheme | gamepaywelcome、gamepaywxd2bd650e06bdfe58 |
H5/外部唤起原生页 |
关键权限:存储读写、读电话状态、定位(精确+粗略)、安装应用、网络、相机、录音、允许明文 HTTP。
⚠️ 安全提示:现有工程把微信 AppSecret / API_KEY 明文硬编码在客户端,存在风险。HarmonyOS 新版应将签名与换 token 逻辑下沉到服务端,登录改为回传 code。
14. HarmonyOS 适配检查清单与待决策项
14.1 必做(保证 H5 零改动运行)
- 实现 WebViewJavascriptBridge 协议:URL scheme
yy://拦截、_handleMessageFromNative/_fetchQueue、Message JSON 结构、onPageFinished注入WebViewJavascriptBridge.js、启动消息队列补发(§2)。直接复用该库的WebViewJavascriptBridge.js。 - 实现全部入站 handler(§8):44 个,名称/参数结构/同步返回 1:1 对齐;差异项取更完整一侧。
- 实现全部出站 handler 调用(§9):在对应时机以同名
callHandler推送同结构 data。 - 配置体系(§4):提供 §4.2 全部配置键取值(建议改用 KV 配置文件,无需沿用目录名编码)。
- 远程配置请求与分层覆盖(§4.3/4.4):URL 拼装、二级 url 二次请求、agent→channel→market→game 后层覆盖、
showmessage阻断。 - 资源管理(§5):内置包拷贝、version.xml 版本比较、远程 zip 下载/删旧/解压到资源目录。
- app_data.js 注入(§6):加载大厅前在大厅目录生成同名全局变量。
- 大厅入口(§3):
weburl空 →file://.../gamehall/index.html?Launchtype=0;非空 →http://<weburl去-换/>?Launchtype=0。 - WebView 能力(§7):JS、DOMStorage、file/universal-file 访问、混合内容、明文 HTTP、禁缓存、禁缩放、定位。
- 路径 A 子游戏切换(§11.1):
SwitchOverGameData在 BridgeWebView 容器内按目录重载、横竖屏切换。 - 路径 B + 通用网页容器(§11.2/§11.3):
OpenurlTitleData打开独立网页容器;该容器实现settings注入对象 6 方法(backgameData(data)/loadurl(urls)/browser(url)/finishweb()/isexitdialogeshow()/isbackfinishweb())+ 3 个javascript:直调全局函数(getWebdata(data)/gamebackkeydown()/backgameData())+ 结果码 101 回传上层 → 上层出站getWebdata。这是与主容器不同的第二套机制,勿遗漏。 - 本机 HTTP 上传端点 +
setPostUrl(§7/§9):支撑截图分享上传。 - 设备能力(§10):分享、微信登录/支付、定位、录音/音效、摇一摇、扫码、相机、震动、剪贴板、网络/电量/WiFi/电话状态。
14.2 待决策 / 需补齐(现有 Android 即缺失,新平台应主动完善)
| 事项 | 现状 | 建议 |
|---|---|---|
| QQ / 抖音分享结果回传 | 无回传 | 补齐统一 sharesuccess 回传 |
| 抖音 / 快手登录 | 完全未实现(sgapi 是闲聊且注释) | 按需全新对接,回传 code |
| 主动截图能力 | 仅耦合在分享内 | 新增独立 getCanvasBase64 handler |
通讯录 getAddressBook |
空实现 | 按需实现或保持空 |
notification 通知 |
空实现 | 按需实现 |
| 微信 AppSecret/API_KEY 明文 | 客户端硬编码 | 下沉服务端,登录改 code 模式 |
servertype / gameserver 配置 |
有目录无代码读取 | 可不实现 |
| App 内微信支付 vs 浏览器支付 | 新旧容器不一致 | 统一用 paybrowser,按需保留 App 内支付 |
14.3 接口名"原样保留"陷阱清单(拼写以代码为准,不可纠正)
finsh(退出,非 finish)accreditlogin、friendsSharetypeUrlToptitleDescript、SwitchOverGameData、DragViewvideoIsshowgetcameraaAddress(双 a)、getsaomaData、opensaomaPayuserPaytypePaystate、gameui_play_voice/gameui_stop_voicecanclevibrator(非 cancel)、repeatvibrator- 出站
backgameData-(末尾连字符)≠ 入站backgameData - 下载目录名
dowlod_zip(拼写如此)
结论:H5 与原生之间的契约 = §2 桥协议 + §8 入站 44 handler + §9 出站约 21 handler + §6
app_data.js注入 + §3~§5 启动与资源流程。新平台(HarmonyOS)只要让这套契约对外表现完全一致,现有 H5 即可零改动运行;原生内部实现方式不受任何限制。