收口原生壳能力来源
新增共享 HostBridge capability profile,区分 Expo 移动通用、iOS 额外和 Tauri 桌面能力 移动壳能力清单改为引用共享 profile,入口 URL 类型支持 readonly 能力数组 两端配置检查和原生壳总门禁改为反查共享 profile,桌面 Rust 清单保持运行时镜像 补充 HostBridge profile 单测和 H5 readonly 能力合并类型兼容 同步 Expo/Tauri 壳方案、HostBridge 协议文档和项目决策记录
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import {
|
||||
HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES,
|
||||
HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES,
|
||||
HOST_BRIDGE_EXPO_MOBILE_IOS_EXTRA_CAPABILITIES,
|
||||
HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES,
|
||||
HOST_BRIDGE_PUBLIC_WEB_ORIGIN,
|
||||
HOST_BRIDGE_PUBLIC_WEB_URL,
|
||||
HOST_BRIDGE_TAURI_COMMAND,
|
||||
HOST_BRIDGE_CAPABILITIES,
|
||||
isHostBridgeMethod,
|
||||
isHostBridgeCapability,
|
||||
normalizeHostBridgeBadgeCount,
|
||||
@@ -90,6 +95,44 @@ describe('HostBridge shared contract helpers', () => {
|
||||
expect(isHostBridgeCapability(null)).toBe(false);
|
||||
});
|
||||
|
||||
test('原生壳 capability profile 来自共享白名单', () => {
|
||||
const profiles = [
|
||||
HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES,
|
||||
HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES,
|
||||
HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES,
|
||||
];
|
||||
for (const profile of profiles) {
|
||||
expect(profile.every((capability) =>
|
||||
HOST_BRIDGE_CAPABILITIES.includes(capability),
|
||||
)).toBe(true);
|
||||
expect(profile).not.toContain('auth.requestLogin');
|
||||
expect(profile).not.toContain('payment.request');
|
||||
}
|
||||
});
|
||||
|
||||
test('移动和桌面 profile 保留真实平台差异', () => {
|
||||
expect(HOST_BRIDGE_EXPO_MOBILE_IOS_EXTRA_CAPABILITIES).toEqual([
|
||||
'app.setBadgeCount',
|
||||
]);
|
||||
expect(HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES).toEqual([
|
||||
...HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES,
|
||||
...HOST_BRIDGE_EXPO_MOBILE_IOS_EXTRA_CAPABILITIES,
|
||||
]);
|
||||
expect(HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES).toContain(
|
||||
'file.captureImage',
|
||||
);
|
||||
expect(HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES).toContain('app.setTitle');
|
||||
expect(HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES).toContain(
|
||||
'file.imageDropped',
|
||||
);
|
||||
expect(HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES).not.toContain(
|
||||
'file.captureImage',
|
||||
);
|
||||
expect(HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES).not.toContain(
|
||||
'haptics.impact',
|
||||
);
|
||||
});
|
||||
|
||||
test('归一化 HostBridge request id', () => {
|
||||
expect(normalizeHostBridgeRequestId(' request-1 ')).toBe('request-1');
|
||||
expect(normalizeHostBridgeRequestId('')).toBeNull();
|
||||
|
||||
@@ -71,12 +71,74 @@ export function isHostBridgeCapability(
|
||||
);
|
||||
}
|
||||
|
||||
export const HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES: readonly HostBridgeCapability[] = [
|
||||
'host.getRuntime',
|
||||
'appearance.getColorScheme',
|
||||
'host.events',
|
||||
'app.lifecycle',
|
||||
'share.open',
|
||||
'share.setTarget',
|
||||
'navigation.openNativePage',
|
||||
'navigation.canGoBack',
|
||||
'app.reloadWebView',
|
||||
'app.openExternalUrl',
|
||||
'network.status',
|
||||
'network.statusChanged',
|
||||
'clipboard.writeText',
|
||||
'clipboard.readText',
|
||||
'file.exportText',
|
||||
'file.importText',
|
||||
'file.exportImage',
|
||||
'file.importImage',
|
||||
'file.captureImage',
|
||||
'file.importAudio',
|
||||
'file.exportAudio',
|
||||
'haptics.impact',
|
||||
'notification.showLocal',
|
||||
];
|
||||
|
||||
export const HOST_BRIDGE_EXPO_MOBILE_IOS_EXTRA_CAPABILITIES: readonly HostBridgeCapability[] = [
|
||||
'app.setBadgeCount',
|
||||
];
|
||||
|
||||
export const HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES: readonly HostBridgeCapability[] = [
|
||||
...HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES,
|
||||
...HOST_BRIDGE_EXPO_MOBILE_IOS_EXTRA_CAPABILITIES,
|
||||
];
|
||||
|
||||
export const HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES: readonly HostBridgeCapability[] = [
|
||||
'host.getRuntime',
|
||||
'appearance.getColorScheme',
|
||||
'host.events',
|
||||
'app.lifecycle',
|
||||
'share.open',
|
||||
'share.setTarget',
|
||||
'navigation.openNativePage',
|
||||
'navigation.canGoBack',
|
||||
'app.reloadWebView',
|
||||
'app.openExternalUrl',
|
||||
'app.setTitle',
|
||||
'app.setBadgeCount',
|
||||
'network.status',
|
||||
'network.statusChanged',
|
||||
'clipboard.writeText',
|
||||
'clipboard.readText',
|
||||
'file.exportText',
|
||||
'file.importText',
|
||||
'file.exportImage',
|
||||
'file.importImage',
|
||||
'file.importAudio',
|
||||
'file.exportAudio',
|
||||
'file.imageDropped',
|
||||
'notification.showLocal',
|
||||
];
|
||||
|
||||
export type HostBridgeRuntimeResult = {
|
||||
shell: NativeHostShell;
|
||||
platform: NativeHostPlatform;
|
||||
hostVersion: string | null;
|
||||
bridgeVersion: number;
|
||||
capabilities: HostBridgeCapability[];
|
||||
capabilities: readonly HostBridgeCapability[];
|
||||
};
|
||||
|
||||
export type HostBridgeRequest<Payload = unknown> = {
|
||||
|
||||
Reference in New Issue
Block a user