diff --git a/apps/mobile-shell/App.tsx b/apps/mobile-shell/App.tsx
index 3d3d65ed8..0cf497498 100644
--- a/apps/mobile-shell/App.tsx
+++ b/apps/mobile-shell/App.tsx
@@ -1,5 +1,5 @@
-import MobileShellApp from './src/shell/MobileShellApp';
+import ShellApp from './src/shell/ShellApp';
export default function App() {
- return ;
+ return ;
}
diff --git a/apps/mobile-shell/scripts/check-config.mjs b/apps/mobile-shell/scripts/check-config.mjs
index 5536e871d..2848c07cb 100644
--- a/apps/mobile-shell/scripts/check-config.mjs
+++ b/apps/mobile-shell/scripts/check-config.mjs
@@ -6,9 +6,9 @@ const appConfigPath = new URL('../app.json', import.meta.url);
const appConfig = JSON.parse(fs.readFileSync(appConfigPath, 'utf8')).expo;
const appPath = new URL('../App.tsx', import.meta.url);
const appSource = fs.readFileSync(appPath, 'utf8');
-const mobileShellAppPath = new URL('../src/shell/MobileShellApp.tsx', import.meta.url);
-const mobileShellAppSource = fs.readFileSync(mobileShellAppPath, 'utf8');
-const bridgePath = new URL('../src/host-bridge/mobileHostBridge.ts', import.meta.url);
+const shellAppPath = new URL('../src/shell/ShellApp.tsx', import.meta.url);
+const shellAppSource = fs.readFileSync(shellAppPath, 'utf8');
+const bridgePath = new URL('../src/host-bridge/bridge.ts', import.meta.url);
const bridgeSource = fs.readFileSync(bridgePath, 'utf8');
const bridgeDirPath = new URL('../src/host-bridge/', import.meta.url);
const bridgeSourceFiles = fs
@@ -24,10 +24,10 @@ const bridgeSourceFiles = fs
const hostBridgeSource = bridgeSourceFiles
.map((file) => fs.readFileSync(file, 'utf8'))
.join('\n');
-const mobileShellUrlPath = new URL('../src/shell/mobileShellUrl.ts', import.meta.url);
-const mobileShellUrlSource = fs.readFileSync(mobileShellUrlPath, 'utf8');
-const mobileShellRuntimePath = new URL('../src/shell/mobileShellRuntime.ts', import.meta.url);
-const mobileShellRuntimeSource = fs.readFileSync(mobileShellRuntimePath, 'utf8');
+const urlPath = new URL('../src/shell/url.ts', import.meta.url);
+const urlSource = fs.readFileSync(urlPath, 'utf8');
+const runtimePath = new URL('../src/shell/runtime.ts', import.meta.url);
+const runtimeSource = fs.readFileSync(runtimePath, 'utf8');
const sharedContractPath = new URL(
'../../../packages/shared/src/contracts/hostBridge.ts',
import.meta.url,
@@ -209,10 +209,10 @@ function assertNoBlockedMobileChannelSnippets() {
const sources = [
['app.json', JSON.stringify(appConfig)],
['App.tsx', appSource],
- ['MobileShellApp.tsx', mobileShellAppSource],
+ ['ShellApp.tsx', shellAppSource],
['src/host-bridge', hostBridgeSource],
- ['mobileShellUrl.ts', mobileShellUrlSource],
- ['mobileShellRuntime.ts', mobileShellRuntimeSource],
+ ['url.ts', urlSource],
+ ['runtime.ts', runtimeSource],
];
for (const [sourceName, source] of sources) {
@@ -543,11 +543,11 @@ if (appConfig.version !== '0.1.0') {
throw new Error('mobile shell app version must be 0.1.0');
}
-const mobileShellHostVersion = extractStringConstExport(
- mobileShellRuntimeSource,
+const mobileHostVersion = extractStringConstExport(
+ runtimeSource,
'MOBILE_SHELL_HOST_VERSION',
);
-if (mobileShellHostVersion !== appConfig.version) {
+if (mobileHostVersion !== appConfig.version) {
throw new Error('mobile shell HostBridge host version must match app.json version');
}
@@ -750,16 +750,16 @@ for (const snippet of [
'onFileDownload={() => undefined}',
'setSupportMultipleWindows={false}',
]) {
- if (!mobileShellAppSource.includes(snippet)) {
- throw new Error(`mobile shell MobileShellApp missing ${snippet}`);
+ if (!shellAppSource.includes(snippet)) {
+ throw new Error(`mobile shell ShellApp missing ${snippet}`);
}
}
-if (!appSource.includes("import MobileShellApp from './src/shell/MobileShellApp';")) {
+if (!appSource.includes("import ShellApp from './src/shell/ShellApp';")) {
throw new Error('mobile shell App must import the shell app facade');
}
-if (!appSource.includes('return ;')) {
+if (!appSource.includes('return ;')) {
throw new Error('mobile shell App must only render the shell app facade');
}
@@ -768,15 +768,15 @@ if (appSource.includes('./src/host-bridge/')) {
}
if (
- mobileShellAppSource.includes('process.env.EXPO_PUBLIC_GENARRATIVE_WEB_URL ||')
+ shellAppSource.includes('process.env.EXPO_PUBLIC_GENARRATIVE_WEB_URL ||')
) {
throw new Error(
- 'mobile shell MobileShellApp must normalize EXPO_PUBLIC_GENARRATIVE_WEB_URL',
+ 'mobile shell ShellApp must normalize EXPO_PUBLIC_GENARRATIVE_WEB_URL',
);
}
if (
- !mobileShellUrlSource.includes(
+ !urlSource.includes(
"DEFAULT_MOBILE_SHELL_WEB_URL = 'https://app.genarrative.world/'",
)
) {
@@ -791,14 +791,14 @@ for (const snippet of [
"'[::1]'",
'isAllowedMobileShellBaseUrl',
]) {
- if (!mobileShellUrlSource.includes(snippet)) {
+ if (!urlSource.includes(snippet)) {
throw new Error(`mobile shell H5 URL allowlist missing ${snippet}`);
}
}
-if (mobileShellAppSource.includes('127.0.0.1:3000')) {
+if (shellAppSource.includes('127.0.0.1:3000')) {
throw new Error(
- 'mobile shell MobileShellApp must not hard-code localhost as the default H5 URL',
+ 'mobile shell ShellApp must not hard-code localhost as the default H5 URL',
);
}
@@ -924,15 +924,15 @@ for (const snippet of [
}
const capabilityQuerySnippet = "capabilities: MOBILE_HOST_CAPABILITIES";
-if (mobileShellAppSource.includes(capabilityQuerySnippet)) {
+if (shellAppSource.includes(capabilityQuerySnippet)) {
throw new Error('mobile shell URL must resolve platform-aware capabilities');
}
-if (!mobileShellAppSource.includes('capabilities: resolveMobileHostCapabilities()')) {
+if (!shellAppSource.includes('capabilities: resolveMobileHostCapabilities()')) {
throw new Error('mobile shell URL must use resolveMobileHostCapabilities()');
}
-if (!mobileShellAppSource.includes('hostVersion: MOBILE_SHELL_HOST_VERSION')) {
+if (!shellAppSource.includes('hostVersion: MOBILE_SHELL_HOST_VERSION')) {
throw new Error('mobile shell URL must use the shared mobile shell host version');
}
@@ -941,7 +941,7 @@ if (!bridgeSource.includes('hostVersion: MOBILE_SHELL_HOST_VERSION')) {
}
if (
- mobileShellAppSource.includes("hostVersion: '0.1.0'") ||
+ shellAppSource.includes("hostVersion: '0.1.0'") ||
bridgeSource.includes("hostVersion: '0.1.0'")
) {
throw new Error('mobile shell HostBridge version must not be duplicated in app or bridge source');
@@ -949,8 +949,8 @@ if (
for (const capability of sdkBackedCapabilities) {
if (
- mobileShellAppSource.includes(`'${capability}'`) ||
- mobileShellAppSource.includes(`"${capability}"`)
+ shellAppSource.includes(`'${capability}'`) ||
+ shellAppSource.includes(`"${capability}"`)
) {
throw new Error(
`mobile shell URL must not advertise ${capability} without a real SDK/channel flow`,
diff --git a/apps/mobile-shell/src/host-bridge/mobileHostBridge.test.ts b/apps/mobile-shell/src/host-bridge/bridge.test.ts
similarity index 99%
rename from apps/mobile-shell/src/host-bridge/mobileHostBridge.test.ts
rename to apps/mobile-shell/src/host-bridge/bridge.test.ts
index 3115d1ff8..1829b858f 100644
--- a/apps/mobile-shell/src/host-bridge/mobileHostBridge.test.ts
+++ b/apps/mobile-shell/src/host-bridge/bridge.test.ts
@@ -25,7 +25,7 @@ import {
configureMobileHostBridgeNavigation,
handleMobileHostBridgeMessage,
resetMobileHostBridgeForTest,
-} from './mobileHostBridge';
+} from './bridge';
type NotificationPermissionStatus =
Awaited>;
diff --git a/apps/mobile-shell/src/host-bridge/mobileHostBridge.ts b/apps/mobile-shell/src/host-bridge/bridge.ts
similarity index 96%
rename from apps/mobile-shell/src/host-bridge/mobileHostBridge.ts
rename to apps/mobile-shell/src/host-bridge/bridge.ts
index e43f771c2..dcaf2ed2f 100644
--- a/apps/mobile-shell/src/host-bridge/mobileHostBridge.ts
+++ b/apps/mobile-shell/src/host-bridge/bridge.ts
@@ -27,9 +27,9 @@ import {
type OpenExternalUrlPayload,
type SetBadgeCountPayload,
} from '../../../../packages/shared/src/contracts/hostBridge';
-import { resolveMobileShellWebViewUrl } from '../shell/mobileShellNavigation';
-import { getMobileNetworkStatus } from '../shell/mobileShellNetwork';
-import { MOBILE_SHELL_HOST_VERSION } from '../shell/mobileShellRuntime';
+import { resolveMobileShellWebViewUrl } from '../shell/navigation';
+import { getMobileNetworkStatus } from '../shell/network';
+import { MOBILE_SHELL_HOST_VERSION } from '../shell/runtime';
import {
captureImageFile,
exportAudioFile,
@@ -38,7 +38,7 @@ import {
importAudioFile,
importImageFile,
importTextFile,
-} from './mobileHostBridgeFiles';
+} from './files';
import {
HOST_BRIDGE_RESPONSE_CACHE_MAX,
type MobileHostBridgeNavigation,
@@ -50,14 +50,14 @@ import {
parseRequest,
resolveMobileHostCapabilities,
unsupported,
-} from './mobileHostBridgeProtocol';
-import { openShare } from './mobileHostBridgeShare';
+} from './protocol';
+import { openShare } from './share';
export {
IOS_MOBILE_HOST_CAPABILITIES,
MOBILE_HOST_CAPABILITIES,
resolveMobileHostCapabilities,
-} from './mobileHostBridgeProtocol';
+} from './protocol';
const LOCAL_NOTIFICATION_CHANNEL_ID = 'genarrative-local';
diff --git a/apps/mobile-shell/src/host-bridge/mobileHostBridgeFiles.ts b/apps/mobile-shell/src/host-bridge/files.ts
similarity index 99%
rename from apps/mobile-shell/src/host-bridge/mobileHostBridgeFiles.ts
rename to apps/mobile-shell/src/host-bridge/files.ts
index d9237b6a7..45d327182 100644
--- a/apps/mobile-shell/src/host-bridge/mobileHostBridgeFiles.ts
+++ b/apps/mobile-shell/src/host-bridge/files.ts
@@ -19,7 +19,7 @@ import {
type HostBridgeTextMimeType,
normalizeHostBridgeExportFileName,
} from '../../../../packages/shared/src/contracts/hostBridge';
-import { invalidRequest } from './mobileHostBridgeProtocol';
+import { invalidRequest } from './protocol';
const EXPORT_TEXT_MAX_BYTES = 5 * 1024 * 1024;
const EXPORT_IMAGE_MAX_BYTES = 5 * 1024 * 1024;
diff --git a/apps/mobile-shell/src/host-bridge/mobileHostBridgeProtocol.ts b/apps/mobile-shell/src/host-bridge/protocol.ts
similarity index 100%
rename from apps/mobile-shell/src/host-bridge/mobileHostBridgeProtocol.ts
rename to apps/mobile-shell/src/host-bridge/protocol.ts
diff --git a/apps/mobile-shell/src/host-bridge/mobileHostBridgeShare.ts b/apps/mobile-shell/src/host-bridge/share.ts
similarity index 97%
rename from apps/mobile-shell/src/host-bridge/mobileHostBridgeShare.ts
rename to apps/mobile-shell/src/host-bridge/share.ts
index 109a35a8d..52607d232 100644
--- a/apps/mobile-shell/src/host-bridge/mobileHostBridgeShare.ts
+++ b/apps/mobile-shell/src/host-bridge/share.ts
@@ -1,7 +1,7 @@
import { Share } from 'react-native';
import { type ShareOpenPayload } from '../../../../packages/shared/src/contracts/hostBridge';
-import { invalidRequest } from './mobileHostBridgeProtocol';
+import { invalidRequest } from './protocol';
const WEB_APP_ORIGIN = 'https://app.genarrative.world';
diff --git a/apps/mobile-shell/src/shell/MobileShellApp.tsx b/apps/mobile-shell/src/shell/ShellApp.tsx
similarity index 90%
rename from apps/mobile-shell/src/shell/MobileShellApp.tsx
rename to apps/mobile-shell/src/shell/ShellApp.tsx
index 9e0cc2f8a..34369ccce 100644
--- a/apps/mobile-shell/src/shell/MobileShellApp.tsx
+++ b/apps/mobile-shell/src/shell/ShellApp.tsx
@@ -16,25 +16,25 @@ import {
configureMobileHostBridgeNavigation,
handleMobileHostBridgeMessage,
resolveMobileHostCapabilities,
-} from '../host-bridge/mobileHostBridge';
-import { buildMobileShellUrlFromDeepLink } from './mobileShellDeepLink';
-import { lifecyclePayloadFromAppState } from './mobileShellLifecycle';
+} from '../host-bridge/bridge';
+import { buildMobileShellUrlFromDeepLink } from './deepLink';
+import { lifecyclePayloadFromAppState } from './lifecycle';
import {
resolveMobileShellExternalUrl,
shouldAcceptMobileShellHostBridgeMessage,
shouldOpenInMobileShellWebView,
-} from './mobileShellNavigation';
+} from './navigation';
import {
getMobileNetworkStatus,
subscribeMobileNetworkStatus,
-} from './mobileShellNetwork';
-import { MOBILE_SHELL_HOST_VERSION } from './mobileShellRuntime';
-import { MOBILE_SHELL_SAFE_AREA_EDGES } from './mobileShellSafeArea';
+} from './network';
+import { MOBILE_SHELL_HOST_VERSION } from './runtime';
+import { MOBILE_SHELL_SAFE_AREA_EDGES } from './safeArea';
import {
buildMobileShellUrl,
resolveMobileShellBaseWebUrl,
-} from './mobileShellUrl';
-import { BLOCK_WEBVIEW_DOWNLOAD_SCRIPT } from './mobileShellWebViewPolicy';
+} from './url';
+import { BLOCK_WEBVIEW_DOWNLOAD_SCRIPT } from './webViewPolicy';
function buildHostBridgeMessageScript(message: unknown) {
return `window.dispatchEvent(new MessageEvent('message', { data: ${JSON.stringify(
@@ -42,13 +42,13 @@ function buildHostBridgeMessageScript(message: unknown) {
)}, origin: window.location.origin, source: window })); true;`;
}
-export default function MobileShellApp() {
+export default function ShellApp() {
const webViewRef = useRef(null);
const [canGoBack, setCanGoBack] = useState(false);
const baseWebUrl = resolveMobileShellBaseWebUrl(
process.env.EXPO_PUBLIC_GENARRATIVE_WEB_URL,
);
- const mobileShellUrlOptions = useMemo(
+ const urlOptions = useMemo(
() => ({
platform: Platform.OS === 'ios' ? 'ios' as const : 'android' as const,
hostVersion: MOBILE_SHELL_HOST_VERSION,
@@ -57,7 +57,7 @@ export default function MobileShellApp() {
[],
);
const [webUrl, setWebUrl] = useState(() =>
- buildMobileShellUrl(baseWebUrl, mobileShellUrlOptions),
+ buildMobileShellUrl(baseWebUrl, urlOptions),
);
const allowedWebOrigin = useMemo(() => new URL(webUrl).origin, [webUrl]);
const reloadCurrentWebView = useCallback(() => {
@@ -105,7 +105,7 @@ export default function MobileShellApp() {
const nextUrl = buildMobileShellUrlFromDeepLink(
url,
baseWebUrl,
- mobileShellUrlOptions,
+ urlOptions,
);
setWebUrl(nextUrl);
};
@@ -124,7 +124,7 @@ export default function MobileShellApp() {
disposed = true;
subscription.remove();
};
- }, [baseWebUrl, mobileShellUrlOptions]);
+ }, [baseWebUrl, urlOptions]);
useEffect(() => {
const subscription = BackHandler.addEventListener(
diff --git a/apps/mobile-shell/src/shell/mobileShellDeepLink.test.ts b/apps/mobile-shell/src/shell/deepLink.test.ts
similarity index 97%
rename from apps/mobile-shell/src/shell/mobileShellDeepLink.test.ts
rename to apps/mobile-shell/src/shell/deepLink.test.ts
index 24cc2a937..f28db0373 100644
--- a/apps/mobile-shell/src/shell/mobileShellDeepLink.test.ts
+++ b/apps/mobile-shell/src/shell/deepLink.test.ts
@@ -1,6 +1,6 @@
import { describe, expect, test } from 'vitest';
-import { buildMobileShellUrlFromDeepLink } from './mobileShellDeepLink';
+import { buildMobileShellUrlFromDeepLink } from './deepLink';
const options = {
platform: 'ios' as const,
diff --git a/apps/mobile-shell/src/shell/mobileShellDeepLink.ts b/apps/mobile-shell/src/shell/deepLink.ts
similarity index 98%
rename from apps/mobile-shell/src/shell/mobileShellDeepLink.ts
rename to apps/mobile-shell/src/shell/deepLink.ts
index 24f908d18..599411dc9 100644
--- a/apps/mobile-shell/src/shell/mobileShellDeepLink.ts
+++ b/apps/mobile-shell/src/shell/deepLink.ts
@@ -2,7 +2,7 @@ import {
buildMobileShellUrl,
resolveMobileShellBaseWebUrl,
type MobileShellUrlOptions,
-} from './mobileShellUrl';
+} from './url';
const supportedHosts = new Set(['open', 'app']);
diff --git a/apps/mobile-shell/src/shell/mobileShellLifecycle.test.ts b/apps/mobile-shell/src/shell/lifecycle.test.ts
similarity index 86%
rename from apps/mobile-shell/src/shell/mobileShellLifecycle.test.ts
rename to apps/mobile-shell/src/shell/lifecycle.test.ts
index eedf543ab..89d96d3ca 100644
--- a/apps/mobile-shell/src/shell/mobileShellLifecycle.test.ts
+++ b/apps/mobile-shell/src/shell/lifecycle.test.ts
@@ -1,8 +1,8 @@
import { describe, expect, test } from 'vitest';
-import { lifecyclePayloadFromAppState } from './mobileShellLifecycle';
+import { lifecyclePayloadFromAppState } from './lifecycle';
-describe('mobileShellLifecycle', () => {
+describe('lifecycle', () => {
test('把 React Native AppState 映射为统一 HostBridge 生命周期状态', () => {
expect(lifecyclePayloadFromAppState('active')).toEqual({
state: 'active',
diff --git a/apps/mobile-shell/src/shell/mobileShellLifecycle.ts b/apps/mobile-shell/src/shell/lifecycle.ts
similarity index 100%
rename from apps/mobile-shell/src/shell/mobileShellLifecycle.ts
rename to apps/mobile-shell/src/shell/lifecycle.ts
diff --git a/apps/mobile-shell/src/shell/mobileShellNavigation.test.ts b/apps/mobile-shell/src/shell/navigation.test.ts
similarity index 99%
rename from apps/mobile-shell/src/shell/mobileShellNavigation.test.ts
rename to apps/mobile-shell/src/shell/navigation.test.ts
index 6899f76d3..731b5ec9a 100644
--- a/apps/mobile-shell/src/shell/mobileShellNavigation.test.ts
+++ b/apps/mobile-shell/src/shell/navigation.test.ts
@@ -5,7 +5,7 @@ import {
resolveMobileShellWebViewUrl,
shouldAcceptMobileShellHostBridgeMessage,
shouldOpenInMobileShellWebView,
-} from './mobileShellNavigation';
+} from './navigation';
describe('shouldOpenInMobileShellWebView', () => {
test('只允许主站同源页面留在移动壳 WebView 内', () => {
diff --git a/apps/mobile-shell/src/shell/mobileShellNavigation.ts b/apps/mobile-shell/src/shell/navigation.ts
similarity index 100%
rename from apps/mobile-shell/src/shell/mobileShellNavigation.ts
rename to apps/mobile-shell/src/shell/navigation.ts
diff --git a/apps/mobile-shell/src/shell/mobileShellNetwork.test.ts b/apps/mobile-shell/src/shell/network.test.ts
similarity index 96%
rename from apps/mobile-shell/src/shell/mobileShellNetwork.test.ts
rename to apps/mobile-shell/src/shell/network.test.ts
index e8aab22e7..0e2a69245 100644
--- a/apps/mobile-shell/src/shell/mobileShellNetwork.test.ts
+++ b/apps/mobile-shell/src/shell/network.test.ts
@@ -4,7 +4,7 @@ import {
getMobileNetworkStatus,
normalizeMobileNetworkStatus,
subscribeMobileNetworkStatus,
-} from './mobileShellNetwork';
+} from './network';
vi.mock('expo-network', () => ({
addNetworkStateListener: vi.fn(),
@@ -17,7 +17,7 @@ vi.mock('expo-network', () => ({
},
}));
-describe('mobileShellNetwork', async () => {
+describe('network', async () => {
const Network = await import('expo-network');
test('归一化 Expo Network 状态', () => {
diff --git a/apps/mobile-shell/src/shell/mobileShellNetwork.ts b/apps/mobile-shell/src/shell/network.ts
similarity index 100%
rename from apps/mobile-shell/src/shell/mobileShellNetwork.ts
rename to apps/mobile-shell/src/shell/network.ts
diff --git a/apps/mobile-shell/src/shell/mobileShellRuntime.ts b/apps/mobile-shell/src/shell/runtime.ts
similarity index 100%
rename from apps/mobile-shell/src/shell/mobileShellRuntime.ts
rename to apps/mobile-shell/src/shell/runtime.ts
diff --git a/apps/mobile-shell/src/shell/mobileShellSafeArea.test.ts b/apps/mobile-shell/src/shell/safeArea.test.ts
similarity index 80%
rename from apps/mobile-shell/src/shell/mobileShellSafeArea.test.ts
rename to apps/mobile-shell/src/shell/safeArea.test.ts
index 65bda42aa..09c70c82e 100644
--- a/apps/mobile-shell/src/shell/mobileShellSafeArea.test.ts
+++ b/apps/mobile-shell/src/shell/safeArea.test.ts
@@ -1,6 +1,6 @@
import { describe, expect, test } from 'vitest';
-import { MOBILE_SHELL_SAFE_AREA_EDGES } from './mobileShellSafeArea';
+import { MOBILE_SHELL_SAFE_AREA_EDGES } from './safeArea';
describe('mobile shell safe area', () => {
test('protects the WebView from every device edge', () => {
diff --git a/apps/mobile-shell/src/shell/mobileShellSafeArea.ts b/apps/mobile-shell/src/shell/safeArea.ts
similarity index 100%
rename from apps/mobile-shell/src/shell/mobileShellSafeArea.ts
rename to apps/mobile-shell/src/shell/safeArea.ts
diff --git a/apps/mobile-shell/src/shell/mobileShellUrl.test.ts b/apps/mobile-shell/src/shell/url.test.ts
similarity index 99%
rename from apps/mobile-shell/src/shell/mobileShellUrl.test.ts
rename to apps/mobile-shell/src/shell/url.test.ts
index ab63f24aa..efd10ffa2 100644
--- a/apps/mobile-shell/src/shell/mobileShellUrl.test.ts
+++ b/apps/mobile-shell/src/shell/url.test.ts
@@ -4,7 +4,7 @@ import {
DEFAULT_MOBILE_SHELL_WEB_URL,
buildMobileShellUrl,
resolveMobileShellBaseWebUrl,
-} from './mobileShellUrl';
+} from './url';
describe('buildMobileShellUrl', () => {
test('默认 H5 地址指向真实主站', () => {
diff --git a/apps/mobile-shell/src/shell/mobileShellUrl.ts b/apps/mobile-shell/src/shell/url.ts
similarity index 100%
rename from apps/mobile-shell/src/shell/mobileShellUrl.ts
rename to apps/mobile-shell/src/shell/url.ts
diff --git a/apps/mobile-shell/src/shell/mobileShellWebViewPolicy.test.ts b/apps/mobile-shell/src/shell/webViewPolicy.test.ts
similarity index 87%
rename from apps/mobile-shell/src/shell/mobileShellWebViewPolicy.test.ts
rename to apps/mobile-shell/src/shell/webViewPolicy.test.ts
index ec86e29c7..227056779 100644
--- a/apps/mobile-shell/src/shell/mobileShellWebViewPolicy.test.ts
+++ b/apps/mobile-shell/src/shell/webViewPolicy.test.ts
@@ -1,6 +1,6 @@
import { describe, expect, test } from 'vitest';
-import { BLOCK_WEBVIEW_DOWNLOAD_SCRIPT } from './mobileShellWebViewPolicy';
+import { BLOCK_WEBVIEW_DOWNLOAD_SCRIPT } from './webViewPolicy';
describe('BLOCK_WEBVIEW_DOWNLOAD_SCRIPT', () => {
test('阻断 WebView 内的网页下载链接', () => {
diff --git a/apps/mobile-shell/src/shell/mobileShellWebViewPolicy.ts b/apps/mobile-shell/src/shell/webViewPolicy.ts
similarity index 100%
rename from apps/mobile-shell/src/shell/mobileShellWebViewPolicy.ts
rename to apps/mobile-shell/src/shell/webViewPolicy.ts
diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md
index 529b55fa1..4602ad71d 100644
--- a/docs/project-memory/shared-memory/decision-log.md
+++ b/docs/project-memory/shared-memory/decision-log.md
@@ -49,7 +49,7 @@
- 2026-06-18 移动壳启动 URL 归一:Expo 壳的 `EXPO_PUBLIC_GENARRATIVE_WEB_URL` 和 deep link 基准地址只接受生产主站 `https://app.genarrative.world`,以及本机开发联调 `http://127.0.0.1`、`http://localhost`、`http://[::1]`;空值、相对路径、外域、`file:`、`javascript:` 等非法配置回退到默认 H5 地址后再附加 `native_app` 宿主上下文;deep link 仍只映射归一后基准 origin 的 H5 路径,禁止把外域或危险协议页面装进带完整 HostBridge 的 WebView。
- 2026-06-18 移动壳默认入口:Expo 壳默认 H5 地址固定为 `https://app.genarrative.world/`,开发联调本机 Vite 必须显式设置 `EXPO_PUBLIC_GENARRATIVE_WEB_URL=http://127.0.0.1:3000/`、`http://localhost:3000/` 或 `http://[::1]:3000/`;生产包不得在未配置环境变量时加载设备本机 localhost,也不得通过环境变量把第三方外域 H5 放入带完整 HostBridge 的 WebView。
- 2026-06-18 移动壳安装包身份:Expo 移动壳的 iOS bundle identifier 与 Android package 统一固定为 `world.genarrative.mobile`,应用版本固定为 `0.1.0`,iOS `buildNumber` 从字符串 `"1"` 起步,Android `versionCode` 从整数 `1` 起步;后续分发安装包时递增构建号 / versionCode,产品版本号按发布节奏调整。移动壳配置检查会校验 `app.json` 与 `package.json` 版本一致,并拒绝缺失或漂移的包标识,当前不写入假商店元数据、假更新端点或占位渠道 SDK 配置。
-- 2026-06-18 移动壳 HostBridge 版本单一来源:Expo 移动壳的 H5 入口 query 和 `host.getRuntime` 回包都读取 `MOBILE_SHELL_HOST_VERSION`,该常量必须与 `app.json` / `package.json` 版本一致;配置检查会拒绝 `App.tsx` 或 `mobileHostBridge.ts` 重新散落硬编码版本,避免安装包版本升级时 H5 首屏上下文与 runtime 回读分叉。
+- 2026-06-18 移动壳 HostBridge 版本单一来源:Expo 移动壳的 H5 入口 query 和 `host.getRuntime` 回包都读取 `MOBILE_SHELL_HOST_VERSION`,该常量必须与 `app.json` / `package.json` 版本一致;配置检查会拒绝 `App.tsx` 或 `bridge.ts` 重新散落硬编码版本,避免安装包版本升级时 H5 首屏上下文与 runtime 回读分叉。
- 2026-06-18 移动壳发布通道边界:Expo 移动壳默认显式关闭 OTA 更新,只允许 `updates.enabled=false`;在真实发布通道、更新端点、签名 / 回滚策略和团队发布流程落地前,不得配置 `runtimeVersion`、release channel、EAS channel、`expo-updates` 插件或移动端 crash / analytics / CodePush 依赖。移动壳配置检查和 Expo public config smoke 会拒绝这些发布通道能力被提前打开,根 `package-lock.json` 也不得解析 `expo-updates`、Sentry、Firebase Analytics、PostHog、Amplitude、Segment、CodePush 等真实发布 / 观测 SDK。
- 2026-06-18 移动壳观测与渠道 SDK 初始化边界:移动壳生产入口、HostBridge、启动 URL 和 runtime 配置不得提前初始化 Sentry、Firebase Analytics、PostHog、Amplitude、Segment、CodePush 或 Expo Updates;这些 SDK 必须等真实发布通道、采集字段、用户授权、隐私披露、签名 / 回滚策略和团队发布流程落地后逐项接入。配置检查会同时拒绝相关依赖、锁文件解析、Expo 配置和源码初始化片段;`expo-application` 可能由 Expo 自身传递解析,但项目不得主动 direct 依赖它实现渠道逻辑。
- 2026-06-18 桌面图片拖入接入主图槽位:`CreativeImageInputPanel` 在桌面壳声明 `file.imageDropped` 时订阅宿主拖入事件,只在拖入坐标命中当前主图卡片且未被上层元素遮挡时消费事件,避免窗口级拖入被多个创作面板同时接收;成功后仍转换为现有 `File` 上传回调。
@@ -86,7 +86,7 @@
- 2026-06-18 移动壳 WebView 安全开关:Expo 移动壳 WebView 必须显式禁用 JS 自动开窗、多窗口、文件访问、file URL 跨源访问、HTTPS 混合内容、第三方 Cookie、共享 Cookie 和 WebView 远程调试;同源主站页面才能留在带 HostBridge 的 WebView 内,外链只通过受控协议离开容器交给系统。配置检查和移动壳导航测试会拒绝这些边界被放宽。
- 2026-06-18 移动壳 WebView 默认下载边界:Expo WebView 内网页自动下载和 `` 直接落盘默认关闭;壳层注入脚本阻断 download 链接,iOS `onFileDownload` 只丢弃不落盘,Android 包配置通过 `blockedPermissions` 移除外部存储读写、管理外部存储和请求安装包权限。移动端文本、图片、音频保存只能通过 `file.exportText`、`file.exportImage`、`file.exportAudio` 等 HostBridge 受控导出能力进入系统分享 / 保存面板。
- 2026-06-18 移动壳 HostBridge 消息来源校验:Expo 移动壳 `onMessage` 必须根据 `event.nativeEvent.url` 校验消息来源,只有同源主站页面能进入 `handleMobileHostBridgeMessage`;`about:blank`、外域、协议降级和危险协议页面消息直接丢弃,不返回宿主能力错误细节。该规则与 WebView 导航留壳规则共用同源判断,配置检查和移动壳导航测试会拒绝移除。
-- 2026-06-18 三端桥接层目录同构:微信小程序、Expo 移动壳和 Tauri 桌面壳都按 `host-bridge / shell` 两层管理宿主桥接代码。微信 `miniprogram/host-bridge/wechatHostBridge*.js` 只放协议归一、支付 / 订阅 / 分享结果编解码和可测试桥接函数,`miniprogram/shell/wechatShell*.js` 承接 Page 生命周期、`wx.*` 容器调用、WebView 容器行为和页面工厂;页面目录只保留 `Page(createWechat...Page())` 装配。Expo `mobileHostBridgeProtocol.ts`、`mobileHostBridgeFiles.ts`、`mobileHostBridgeShare.ts` 和 facade `mobileHostBridge.ts` 分别对齐 Tauri `host_bridge/protocol.rs`、`files.rs`、`share.rs`、`mod.rs`,根 `App.tsx` 只装配 `src/shell/MobileShellApp.tsx`,不直接进口 HostBridge。Tauri `shell/deep_link.rs`、`shell/tray.rs`、`shell/webview.rs` 分别承接深链、托盘和 WebView 容器行为。`npm run check:native-shells` 会校验微信、移动和桌面三端目录清单,新增宿主能力必须按同一边界落文件和测试。
+- 2026-06-18 三端桥接层目录同构:微信小程序、Expo 移动壳和 Tauri 桌面壳都按 `host-bridge / shell` 两层管理宿主桥接代码。微信 `miniprogram/host-bridge/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js` 只放协议归一、支付 / 订阅 / 分享结果编解码和可测试桥接函数,`miniprogram/shell/` 下同名职责文件承接 Page 生命周期、`wx.*` 容器调用、WebView 容器行为和页面工厂;页面目录只保留 `Page(createWechat...Page())` 装配。Expo `protocol.ts`、`files.ts`、`share.ts` 和 facade `bridge.ts` 分别对齐 Tauri `host_bridge/protocol.rs`、`files.rs`、`share.rs`、`mod.rs`,根 `App.tsx` 只装配 `src/shell/ShellApp.tsx`,不直接进口 HostBridge。Tauri `shell/deep_link.rs`、`shell/tray.rs`、`shell/webview.rs` 分别承接深链、托盘和 WebView 容器行为。`npm run check:native-shells` 会校验微信、移动和桌面三端目录清单,新增宿主能力必须按同一边界落文件和测试。
- 影响范围:`src/services/host-bridge/`、未来 `apps/mobile-shell/`、未来 `apps/desktop-shell/`、移动端支付 / 分享 / 深链 / 推送、桌面端系统能力、AI H5 sandbox 的 GameBridge 边界。
- 验证方式:普通浏览器、小程序、Expo 壳、Tauri 壳都能返回正确 `getHostRuntime()`;未支持能力能回退 H5;固定玩法在各宿主中读取同一作品数据和运行态 snapshot;AI sandbox 无法直接调用 HostBridge;Tauri release 不允许任意远端页面调用桌面命令。
- 关联文档:`docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md`、`docs/【前端架构】宿主壳能力统一协议-2026-06-17.md`。
@@ -2399,14 +2399,14 @@
- 背景:H5 transport 会为每个 HostBridge 请求生成 id 并设置超时,但系统分享、外链打开、文件选择 / 保存、本地通知和窗口导航等宿主副作用如果收到重复 id,不应因为消息重试、快速双发或 WebView 事件抖动被执行两次。
- 决策:Expo 移动壳缓存已完成响应,并让进行中的同 id 请求共用同一个执行 Promise;Tauri 桌面壳在唯一 `host_bridge_request` command 外层通过 `HostBridgeReplayState` 让同 id 请求等待 / 回放首次结果。重复 id 只返回首次响应,不二次执行宿主能力。
-- 影响范围:`apps/mobile-shell/src/host-bridge/mobileHostBridge.ts`、`apps/desktop-shell/src-tauri/src/host_bridge/`、`apps/desktop-shell/src-tauri/src/main.rs`、两端配置检查、Expo / Tauri HostBridge 方案文档。
+- 影响范围:`apps/mobile-shell/src/host-bridge/bridge.ts`、`apps/desktop-shell/src-tauri/src/host_bridge/`、`apps/desktop-shell/src-tauri/src/main.rs`、两端配置检查、Expo / Tauri HostBridge 方案文档。
- 验证方式:`npm run check:native-shells`、`npm run typecheck`、`npm run check:encoding`、`git diff --check`。
## 2026-06-18 HostBridge request envelope 校验
- 背景:HostBridge 请求来自 H5 WebView / Tauri 注入通道,TypeScript 类型不能替代宿主运行时校验;空 id、控制字符 id、过长 id 或未知 method 如果进入 replay / 能力分发,可能污染缓存、绕过方法白名单或造成错误语义混乱。
- 决策:共享契约提供 `isHostBridgeMethod` 和 `normalizeHostBridgeRequestId`;Expo 壳直接复用,Tauri 壳镜像同一 `HOST_BRIDGE_METHODS` 和 request id 规则。request id 归一后必须为 1-120 字符且不含控制字符;未知 method 在进入能力分发前返回 `invalid_request`,只有白名单内但当前壳未实现的登录 / 支付等 method 返回 `unsupported_method`。
-- 影响范围:`packages/shared/src/contracts/hostBridge.ts`、`apps/mobile-shell/src/host-bridge/mobileHostBridge.ts`、`apps/desktop-shell/src-tauri/src/host_bridge/`、`apps/desktop-shell/src-tauri/src/main.rs`、两端配置检查、Expo / Tauri HostBridge 方案文档。
+- 影响范围:`packages/shared/src/contracts/hostBridge.ts`、`apps/mobile-shell/src/host-bridge/bridge.ts`、`apps/desktop-shell/src-tauri/src/host_bridge/`、`apps/desktop-shell/src-tauri/src/main.rs`、两端配置检查、Expo / Tauri HostBridge 方案文档。
- 验证方式:`npm run check:native-shells`、`npm run typecheck`、`npm run check:encoding`、`git diff --check`。
## 2026-06-18 HostBridge method 白名单跨壳门禁
@@ -2475,6 +2475,6 @@
## 2026-06-18 三端宿主桥接层文件结构对齐
- 背景:微信小程序壳、Expo 移动壳和 Tauri 桌面壳都在承接宿主能力;如果微信页面继续散落 `index.shared.js`,桌面端继续把桥接分发堆在 `main.rs`,后续新增登录、支付、文件、通知或 sandbox 转发能力时会很难跨端对照 owner。
-- 决策:三端桥接层按职责对齐。微信小程序页面路由不改,但可测试桥接逻辑统一放到 `miniprogram/host-bridge/wechatHostBridge*.js`,页面目录只保留生命周期和装配;Expo 移动壳拆成 `apps/mobile-shell/src/host-bridge/mobileHostBridgeProtocol.ts`、`mobileHostBridgeFiles.ts`、`mobileHostBridgeShare.ts` 和 facade `mobileHostBridge.ts`,分别负责协议 / 能力清单 / request 校验 / replay 基础、文件能力、分享能力和 method 分发,根 `App.tsx` 只装配 `apps/mobile-shell/src/shell/MobileShellApp.tsx`,`apps/mobile-shell/src/shell/mobileShell*.ts(x)` 负责 WebView 容器、URL、导航、网络、生命周期、安全区和 WebView policy;Tauri 桌面壳拆成 `apps/desktop-shell/src-tauri/src/host_bridge/*.rs` 与 `apps/desktop-shell/src-tauri/src/shell/*.rs`,其中 deep link、tray、webview 分文件承接容器行为,`main.rs` 只做 builder、plugin、窗口和状态装配。`scripts/check-native-shells.mjs` 锁定三端桥接层目录清单,并拒绝移动根入口直接引用 HostBridge。
+- 决策:三端桥接层按职责对齐。微信小程序页面路由不改,但可测试桥接逻辑统一放到 `miniprogram/host-bridge/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js`,页面目录只保留生命周期和装配;Expo 移动壳拆成 `apps/mobile-shell/src/host-bridge/protocol.ts`、`files.ts`、`share.ts` 和 facade `bridge.ts`,分别负责协议 / 能力清单 / request 校验 / replay 基础、文件能力、分享能力和 method 分发,根 `App.tsx` 只装配 `apps/mobile-shell/src/shell/ShellApp.tsx`,`apps/mobile-shell/src/shell/*.ts(x)` 负责 WebView 容器、URL、导航、网络、生命周期、安全区和 WebView policy;Tauri 桌面壳拆成 `apps/desktop-shell/src-tauri/src/host_bridge/*.rs` 与 `apps/desktop-shell/src-tauri/src/shell/*.rs`,其中 deep link、tray、webview 分文件承接容器行为,`main.rs` 只做 builder、plugin、窗口和状态装配。`scripts/check-native-shells.mjs` 锁定三端桥接层目录清单,并拒绝移动根入口直接引用 HostBridge。
- 影响范围:`miniprogram/host-bridge/`、`miniprogram/pages/*/index.js`、`apps/mobile-shell/src/`、`apps/desktop-shell/src-tauri/src/`、`scripts/check-native-shells.mjs`、宿主壳方案文档。
-- 验证方式:`npm run test -- miniprogram/host-bridge/wechatHostBridgeWebView.test.js miniprogram/host-bridge/wechatHostBridgePayment.test.js miniprogram/host-bridge/wechatHostBridgeShareGrid.test.js miniprogram/host-bridge/wechatHostBridgeSubscribeMessage.test.js miniprogram/pages/web-view/index.style.test.js`、`npm run check:native-shells`、`npm run typecheck`、`npm run check:encoding`、`git diff --check`。
+- 验证方式:`npm run test -- miniprogram/host-bridge/webView.test.js miniprogram/host-bridge/payment.test.js miniprogram/host-bridge/shareGrid.test.js miniprogram/host-bridge/subscribeMessage.test.js miniprogram/pages/web-view/index.style.test.js`、`npm run check:native-shells`、`npm run typecheck`、`npm run check:encoding`、`git diff --check`。
diff --git a/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md b/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md
index 7e16cb3c2..a02acb504 100644
--- a/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md
+++ b/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md
@@ -64,7 +64,7 @@ src/
已落地:`packages/shared/src/contracts/hostBridge.ts` 保存消息 envelope、method、payload 和错误码,H5、Expo 壳与 Tauri 壳共享同一份协议类型。
-三端宿主桥接层按职责对齐命名:微信小程序页面路由仍保留在 `miniprogram/pages/*`,协议归一、支付 / 订阅 / 分享结果编解码统一放在 `miniprogram/host-bridge/wechatHostBridge*.js`,Page 生命周期、`wx.*` 容器调用、WebView 容器行为和页面工厂统一放在 `miniprogram/shell/wechatShell*.js`,页面入口只做 `Page(createWechat...Page())` 装配;Expo 移动壳使用 `apps/mobile-shell/src/host-bridge/mobileHostBridgeProtocol.ts` 承接 envelope、能力清单、request 校验和 replay 基础,`mobileHostBridgeFiles.ts` / `mobileHostBridgeShare.ts` 分别承接文件和分享能力,`mobileHostBridge.ts` 只作为对外 facade 与 method 分发入口,`apps/mobile-shell/App.tsx` 只装配 `apps/mobile-shell/src/shell/MobileShellApp.tsx`,由 `apps/mobile-shell/src/shell/mobileShell*.ts(x)` 承接 WebView 容器、URL、导航、网络、生命周期、安全区和 WebView policy;Tauri 桌面壳使用 `apps/desktop-shell/src-tauri/src/host_bridge/protocol.rs`、`files.rs`、`share.rs` 和 `mod.rs` 承接协议、文件、分享和分发,`apps/desktop-shell/src-tauri/src/shell/*.rs` 承接 WebView、托盘和容器行为,`main.rs` 只保留 Tauri builder / plugin / window 装配。
+三端宿主桥接层按职责对齐命名:微信小程序页面路由仍保留在 `miniprogram/pages/*`,协议归一、支付 / 订阅 / 分享结果编解码统一放在 `miniprogram/host-bridge/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js`,Page 生命周期、`wx.*` 容器调用、WebView 容器行为和页面工厂统一放在 `miniprogram/shell/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js`,页面入口只做 `Page(createWechat...Page())` 装配;Expo 移动壳使用 `apps/mobile-shell/src/host-bridge/protocol.ts` 承接 envelope、能力清单、request 校验和 replay 基础,`files.ts` / `share.ts` 分别承接文件和分享能力,`bridge.ts` 只作为对外 facade 与 method 分发入口,`apps/mobile-shell/App.tsx` 只装配 `apps/mobile-shell/src/shell/ShellApp.tsx`,由 `apps/mobile-shell/src/shell/*.ts(x)` 承接 WebView 容器、URL、导航、网络、生命周期、安全区和 WebView policy;Tauri 桌面壳使用 `apps/desktop-shell/src-tauri/src/host_bridge/protocol.rs`、`files.rs`、`share.rs` 和 `mod.rs` 承接协议、文件、分享和分发,`apps/desktop-shell/src-tauri/src/shell/*.rs` 承接 WebView、托盘和容器行为,`main.rs` 只保留 Tauri builder / plugin / window 装配。
## HostBridge 消息协议
@@ -312,7 +312,7 @@ GameBridge 禁止:
2026-06-18 追加:移动壳安装包身份固定为 `world.genarrative.mobile`。Expo `app.json` 中的 `ios.bundleIdentifier` 与 `android.package` 使用同一包标识,应用版本为 `0.1.0`,iOS `buildNumber` 从字符串 `"1"` 起步,Android `versionCode` 从整数 `1` 起步;后续每次生成可分发安装包时只递增构建号 / versionCode,产品版本号按发布节奏单独调整。`apps/mobile-shell/scripts/check-config.mjs` 会校验这些字段与 `package.json` 版本一致,避免 iOS、Android 和 H5 HostBridge `hostVersion` 发生静默漂移;`npm run mobile-shell:config` 会调用真实 Expo CLI 解析 public managed config,确认最终 Expo 配置仍保留同一包身份、深链、安全字段、插件权限和 HostBridge 版本。当前仍不写入假商店上架信息、假更新端点或占位渠道 SDK 配置。
-2026-06-18 追加:移动壳 H5 入口 query 和 `host.getRuntime` 回包统一读取 `MOBILE_SHELL_HOST_VERSION`,该常量必须与 Expo `app.json` / `package.json` 版本一致。配置检查会拒绝在 `apps/mobile-shell/src/shell/MobileShellApp.tsx` 或 `apps/mobile-shell/src/host-bridge/mobileHostBridge.ts` 内重新散落硬编码版本,避免升级移动安装包时 H5 首屏上下文和宿主 runtime 回读版本不一致。
+2026-06-18 追加:移动壳 H5 入口 query 和 `host.getRuntime` 回包统一读取 `MOBILE_SHELL_HOST_VERSION`,该常量必须与 Expo `app.json` / `package.json` 版本一致。配置检查会拒绝在 `apps/mobile-shell/src/shell/ShellApp.tsx` 或 `apps/mobile-shell/src/host-bridge/bridge.ts` 内重新散落硬编码版本,避免升级移动安装包时 H5 首屏上下文和宿主 runtime 回读版本不一致。
2026-06-18 追加:移动壳默认显式关闭 Expo OTA 更新,直到存在真实发布通道、更新端点、签名 / 回滚策略和团队发布流程后再接入。`app.json` 只允许 `updates.enabled=false`,不得配置 `runtimeVersion`、release channel、EAS channel、`expo-updates` 插件或移动端 crash / analytics / CodePush 依赖;`apps/mobile-shell/scripts/check-config.mjs` 和 Expo public config smoke 会共同拒绝这些发布通道能力被提前打开,移动壳生产入口、HostBridge 和 URL/runtime 配置也不得提前初始化 Sentry、Firebase Analytics、PostHog、Amplitude、Segment、CodePush 或 Expo Updates。由于移动壳运行依赖会从根安装树解析,根 H5 `package.json` 也不得直接安装这些移动端发布通道、崩溃上报、analytics 或 CodePush SDK;根 `package-lock.json` 也不得解析 `expo-updates`、Sentry、Firebase Analytics、PostHog、Amplitude、Segment、CodePush 等真实发布 / 观测 SDK。`expo-application` 可能由 Expo 自身传递解析,但项目不得把它作为 direct dependency 主动用于渠道逻辑。
@@ -409,13 +409,13 @@ GameBridge 禁止:
2026-06-18 追加:移动壳 Android 自动备份显式关闭。Expo `android.allowBackup=false`,避免 WebView cookie、localStorage、缓存文件、系统剪贴板导入中间文件等本地宿主状态进入 Google Drive 自动备份 / 恢复链路;正式业务事实仍以后端账号、作品、钱包和草稿状态为准,不依赖设备备份恢复。`apps/mobile-shell/scripts/check-config.mjs` 会拒绝恢复默认允许备份的 Android 包配置。
-2026-06-18 追加:移动壳 WebView 原生安全开关显式收紧。`react-native-webview` 只加载同源主站入口,保留 JS 和 DOM storage 以运行现有 H5,但禁用 JS 自动开窗、多窗口、文件访问、file URL 跨源访问、HTTPS 页面加载 HTTP 混合内容、第三方 Cookie、共享 Cookie 和 WebView 远程调试;外链继续只允许 `http:`、`https:`、`mailto:`、`tel:` 离开 WebView 交给系统。`apps/mobile-shell/scripts/check-config.mjs` 和 `mobileShellNavigation.test.ts` 会覆盖这些壳边界,避免后续为单个页面调试把完整 HostBridge 暴露给外域页面。
+2026-06-18 追加:移动壳 WebView 原生安全开关显式收紧。`react-native-webview` 只加载同源主站入口,保留 JS 和 DOM storage 以运行现有 H5,但禁用 JS 自动开窗、多窗口、文件访问、file URL 跨源访问、HTTPS 页面加载 HTTP 混合内容、第三方 Cookie、共享 Cookie 和 WebView 远程调试;外链继续只允许 `http:`、`https:`、`mailto:`、`tel:` 离开 WebView 交给系统。`apps/mobile-shell/scripts/check-config.mjs` 和 `navigation.test.ts` 会覆盖这些壳边界,避免后续为单个页面调试把完整 HostBridge 暴露给外域页面。
2026-06-18 追加:移动壳 WebView 默认下载路径显式关闭。壳层在 WebView 注入脚本中阻断 `` 点击,iOS `onFileDownload` 事件只丢弃不落盘,Android 包配置阻断外部存储读写、管理外部存储和请求安装包权限;H5 文本、图片、音频保存继续只能走 `file.exportText`、`file.exportImage`、`file.exportAudio` 的受控 HostBridge 导出能力。
2026-06-18 追加:移动壳 HostBridge 消息入口增加来源校验。`onMessage` 不只依赖导航拦截和 `originWhitelist`,还会读取 `event.nativeEvent.url`,只有同源主站页面才能进入 `handleMobileHostBridgeMessage`;`about:blank`、外域 URL、协议降级或危险协议页面发来的消息全部丢弃,不返回 HostBridge 错误细节。该校验与 `navigation.openNativePage` 共用同源规则,防止历史中间页或异常页面在带完整 HostBridge 的 WebView 中发起宿主能力请求。
-2026-06-18 追加:微信、移动端和桌面端桥接层文件结构按职责对齐。微信小程序的 `web-view`、支付、九宫切图和订阅消息桥接逻辑统一迁入 `miniprogram/host-bridge/wechatHostBridge*.js`,页面目录只保留页面生命周期、WXML/WXSS 和装配;移动壳拆成 `apps/mobile-shell/src/host-bridge/mobileHostBridgeProtocol.ts`、`mobileHostBridgeFiles.ts`、`mobileHostBridgeShare.ts` 和 facade `mobileHostBridge.ts`,与桌面端 `host_bridge/protocol.rs`、`files.rs`、`share.rs`、`mod.rs` 对齐;移动壳根 `App.tsx` 也保持薄入口,只装配 `src/shell/MobileShellApp.tsx`,WebView 容器、深链、网络、生命周期和安全策略全部留在 `src/shell/`;桌面壳 Rust 源码拆成 `apps/desktop-shell/src-tauri/src/host_bridge/*.rs` 与 `apps/desktop-shell/src-tauri/src/shell/*.rs`,其中 `shell/deep_link.rs`、`shell/tray.rs`、`shell/webview.rs` 分别承接深链、托盘和 WebView 容器行为,薄 `main.rs` 只声明两个模块并装配 Tauri builder / plugin / window。根级 `npm run check:native-shells` 会锁定三端桥接层目录清单,避免后续把能力逻辑重新散落到页面、移动入口或桌面入口。
+2026-06-18 追加:微信、移动端和桌面端桥接层文件结构按职责对齐。微信小程序的 `web-view`、支付、九宫切图和订阅消息桥接逻辑统一迁入 `miniprogram/host-bridge/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js`,页面目录只保留页面生命周期、WXML/WXSS 和装配;移动壳拆成 `apps/mobile-shell/src/host-bridge/protocol.ts`、`files.ts`、`share.ts` 和 facade `bridge.ts`,与桌面端 `host_bridge/protocol.rs`、`files.rs`、`share.rs`、`mod.rs` 对齐;移动壳根 `App.tsx` 也保持薄入口,只装配 `src/shell/ShellApp.tsx`,WebView 容器、深链、网络、生命周期和安全策略全部留在 `src/shell/`;桌面壳 Rust 源码拆成 `apps/desktop-shell/src-tauri/src/host_bridge/*.rs` 与 `apps/desktop-shell/src-tauri/src/shell/*.rs`,其中 `shell/deep_link.rs`、`shell/tray.rs`、`shell/webview.rs` 分别承接深链、托盘和 WebView 容器行为,薄 `main.rs` 只声明两个模块并装配 Tauri builder / plugin / window。根级 `npm run check:native-shells` 会锁定三端桥接层目录清单,避免后续把能力逻辑重新散落到页面、移动入口或桌面入口。
### Phase 4:宿主能力扩展
diff --git a/docs/【前端架构】宿主壳能力统一协议-2026-06-17.md b/docs/【前端架构】宿主壳能力统一协议-2026-06-17.md
index 4f1b70458..c69353fcb 100644
--- a/docs/【前端架构】宿主壳能力统一协议-2026-06-17.md
+++ b/docs/【前端架构】宿主壳能力统一协议-2026-06-17.md
@@ -37,7 +37,7 @@ AI H5 sandbox
-> parent HostBridge adapter
```
-桥接层文件结构按宿主统一为“协议 / 分发 / 宿主容器行为”三类职责。微信小程序的协议与可测试桥接函数统一放在 `miniprogram/host-bridge/wechatHostBridge*.js`,`miniprogram/shell/wechatShell*.js` 承接 Page 生命周期、`wx.*` 容器调用、WebView 容器行为、支付页和订阅页装配,页面目录只保留 `Page(createWechat...Page())` 装配;Expo 移动壳使用 `apps/mobile-shell/src/host-bridge/mobileHostBridgeProtocol.ts` 承接 envelope、能力清单、request 校验和 replay 基础,`mobileHostBridgeFiles.ts` / `mobileHostBridgeShare.ts` 分别承接文件和分享能力,`mobileHostBridge.ts` 只作为对外 facade 与 method 分发入口,`apps/mobile-shell/App.tsx` 只装配 `apps/mobile-shell/src/shell/MobileShellApp.tsx`,由 `apps/mobile-shell/src/shell/mobileShell*.ts(x)` 承接 WebView 容器、URL、导航、网络、生命周期、安全区和 WebView policy;Tauri 桌面壳使用 `apps/desktop-shell/src-tauri/src/host_bridge/protocol.rs`、`files.rs`、`share.rs` 和 `mod.rs` 承接协议、文件、分享和分发,`apps/desktop-shell/src-tauri/src/shell/*.rs` 承接 WebView、托盘和容器行为,`main.rs` 只保留 Tauri builder / plugin / window 装配。`npm run check:native-shells` 会检查这些目录清单。
+桥接层文件结构按宿主统一为“协议 / 分发 / 宿主容器行为”三类职责。微信小程序的协议与可测试桥接函数统一放在 `miniprogram/host-bridge/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js`,`miniprogram/shell/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js` 承接 Page 生命周期、`wx.*` 容器调用、WebView 容器行为、支付页和订阅页装配,页面目录只保留 `Page(createWechat...Page())` 装配;Expo 移动壳使用 `apps/mobile-shell/src/host-bridge/protocol.ts` 承接 envelope、能力清单、request 校验和 replay 基础,`files.ts` / `share.ts` 分别承接文件和分享能力,`bridge.ts` 只作为对外 facade 与 method 分发入口,`apps/mobile-shell/App.tsx` 只装配 `apps/mobile-shell/src/shell/ShellApp.tsx`,由 `apps/mobile-shell/src/shell/*.ts(x)` 承接 WebView 容器、URL、导航、网络、生命周期、安全区和 WebView policy;Tauri 桌面壳使用 `apps/desktop-shell/src-tauri/src/host_bridge/protocol.rs`、`files.rs`、`share.rs` 和 `mod.rs` 承接协议、文件、分享和分发,`apps/desktop-shell/src-tauri/src/shell/*.rs` 承接 WebView、托盘和容器行为,`main.rs` 只保留 Tauri builder / plugin / window 装配。`npm run check:native-shells` 会检查这些目录清单。
## 首批能力
diff --git a/miniprogram/host-bridge/wechatHostBridgePayment.js b/miniprogram/host-bridge/payment.js
similarity index 100%
rename from miniprogram/host-bridge/wechatHostBridgePayment.js
rename to miniprogram/host-bridge/payment.js
diff --git a/miniprogram/host-bridge/wechatHostBridgePayment.test.js b/miniprogram/host-bridge/payment.test.js
similarity index 99%
rename from miniprogram/host-bridge/wechatHostBridgePayment.test.js
rename to miniprogram/host-bridge/payment.test.js
index 21dbfa0e7..3cb7f2a2f 100644
--- a/miniprogram/host-bridge/wechatHostBridgePayment.test.js
+++ b/miniprogram/host-bridge/payment.test.js
@@ -6,7 +6,7 @@ import { loadCommonJsModule } from '../test-utils/loadCommonJsModule.js';
const payBridgePath = path.resolve(
process.cwd(),
- 'miniprogram/host-bridge/wechatHostBridgePayment.js',
+ 'miniprogram/host-bridge/payment.js',
);
describe('wechat-pay mini program payment bridge', () => {
diff --git a/miniprogram/host-bridge/wechatHostBridgeShareGrid.js b/miniprogram/host-bridge/shareGrid.js
similarity index 100%
rename from miniprogram/host-bridge/wechatHostBridgeShareGrid.js
rename to miniprogram/host-bridge/shareGrid.js
diff --git a/miniprogram/host-bridge/wechatHostBridgeShareGrid.test.js b/miniprogram/host-bridge/shareGrid.test.js
similarity index 96%
rename from miniprogram/host-bridge/wechatHostBridgeShareGrid.test.js
rename to miniprogram/host-bridge/shareGrid.test.js
index 5002fef2f..201d07f2a 100644
--- a/miniprogram/host-bridge/wechatHostBridgeShareGrid.test.js
+++ b/miniprogram/host-bridge/shareGrid.test.js
@@ -1,6 +1,6 @@
import { describe, expect, test } from 'vitest';
-import shareGridBridge from './wechatHostBridgeShareGrid.js';
+import shareGridBridge from './shareGrid.js';
const {
buildShareGridTileFileName,
diff --git a/miniprogram/host-bridge/wechatHostBridgeSubscribeMessage.js b/miniprogram/host-bridge/subscribeMessage.js
similarity index 100%
rename from miniprogram/host-bridge/wechatHostBridgeSubscribeMessage.js
rename to miniprogram/host-bridge/subscribeMessage.js
diff --git a/miniprogram/host-bridge/wechatHostBridgeSubscribeMessage.test.js b/miniprogram/host-bridge/subscribeMessage.test.js
similarity index 98%
rename from miniprogram/host-bridge/wechatHostBridgeSubscribeMessage.test.js
rename to miniprogram/host-bridge/subscribeMessage.test.js
index 2db75b73c..ef96a3dfd 100644
--- a/miniprogram/host-bridge/wechatHostBridgeSubscribeMessage.test.js
+++ b/miniprogram/host-bridge/subscribeMessage.test.js
@@ -8,7 +8,7 @@ const TEST_TEMPLATE_ID = 'm5z7BkkBhJGbcH0cdDeHaeRU2tViDEguP38XdrRRCdU';
const subscribeBridgePath = path.resolve(
process.cwd(),
- 'miniprogram/host-bridge/wechatHostBridgeSubscribeMessage.js',
+ 'miniprogram/host-bridge/subscribeMessage.js',
);
describe('subscribe-message mini program bridge', () => {
diff --git a/miniprogram/host-bridge/wechatHostBridgeWebView.js b/miniprogram/host-bridge/webView.js
similarity index 100%
rename from miniprogram/host-bridge/wechatHostBridgeWebView.js
rename to miniprogram/host-bridge/webView.js
diff --git a/miniprogram/host-bridge/wechatHostBridgeWebView.test.js b/miniprogram/host-bridge/webView.test.js
similarity index 98%
rename from miniprogram/host-bridge/wechatHostBridgeWebView.test.js
rename to miniprogram/host-bridge/webView.test.js
index 6790fd020..619c76485 100644
--- a/miniprogram/host-bridge/wechatHostBridgeWebView.test.js
+++ b/miniprogram/host-bridge/webView.test.js
@@ -1,6 +1,6 @@
import { describe, expect, test } from 'vitest';
-import webViewBridge from './wechatHostBridgeWebView.js';
+import webViewBridge from './webView.js';
const {
appendLaunchTargetToEntryUrl,
diff --git a/miniprogram/pages/share-grid/index.js b/miniprogram/pages/share-grid/index.js
index 79e22a6e1..d0b7d53df 100644
--- a/miniprogram/pages/share-grid/index.js
+++ b/miniprogram/pages/share-grid/index.js
@@ -1,5 +1,5 @@
/* global Page */
-const { createWechatShareGridPage } = require('../../shell/wechatShellShareGrid');
+const { createWechatShareGridPage } = require('../../shell/shareGrid');
Page(createWechatShareGridPage());
diff --git a/miniprogram/pages/subscribe-message/index.js b/miniprogram/pages/subscribe-message/index.js
index bd6c9d521..ad5eafa68 100644
--- a/miniprogram/pages/subscribe-message/index.js
+++ b/miniprogram/pages/subscribe-message/index.js
@@ -3,7 +3,7 @@
const { GENERATION_RESULT_SUBSCRIBE_TEMPLATE_ID } = require('../../config');
const {
createSubscribeMessagePage,
-} = require('../../shell/wechatShellSubscribeMessage');
+} = require('../../shell/subscribeMessage');
Page(
createSubscribeMessagePage(null, {
diff --git a/miniprogram/pages/web-view/index.js b/miniprogram/pages/web-view/index.js
index 273d2bb03..1456274e4 100644
--- a/miniprogram/pages/web-view/index.js
+++ b/miniprogram/pages/web-view/index.js
@@ -1,5 +1,5 @@
/* global Page */
-const { createWechatWebViewPage } = require('../../shell/wechatShellWebView');
+const { createWechatWebViewPage } = require('../../shell/webView');
Page(createWechatWebViewPage());
diff --git a/miniprogram/pages/wechat-pay/index.js b/miniprogram/pages/wechat-pay/index.js
index 8006a204c..02b691b3e 100644
--- a/miniprogram/pages/wechat-pay/index.js
+++ b/miniprogram/pages/wechat-pay/index.js
@@ -1,5 +1,5 @@
/* global Page */
-const { createWechatPayPage } = require('../../shell/wechatShellPayment');
+const { createWechatPayPage } = require('../../shell/payment');
Page(createWechatPayPage());
diff --git a/miniprogram/shell/wechatShellPayment.js b/miniprogram/shell/payment.js
similarity index 94%
rename from miniprogram/shell/wechatShellPayment.js
rename to miniprogram/shell/payment.js
index 8f51aa5a2..d1065adf1 100644
--- a/miniprogram/shell/wechatShellPayment.js
+++ b/miniprogram/shell/payment.js
@@ -4,7 +4,7 @@ const {
notifyPreviousWebView,
parsePayParams,
requestWechatPayment,
-} = require('../host-bridge/wechatHostBridgePayment');
+} = require('../host-bridge/payment');
function createWechatPayPage(pageContext) {
return {
diff --git a/miniprogram/shell/wechatShellPayment.test.js b/miniprogram/shell/payment.test.js
similarity index 92%
rename from miniprogram/shell/wechatShellPayment.test.js
rename to miniprogram/shell/payment.test.js
index 603b592ca..295d6d213 100644
--- a/miniprogram/shell/wechatShellPayment.test.js
+++ b/miniprogram/shell/payment.test.js
@@ -6,11 +6,11 @@ import { loadCommonJsModule } from '../test-utils/loadCommonJsModule.js';
const payBridgePath = path.resolve(
process.cwd(),
- 'miniprogram/host-bridge/wechatHostBridgePayment.js',
+ 'miniprogram/host-bridge/payment.js',
);
const paymentShellPath = path.resolve(
process.cwd(),
- 'miniprogram/shell/wechatShellPayment.js',
+ 'miniprogram/shell/payment.js',
);
describe('wechat payment shell page', () => {
@@ -27,7 +27,7 @@ describe('wechat payment shell page', () => {
globalThis.getCurrentPages = vi.fn(() => []);
const wechatPayBridge = loadCommonJsModule(payBridgePath);
const wechatPaymentShell = loadCommonJsModule(paymentShellPath, {
- '../host-bridge/wechatHostBridgePayment': wechatPayBridge,
+ '../host-bridge/payment': wechatPayBridge,
});
createWechatPayPage = wechatPaymentShell.createWechatPayPage;
});
diff --git a/miniprogram/shell/wechatShellShareGrid.js b/miniprogram/shell/shareGrid.js
similarity index 98%
rename from miniprogram/shell/wechatShellShareGrid.js
rename to miniprogram/shell/shareGrid.js
index 562b5b67e..2a02c9625 100644
--- a/miniprogram/shell/wechatShellShareGrid.js
+++ b/miniprogram/shell/shareGrid.js
@@ -5,7 +5,7 @@ const {
buildShareGridTileFileName,
buildShareGridTilePlan,
normalizeShareGridQuery,
-} = require('../host-bridge/wechatHostBridgeShareGrid');
+} = require('../host-bridge/shareGrid');
function downloadImage(imageUrl) {
return new Promise((resolve, reject) => {
diff --git a/miniprogram/shell/wechatShellShareGrid.test.js b/miniprogram/shell/shareGrid.test.js
similarity index 86%
rename from miniprogram/shell/wechatShellShareGrid.test.js
rename to miniprogram/shell/shareGrid.test.js
index 1a64c48c3..7ea62e7a8 100644
--- a/miniprogram/shell/wechatShellShareGrid.test.js
+++ b/miniprogram/shell/shareGrid.test.js
@@ -6,11 +6,11 @@ import { loadCommonJsModule } from '../test-utils/loadCommonJsModule.js';
const shareGridBridgePath = path.resolve(
process.cwd(),
- 'miniprogram/host-bridge/wechatHostBridgeShareGrid.js',
+ 'miniprogram/host-bridge/shareGrid.js',
);
const shareGridShellPath = path.resolve(
process.cwd(),
- 'miniprogram/shell/wechatShellShareGrid.js',
+ 'miniprogram/shell/shareGrid.js',
);
let createWechatShareGridPage;
@@ -33,7 +33,7 @@ describe('wechat share-grid shell page', () => {
};
const shareGridBridge = loadCommonJsModule(shareGridBridgePath);
const shareGridShell = loadCommonJsModule(shareGridShellPath, {
- '../host-bridge/wechatHostBridgeShareGrid': shareGridBridge,
+ '../host-bridge/shareGrid': shareGridBridge,
});
createWechatShareGridPage = shareGridShell.createWechatShareGridPage;
});
diff --git a/miniprogram/shell/wechatShellSubscribeMessage.js b/miniprogram/shell/subscribeMessage.js
similarity index 78%
rename from miniprogram/shell/wechatShellSubscribeMessage.js
rename to miniprogram/shell/subscribeMessage.js
index 9973fc64d..f456b3474 100644
--- a/miniprogram/shell/wechatShellSubscribeMessage.js
+++ b/miniprogram/shell/subscribeMessage.js
@@ -1,6 +1,6 @@
const {
createSubscribeMessagePageController,
-} = require('../host-bridge/wechatHostBridgeSubscribeMessage');
+} = require('../host-bridge/subscribeMessage');
function createSubscribeMessagePage(pageContext, options = {}) {
return createSubscribeMessagePageController(pageContext, options);
diff --git a/miniprogram/shell/wechatShellSubscribeMessage.test.js b/miniprogram/shell/subscribeMessage.test.js
similarity index 89%
rename from miniprogram/shell/wechatShellSubscribeMessage.test.js
rename to miniprogram/shell/subscribeMessage.test.js
index 911b7c65d..8a2291ce8 100644
--- a/miniprogram/shell/wechatShellSubscribeMessage.test.js
+++ b/miniprogram/shell/subscribeMessage.test.js
@@ -8,11 +8,11 @@ const TEST_TEMPLATE_ID = 'm5z7BkkBhJGbcH0cdDeHaeRU2tViDEguP38XdrRRCdU';
const subscribeBridgePath = path.resolve(
process.cwd(),
- 'miniprogram/host-bridge/wechatHostBridgeSubscribeMessage.js',
+ 'miniprogram/host-bridge/subscribeMessage.js',
);
const subscribeShellPath = path.resolve(
process.cwd(),
- 'miniprogram/shell/wechatShellSubscribeMessage.js',
+ 'miniprogram/shell/subscribeMessage.js',
);
describe('wechat subscribe-message shell page', () => {
@@ -26,7 +26,7 @@ describe('wechat subscribe-message shell page', () => {
};
const subscribeMessageBridge = loadCommonJsModule(subscribeBridgePath);
const subscribeMessageShell = loadCommonJsModule(subscribeShellPath, {
- '../host-bridge/wechatHostBridgeSubscribeMessage': subscribeMessageBridge,
+ '../host-bridge/subscribeMessage': subscribeMessageBridge,
});
createSubscribeMessagePage =
subscribeMessageShell.createSubscribeMessagePage;
diff --git a/miniprogram/shell/wechatShellWebView.js b/miniprogram/shell/webView.js
similarity index 99%
rename from miniprogram/shell/wechatShellWebView.js
rename to miniprogram/shell/webView.js
index b0ccaeb79..fe8f8d489 100644
--- a/miniprogram/shell/wechatShellWebView.js
+++ b/miniprogram/shell/webView.js
@@ -16,7 +16,7 @@ const {
buildWebViewShareTimelineQuery,
resolveShareTargetFromWebViewMessage,
resolveWebViewUrlFromRuntimeConfig,
-} = require('../host-bridge/wechatHostBridgeWebView');
+} = require('../host-bridge/webView');
const MINI_PROGRAM_CLIENT_TYPE = 'mini_program';
const MINI_PROGRAM_CLIENT_RUNTIME = 'wechat_mini_program';
diff --git a/miniprogram/shell/wechatShellWebView.test.js b/miniprogram/shell/webView.test.js
similarity index 94%
rename from miniprogram/shell/wechatShellWebView.test.js
rename to miniprogram/shell/webView.test.js
index e193c45f0..242a220cb 100644
--- a/miniprogram/shell/wechatShellWebView.test.js
+++ b/miniprogram/shell/webView.test.js
@@ -6,11 +6,11 @@ import { loadCommonJsModule } from '../test-utils/loadCommonJsModule.js';
const webViewBridgePath = path.resolve(
process.cwd(),
- 'miniprogram/host-bridge/wechatHostBridgeWebView.js',
+ 'miniprogram/host-bridge/webView.js',
);
const webViewShellPath = path.resolve(
process.cwd(),
- 'miniprogram/shell/wechatShellWebView.js',
+ 'miniprogram/shell/webView.js',
);
const config = {
API_BASE_URL: 'https://www.genarrative.world',
@@ -56,7 +56,7 @@ describe('wechat web-view shell page', () => {
const webViewBridge = loadCommonJsModule(webViewBridgePath);
const webViewShell = loadCommonJsModule(webViewShellPath, {
'../config': config,
- '../host-bridge/wechatHostBridgeWebView': webViewBridge,
+ '../host-bridge/webView': webViewBridge,
});
createWechatWebViewPage = webViewShell.createWechatWebViewPage;
});
diff --git a/scripts/check-native-shells.mjs b/scripts/check-native-shells.mjs
index afa31b56e..afab7162b 100644
--- a/scripts/check-native-shells.mjs
+++ b/scripts/check-native-shells.mjs
@@ -8,49 +8,49 @@ const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
const productionShellRoots = ['apps/mobile-shell', 'apps/desktop-shell'];
const expectedWechatHostBridgeFiles = [
- 'wechatHostBridgePayment.js',
- 'wechatHostBridgePayment.test.js',
- 'wechatHostBridgeShareGrid.js',
- 'wechatHostBridgeShareGrid.test.js',
- 'wechatHostBridgeSubscribeMessage.js',
- 'wechatHostBridgeSubscribeMessage.test.js',
- 'wechatHostBridgeWebView.js',
- 'wechatHostBridgeWebView.test.js',
+ 'payment.js',
+ 'payment.test.js',
+ 'shareGrid.js',
+ 'shareGrid.test.js',
+ 'subscribeMessage.js',
+ 'subscribeMessage.test.js',
+ 'webView.js',
+ 'webView.test.js',
];
const expectedWechatShellFiles = [
- 'wechatShellPayment.js',
- 'wechatShellPayment.test.js',
- 'wechatShellShareGrid.js',
- 'wechatShellShareGrid.test.js',
- 'wechatShellSubscribeMessage.js',
- 'wechatShellSubscribeMessage.test.js',
- 'wechatShellWebView.js',
- 'wechatShellWebView.test.js',
+ 'payment.js',
+ 'payment.test.js',
+ 'shareGrid.js',
+ 'shareGrid.test.js',
+ 'subscribeMessage.js',
+ 'subscribeMessage.test.js',
+ 'webView.js',
+ 'webView.test.js',
];
const expectedMobileHostBridgeFiles = [
- 'mobileHostBridge.test.ts',
- 'mobileHostBridge.ts',
- 'mobileHostBridgeFiles.ts',
- 'mobileHostBridgeProtocol.ts',
- 'mobileHostBridgeShare.ts',
+ 'bridge.test.ts',
+ 'bridge.ts',
+ 'files.ts',
+ 'protocol.ts',
+ 'share.ts',
];
const expectedMobileShellFiles = [
- 'MobileShellApp.tsx',
- 'mobileShellDeepLink.test.ts',
- 'mobileShellDeepLink.ts',
- 'mobileShellLifecycle.test.ts',
- 'mobileShellLifecycle.ts',
- 'mobileShellNavigation.test.ts',
- 'mobileShellNavigation.ts',
- 'mobileShellNetwork.test.ts',
- 'mobileShellNetwork.ts',
- 'mobileShellRuntime.ts',
- 'mobileShellSafeArea.test.ts',
- 'mobileShellSafeArea.ts',
- 'mobileShellUrl.test.ts',
- 'mobileShellUrl.ts',
- 'mobileShellWebViewPolicy.test.ts',
- 'mobileShellWebViewPolicy.ts',
+ 'ShellApp.tsx',
+ 'deepLink.test.ts',
+ 'deepLink.ts',
+ 'lifecycle.test.ts',
+ 'lifecycle.ts',
+ 'navigation.test.ts',
+ 'navigation.ts',
+ 'network.test.ts',
+ 'network.ts',
+ 'runtime.ts',
+ 'safeArea.test.ts',
+ 'safeArea.ts',
+ 'url.test.ts',
+ 'url.ts',
+ 'webViewPolicy.test.ts',
+ 'webViewPolicy.ts',
];
const expectedDesktopHostBridgeRustFiles = [
'files.rs',
@@ -225,13 +225,13 @@ function assertHostBridgeLayerLayout() {
'wechat host bridge files',
);
- const wechatShellFiles = fs
+ const wechatShellLayerFiles = fs
.readdirSync('miniprogram/shell', { withFileTypes: true })
.filter((entry) => entry.isFile())
.map((entry) => entry.name)
.sort();
assertSameList(
- wechatShellFiles,
+ wechatShellLayerFiles,
expectedWechatShellFiles,
'wechat shell files',
);
@@ -266,19 +266,19 @@ function assertHostBridgeLayerLayout() {
'mobile host bridge files',
);
- const mobileShellFiles = fs
+ const mobileShellLayerFiles = fs
.readdirSync('apps/mobile-shell/src/shell', { withFileTypes: true })
.filter((entry) => entry.isFile())
.map((entry) => entry.name)
.sort();
assertSameList(
- mobileShellFiles,
+ mobileShellLayerFiles,
expectedMobileShellFiles,
'mobile shell bridge files',
);
const mobileAppSource = fs.readFileSync('apps/mobile-shell/App.tsx', 'utf8');
- if (!mobileAppSource.includes("import MobileShellApp from './src/shell/MobileShellApp';")) {
+ if (!mobileAppSource.includes("import ShellApp from './src/shell/ShellApp';")) {
throw new Error('mobile shell App.tsx must import from apps/mobile-shell/src/shell');
}
if (mobileAppSource.includes('./src/host-bridge/')) {
diff --git a/scripts/check-wechat-miniprogram-auth-smoke.mjs b/scripts/check-wechat-miniprogram-auth-smoke.mjs
index 7f7951a7a..5ca40df79 100644
--- a/scripts/check-wechat-miniprogram-auth-smoke.mjs
+++ b/scripts/check-wechat-miniprogram-auth-smoke.mjs
@@ -54,13 +54,13 @@ if (failures.length > 0) {
console.log('\n[wechat-miniprogram-auth-smoke] 通过');
function checkMiniProgramShell() {
- const shellPath = join(repoRoot, 'miniprogram', 'shell', 'wechatShellWebView.js');
- const webViewBridgePath = join(repoRoot, 'miniprogram', 'host-bridge', 'wechatHostBridgeWebView.js');
+ const shellPath = join(repoRoot, 'miniprogram', 'shell', 'webView.js');
+ const webViewBridgePath = join(repoRoot, 'miniprogram', 'host-bridge', 'webView.js');
const pagePath = join(repoRoot, 'miniprogram', 'pages', 'web-view', 'index.js');
const shellTemplatePath = join(repoRoot, 'miniprogram', 'pages', 'web-view', 'index.wxml');
const authServiceTestPath = join(repoRoot, 'src', 'services', 'authService.test.ts');
- ensureNeedles(pagePath, ["require('../../shell/wechatShellWebView')"]);
+ ensureNeedles(pagePath, ["require('../../shell/webView')"]);
ensureNeedles(shellPath, [
'/api/auth/wechat/miniprogram-login',
'/api/auth/wechat/bind-phone',
diff --git a/scripts/miniprogram-web-view-auth.test.ts b/scripts/miniprogram-web-view-auth.test.ts
index 8d56a94c4..64536d517 100644
--- a/scripts/miniprogram-web-view-auth.test.ts
+++ b/scripts/miniprogram-web-view-auth.test.ts
@@ -9,13 +9,13 @@ const shellScriptPath = join(
repoRoot,
'miniprogram',
'shell',
- 'wechatShellWebView.js',
+ 'webView.js',
);
const webViewHostBridgePath = join(
repoRoot,
'miniprogram',
'host-bridge',
- 'wechatHostBridgeWebView.js',
+ 'webView.js',
);
type MiniProgramPage = {
@@ -65,7 +65,7 @@ function loadWebViewPage(
},
...configOverrides,
},
- '../host-bridge/wechatHostBridgeWebView': webViewBridge,
+ '../host-bridge/webView': webViewBridge,
}) as {
createWechatWebViewPage: () => Record;
};