补齐原生壳方法表门禁
补齐 HostBridge 方法表中的图片导出能力 原生壳总门禁校验方案方法表与共享契约一致 修正 Expo 壳未来 SDK 接入口径 同步验收清单和共享决策记录
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
- 2026-06-18 能力声明收紧:`packages/shared/src/contracts/hostBridge.ts` 提供 HostBridge method / capability 白名单,H5 的 `getHostRuntime()` 会解析并过滤 `hostCapabilities`;`openHostShare`、`writeHostClipboardText`、`requestHostHapticsImpact`、`setHostAppTitle`、`exportHostTextFile` 等 native 能力只在宿主声明对应 capability 后调用。发布分享弹窗只有声明 `share.open` 时才显示“系统分享”,避免旧壳或裁剪壳露出不可用入口。
|
||||
- 2026-06-18 宿主 runtime 回读:主 App 启动时会通过真实 `host.getRuntime` 回读 Expo / Tauri runtime 并缓存过滤后的能力清单,能力来源为 URL `hostCapabilities` 与宿主真实回包的并集;裁剪壳或旧入口 URL 缺少 `hostCapabilities` 时也能启用真实声明能力,但仍不会仅凭 `native_app` 或 transport 存在推断能力可用。
|
||||
- 2026-06-18 壳能力防漂移:`npm run mobile-shell:typecheck` 与 `npm run desktop-shell:typecheck` 会校验 Expo / Tauri 壳声明的 capability 均来自共享 HostBridge 白名单,并校验壳 runtime 回包、H5 URL `hostCapabilities` 和实现分支保持一致;微信小程序 `WECHAT_HOST_CAPABILITIES` 也由 `miniprogram/host-bridge/protocol.test.js` 反查同一共享白名单。新增能力必须先更新契约和真实壳实现,再通过这些检查。
|
||||
- 2026-06-18 原生壳统一验收门禁:根级 `npm run check:native-shells` 统一执行 H5 HostBridge 关键测试、Expo 壳 typecheck / test / config smoke / Metro export smoke、Tauri 壳 typecheck / cargo test、桌面 release `--no-bundle` 构建烟测和微信 / Expo / Tauri 三端生产壳临时替身词扫描;根级 `npm run check` 会在 lint、主站测试、构建和内容检查后继续执行该门禁,避免 HostBridge、三端壳、Expo managed config、移动端 production bundle、桌面 release 入口和壳生产源码禁替身验收散落成容易漏跑的单项命令。
|
||||
- 2026-06-18 原生壳统一验收门禁:根级 `npm run check:native-shells` 统一执行 H5 HostBridge 关键测试、Expo 壳 typecheck / test / config smoke / Metro export smoke、Tauri 壳 typecheck / cargo test、桌面 release `--no-bundle` 构建烟测,以及可分发壳与 H5 HostBridge 真实调用链的临时替身词扫描;根级 `npm run check` 会在 lint、主站测试、构建和内容检查后继续执行该门禁,避免 HostBridge、三端壳、Expo managed config、移动端 production bundle、桌面 release 入口和壳生产源码禁替身验收散落成容易漏跑的单项命令。
|
||||
- 2026-06-18 微信壳桥接层纳入统一验收:`npm run check:native-shells` 还会运行 `miniprogram/host-bridge/`、`miniprogram/shell/`、`pages/web-view` 样式和 `scripts/miniprogram-web-view-auth.test.ts` 的微信壳测试,覆盖 WebView 入口、登录触发、分享目标、支付结果、订阅消息结果和九宫切图行为;三端桥接层文件结构检查只证明目录边界,行为回归必须由同一门禁中的微信壳测试证明。
|
||||
- 2026-06-18 登录 / 支付能力禁伪声明:`auth.requestLogin` 和 `payment.request` 保留在共享 HostBridge 契约中供未来真实接入,但 Expo / Tauri 壳在真实 SDK、渠道流程和后端契约落地前不得声明这些 capability,也不得把它们写入入口 URL `hostCapabilities`;两端检查脚本会拒绝伪声明,请求实际到达壳层时必须返回明确 `unsupported_method` 并让 H5 fallback,两端壳测试直接覆盖这两个 method。
|
||||
- 2026-06-18 移动壳触觉反馈边界:`haptics.impact` 只接受 `light`、`medium`、`heavy` 三档 impact style,缺省为 `light`;未知值必须返回 `invalid_request`,不得静默降级成真实设备触觉反馈。桌面壳不声明该 capability,H5 继续按 HostBridge fallback 处理。
|
||||
|
||||
@@ -134,6 +134,7 @@ type HostBridgeEvent = {
|
||||
| `clipboard.readText` | 读取纯文本剪贴板 | 支持 | 支持 |
|
||||
| `file.exportText` | 导出文本到用户选择的本地文件 | 支持系统分享 / 保存面板 | 支持系统保存对话框 |
|
||||
| `file.importText` | 导入用户选择的文本文件 | 支持系统文档选择器 | 支持系统选择文本文件 |
|
||||
| `file.exportImage` | 导出当前 H5 已持有的图片文件 | 支持系统分享 / 保存面板 | 支持系统保存对话框 |
|
||||
| `file.importImage` | 导入用户选择的图片文件 | 支持系统相册选择图片 | 支持系统选择图片 |
|
||||
| `file.captureImage` | 拍摄图片并导入当前 H5 流程 | 支持系统相机拍照 | 不声明 |
|
||||
| `file.importAudio` | 导入用户选择的音频文件 | 支持系统文档选择器 | 支持系统选择音频文件 |
|
||||
@@ -154,7 +155,7 @@ Expo 壳只负责 App 外壳和原生能力,不承接玩法业务。
|
||||
- H5 到 RN:`window.ReactNativeWebView.postMessage(JSON.stringify(request))`。
|
||||
- RN 到 H5:通过 WebView ref 注入脚本,向 H5 派发统一 bridge response / event。
|
||||
- 使用 development build,不依赖 Expo Go 作为真实集成环境;需要自定义原生配置时用 config plugin / prebuild 管理。
|
||||
- App 壳维护启动页、深链、系统分享、推送、权限、App 版本、崩溃日志和支付 SDK。
|
||||
- App 壳维护启动页、深链、系统分享、即时本地通知、权限和 App 版本;远程推送、崩溃日志、支付 SDK 等能力必须等真实端点、渠道合同、发布流程和隐私口径确定后逐项接入。
|
||||
- 登录首期优先复用 H5 账号体系;后续再逐项接入 Apple / Android / 微信等原生登录能力。
|
||||
- 支付必须按上架渠道拆分:iOS / Android 虚拟内容优先评估 IAP / Google Play Billing 或国内渠道要求;H5 支付、小程序虚拟支付和桌面二维码支付不能直接照搬到 App Store 包。
|
||||
|
||||
@@ -478,7 +479,7 @@ GameBridge 禁止:
|
||||
- AI sandbox 无法调用 HostBridge,也无法读取 H5 登录态。
|
||||
- Tauri release 包不允许任意远端页面调用桌面命令。
|
||||
- Expo WebView 外链离开主站后不保留完整 HostBridge。
|
||||
- 根级验收入口 `npm run check:native-shells` 必须同时覆盖 H5 HostBridge 关键路径、三端桥接层文件结构门禁、Expo 壳 typecheck / test / config smoke / Metro export smoke、Tauri 壳 typecheck / cargo test、桌面 release `--no-bundle` 构建烟测和三端生产壳临时替身词扫描。
|
||||
- 根级验收入口 `npm run check:native-shells` 必须同时覆盖 H5 HostBridge 关键路径、三端桥接层文件结构门禁、Expo 壳 typecheck / test / config smoke / Metro export smoke、Tauri 壳 typecheck / cargo test、桌面 release `--no-bundle` 构建烟测,以及可分发壳与 H5 HostBridge 真实调用链的临时替身词扫描。
|
||||
|
||||
## 参考资料
|
||||
|
||||
|
||||
@@ -331,6 +331,22 @@ function extractDocumentCapabilityList(source, marker) {
|
||||
return [...sentence.matchAll(/`([^`]+)`/g)].map((entry) => entry[1]);
|
||||
}
|
||||
|
||||
function extractDocumentMethodTable(source) {
|
||||
const start = source.indexOf('首批 method:');
|
||||
if (start === -1) {
|
||||
throw new Error('native shell plan missing HostBridge method table');
|
||||
}
|
||||
|
||||
const end = source.indexOf('每个 method 都必须', start);
|
||||
if (end === -1) {
|
||||
throw new Error('native shell plan method table missing end marker');
|
||||
}
|
||||
|
||||
return [...source.slice(start, end).matchAll(/^\| `([^`]+)` \|/gm)].map(
|
||||
(entry) => entry[1],
|
||||
);
|
||||
}
|
||||
|
||||
function assertNativeShellCapabilityPlan() {
|
||||
const planSource = fs.readFileSync(nativeShellPlanPath, 'utf8');
|
||||
if (
|
||||
@@ -341,6 +357,14 @@ function assertNativeShellCapabilityPlan() {
|
||||
'native shell plan must not document core:default as a desktop capability permission',
|
||||
);
|
||||
}
|
||||
if (
|
||||
planSource.includes('三端生产壳临时替身词扫描') ||
|
||||
!planSource.includes('H5 HostBridge 真实调用链的临时替身词扫描')
|
||||
) {
|
||||
throw new Error(
|
||||
'native shell plan must document production scaffold scanning for the H5 HostBridge call chain',
|
||||
);
|
||||
}
|
||||
|
||||
const mobileCapabilitySource = fs.readFileSync(
|
||||
'apps/mobile-shell/src/host-bridge/capabilities.ts',
|
||||
@@ -354,6 +378,10 @@ function assertNativeShellCapabilityPlan() {
|
||||
mobileCapabilitySource,
|
||||
'MOBILE_HOST_CAPABILITIES',
|
||||
);
|
||||
const sharedMethods = extractTsStringArray(
|
||||
fs.readFileSync(sharedHostBridgeContractPath, 'utf8'),
|
||||
'HOST_BRIDGE_METHODS',
|
||||
);
|
||||
const iosMobileCapabilities = extractTsStringArray(
|
||||
mobileCapabilitySource,
|
||||
'IOS_MOBILE_HOST_CAPABILITIES',
|
||||
@@ -363,6 +391,20 @@ function assertNativeShellCapabilityPlan() {
|
||||
);
|
||||
const desktopCapabilities = extractRustCapabilities(desktopCapabilitySource);
|
||||
|
||||
assertSameList(
|
||||
extractDocumentMethodTable(planSource),
|
||||
[
|
||||
...sharedMethods.slice(0, 8),
|
||||
'app.lifecycle',
|
||||
'navigation.canGoBack',
|
||||
...sharedMethods.slice(8, 12),
|
||||
'network.statusChanged',
|
||||
...sharedMethods.slice(12, 21),
|
||||
'file.imageDropped',
|
||||
...sharedMethods.slice(21),
|
||||
],
|
||||
'native shell documented method table',
|
||||
);
|
||||
assertSameList(
|
||||
extractDocumentCapabilityList(planSource, capabilityListMarkers.mobile),
|
||||
mobileCapabilities,
|
||||
|
||||
Reference in New Issue
Block a user