补齐平台壳宿主消费门禁
新增平台壳草稿通知和角标 HostBridge 同步层 补充真实 Tauri transport 单测和跳一跳完成集成测试 扩展原生壳门禁覆盖 H5 宿主消费链路 更新宿主壳协议、方案和共享决策记录
This commit is contained in:
@@ -191,10 +191,6 @@ import {
|
||||
saveBabyObjectMatchDraft,
|
||||
} from '../../services/edutainment-baby-object';
|
||||
import { getExternalGenerationQueueOverview } from '../../services/external-generation';
|
||||
import {
|
||||
setHostAppBadgeCount,
|
||||
showHostLocalNotification,
|
||||
} from '../../services/host-bridge/hostBridge';
|
||||
import {
|
||||
jumpHopClient,
|
||||
type JumpHopGalleryCardResponse,
|
||||
@@ -553,6 +549,10 @@ import {
|
||||
type PlatformHostDraftNotification,
|
||||
sendPlatformHostDraftNotificationOnce,
|
||||
} from './platformHostNotificationModel';
|
||||
import {
|
||||
sendPlatformHostDraftNotificationToHost,
|
||||
syncPlatformHostDraftBadgeCountToHost,
|
||||
} from './platformHostBridgeSync';
|
||||
import {
|
||||
buildMatch3DProfileFromSession,
|
||||
hasMatch3DRuntimeAsset,
|
||||
@@ -2030,7 +2030,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
sendPlatformHostDraftNotificationOnce(
|
||||
sentPlatformHostDraftNotificationKeysRef.current,
|
||||
notification,
|
||||
showHostLocalNotification,
|
||||
sendPlatformHostDraftNotificationToHost,
|
||||
);
|
||||
},
|
||||
[],
|
||||
@@ -3340,7 +3340,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
[draftGenerationNotices, visibleDraftNoticeKeys],
|
||||
);
|
||||
useEffect(() => {
|
||||
void setHostAppBadgeCount({ count: unreadDraftGenerationUpdateCount });
|
||||
syncPlatformHostDraftBadgeCountToHost(unreadDraftGenerationUpdateCount);
|
||||
}, [unreadDraftGenerationUpdateCount]);
|
||||
const resultViewError =
|
||||
autosaveCoordinator.customWorldAutoSaveError ??
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/* @vitest-environment jsdom */
|
||||
|
||||
import { afterEach, describe, expect, test, vi } from 'vitest';
|
||||
|
||||
import type {
|
||||
HostBridgeCapability,
|
||||
HostBridgeRequest,
|
||||
} from '../../../packages/shared/src/contracts/hostBridge';
|
||||
import { resetHostRuntimeCacheForTest } from '../../services/host-bridge/hostBridge';
|
||||
import { resetNativeAppHostBridgeForTest } from '../../services/host-bridge/nativeAppHostBridge';
|
||||
import {
|
||||
sendPlatformHostDraftNotificationToHost,
|
||||
syncPlatformHostDraftBadgeCountToHost,
|
||||
} from './platformHostBridgeSync';
|
||||
|
||||
function asTauriInvoke(
|
||||
invoke: (command: string, args?: Record<string, unknown>) => Promise<unknown>,
|
||||
) {
|
||||
return async function tauriInvoke<Result = unknown>(
|
||||
command: string,
|
||||
args?: Record<string, unknown>,
|
||||
) {
|
||||
return (await invoke(command, args)) as Result;
|
||||
};
|
||||
}
|
||||
|
||||
function nativeAppPath(capabilities: HostBridgeCapability[] = []) {
|
||||
const params = new URLSearchParams({
|
||||
clientRuntime: 'native_app',
|
||||
hostShell: 'tauri_desktop',
|
||||
});
|
||||
if (capabilities.length > 0) {
|
||||
params.set('hostCapabilities', capabilities.join(','));
|
||||
}
|
||||
return `/?${params.toString()}`;
|
||||
}
|
||||
|
||||
function installTauriHostBridgeRecorder() {
|
||||
const requests: HostBridgeRequest[] = [];
|
||||
const invoke = vi.fn(async (_command: string, args?: Record<string, unknown>) => {
|
||||
const request = (args as { request: HostBridgeRequest }).request;
|
||||
requests.push(request);
|
||||
return {
|
||||
bridge: 'GenarrativeHostBridge',
|
||||
version: 1,
|
||||
id: request.id,
|
||||
ok: true,
|
||||
result: true,
|
||||
};
|
||||
});
|
||||
|
||||
window.__TAURI__ = {
|
||||
core: {
|
||||
invoke: asTauriInvoke(invoke),
|
||||
},
|
||||
};
|
||||
|
||||
return { invoke, requests };
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
window.history.replaceState(null, '', '/');
|
||||
delete window.__TAURI__;
|
||||
resetNativeAppHostBridgeForTest();
|
||||
resetHostRuntimeCacheForTest();
|
||||
});
|
||||
|
||||
describe('platformHostBridgeSync', () => {
|
||||
test('平台壳草稿通知通过真实 HostBridge 请求本地系统通知', async () => {
|
||||
window.history.replaceState(
|
||||
null,
|
||||
'',
|
||||
nativeAppPath(['notification.showLocal']),
|
||||
);
|
||||
const { invoke, requests } = installTauriHostBridgeRecorder();
|
||||
|
||||
await expect(
|
||||
sendPlatformHostDraftNotificationToHost({
|
||||
title: ' 生成完成 ',
|
||||
body: ' 拼图草稿 puzzle-session-1 生成任务已完成 ',
|
||||
}),
|
||||
).resolves.toBe(true);
|
||||
|
||||
expect(invoke).toHaveBeenCalledWith('host_bridge_request', {
|
||||
request: expect.objectContaining({
|
||||
method: 'notification.showLocal',
|
||||
payload: {
|
||||
title: '生成完成',
|
||||
body: '拼图草稿 puzzle-session-1 生成任务已完成',
|
||||
},
|
||||
}),
|
||||
});
|
||||
expect(requests).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('平台壳草稿未读计数通过真实 HostBridge 同步应用角标', async () => {
|
||||
window.history.replaceState(
|
||||
null,
|
||||
'',
|
||||
nativeAppPath(['app.setBadgeCount']),
|
||||
);
|
||||
const { invoke, requests } = installTauriHostBridgeRecorder();
|
||||
|
||||
await expect(syncPlatformHostDraftBadgeCountToHost(3)).resolves.toBe(true);
|
||||
|
||||
expect(invoke).toHaveBeenCalledWith('host_bridge_request', {
|
||||
request: expect.objectContaining({
|
||||
method: 'app.setBadgeCount',
|
||||
payload: {
|
||||
count: 3,
|
||||
},
|
||||
}),
|
||||
});
|
||||
expect(requests).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('宿主未声明草稿通知和角标能力时平台壳保持 H5 回退', async () => {
|
||||
window.history.replaceState(null, '', nativeAppPath());
|
||||
const { invoke } = installTauriHostBridgeRecorder();
|
||||
|
||||
await expect(
|
||||
sendPlatformHostDraftNotificationToHost({
|
||||
title: '生成完成',
|
||||
body: '拼图草稿已完成。',
|
||||
}),
|
||||
).resolves.toBe(false);
|
||||
await expect(syncPlatformHostDraftBadgeCountToHost(1)).resolves.toBe(false);
|
||||
|
||||
expect(invoke).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import {
|
||||
setHostAppBadgeCount,
|
||||
showHostLocalNotification,
|
||||
} from '../../services/host-bridge/hostBridge';
|
||||
import type { PlatformHostDraftNotification } from './platformHostNotificationModel';
|
||||
|
||||
type PlatformHostDraftNotificationPayload = Pick<
|
||||
PlatformHostDraftNotification,
|
||||
'title' | 'body'
|
||||
>;
|
||||
|
||||
// 中文注释:平台壳只把已派生出的通知和角标计数交给 HostBridge,不改业务事实。
|
||||
export function sendPlatformHostDraftNotificationToHost({
|
||||
title,
|
||||
body,
|
||||
}: PlatformHostDraftNotificationPayload) {
|
||||
return showHostLocalNotification({ title, body });
|
||||
}
|
||||
|
||||
export function syncPlatformHostDraftBadgeCountToHost(count: number) {
|
||||
return setHostAppBadgeCount({ count });
|
||||
}
|
||||
Reference in New Issue
Block a user