统一移动通知频道契约
将移动端 Android 本地通知频道提升到共享 HostBridge 契约 让 Expo 通知调度和测试复用共享频道标识 增加移动壳配置门禁防止通知频道回退到本地字面量 补充宿主壳方案文档和共享决策记录
This commit is contained in:
@@ -598,6 +598,10 @@ const sharedPublicWebUrl = extractStringConstExport(
|
||||
sharedContractSource,
|
||||
'HOST_BRIDGE_PUBLIC_WEB_URL',
|
||||
);
|
||||
const sharedMobileLocalNotificationChannelId = extractStringConstExport(
|
||||
sharedContractSource,
|
||||
'HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID',
|
||||
);
|
||||
const sharedNativeAppQueryKeys = extractStringArrayExport(
|
||||
sharedContractSource,
|
||||
'HOST_BRIDGE_NATIVE_APP_QUERY_KEYS',
|
||||
@@ -632,6 +636,7 @@ const sharedPayloadBoundaryImports = [
|
||||
'HOST_BRIDGE_IMPORT_AUDIO_MAX_BYTES',
|
||||
'HOST_BRIDGE_IMPORT_IMAGE_MAX_BYTES',
|
||||
'HOST_BRIDGE_IMPORT_TEXT_MAX_BYTES',
|
||||
'HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID',
|
||||
'normalizeHostBridgeQrCodeValue',
|
||||
'HOST_BRIDGE_TEXT_MIME_TYPES',
|
||||
];
|
||||
@@ -664,6 +669,7 @@ const forbiddenLocalPayloadBoundaryDeclarations = [
|
||||
'HOST_BRIDGE_DOCUMENT_MIME_TYPES',
|
||||
'HOST_BRIDGE_IMAGE_MIME_TYPES',
|
||||
'HOST_BRIDGE_AUDIO_MIME_TYPES',
|
||||
'HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID',
|
||||
];
|
||||
for (const localBoundary of forbiddenLocalPayloadBoundaryDeclarations) {
|
||||
if (new RegExp(`const ${localBoundary}\\s*=`).test(hostBridgeSource)) {
|
||||
@@ -1380,7 +1386,25 @@ for (const forbiddenHostBridgeRuntimeSnippet of ['atob(', 'Buffer.from']) {
|
||||
}
|
||||
|
||||
if (
|
||||
!/trigger:\s*Platform\.OS === 'android'\s*\?\s*\{\s*channelId: LOCAL_NOTIFICATION_CHANNEL_ID\s*\}\s*:\s*null/.test(
|
||||
dispatchSource.includes("const LOCAL_NOTIFICATION_CHANNEL_ID = '") ||
|
||||
dispatchSource.includes('"genarrative-local"') ||
|
||||
dispatchSource.includes("'genarrative-local'")
|
||||
) {
|
||||
throw new Error(
|
||||
'mobile shell local notification channel id must come from shared contract',
|
||||
);
|
||||
}
|
||||
|
||||
if (sharedMobileLocalNotificationChannelId !== 'genarrative-local') {
|
||||
throw new Error('shared mobile local notification channel id drifted');
|
||||
}
|
||||
|
||||
if (!dispatchSource.includes('HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID')) {
|
||||
throw new Error('mobile shell must use the shared local notification channel id');
|
||||
}
|
||||
|
||||
if (
|
||||
!/trigger:\s*Platform\.OS === 'android'\s*\?\s*\{\s*channelId: HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID\s*\}\s*:\s*null/.test(
|
||||
dispatchSource,
|
||||
)
|
||||
) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import { afterEach, describe, expect, test, vi } from 'vitest';
|
||||
|
||||
import {
|
||||
HOST_BRIDGE_BADGE_COUNT_MAX,
|
||||
HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID,
|
||||
HOST_BRIDGE_PROTOCOL,
|
||||
HOST_BRIDGE_RESPONSE_CACHE_MAX,
|
||||
HOST_BRIDGE_VERSION,
|
||||
@@ -738,7 +739,7 @@ describe('handleMobileHostBridgeMessage', () => {
|
||||
|
||||
expectOk(response);
|
||||
expect(Notifications.setNotificationChannelAsync).toHaveBeenCalledWith(
|
||||
'genarrative-local',
|
||||
HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID,
|
||||
{
|
||||
name: 'Genarrative',
|
||||
importance: Notifications.AndroidImportance.DEFAULT,
|
||||
@@ -749,7 +750,7 @@ describe('handleMobileHostBridgeMessage', () => {
|
||||
title: '生成完成',
|
||||
},
|
||||
trigger: {
|
||||
channelId: 'genarrative-local',
|
||||
channelId: HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
type ClipboardWriteTextPayload,
|
||||
type HapticsImpactPayload,
|
||||
HOST_BRIDGE_BADGE_COUNT_MAX,
|
||||
HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID,
|
||||
HOST_BRIDGE_VERSION,
|
||||
type HostBridgeError,
|
||||
type HostBridgeRequest,
|
||||
@@ -51,8 +52,6 @@ import { resetQrScannerForTest, scanQrCode } from './scanner';
|
||||
import { openShare } from './share';
|
||||
import { buildMobileShellUrl } from '../shell/url';
|
||||
|
||||
const LOCAL_NOTIFICATION_CHANNEL_ID = 'genarrative-local';
|
||||
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => ({
|
||||
shouldShowBanner: true,
|
||||
@@ -193,7 +192,7 @@ async function showLocalNotification(payload: unknown) {
|
||||
await ensureNotificationPermission();
|
||||
if (Platform.OS === 'android') {
|
||||
await Notifications.setNotificationChannelAsync(
|
||||
LOCAL_NOTIFICATION_CHANNEL_ID,
|
||||
HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID,
|
||||
{
|
||||
name: 'Genarrative',
|
||||
importance: Notifications.AndroidImportance.DEFAULT,
|
||||
@@ -205,7 +204,7 @@ async function showLocalNotification(payload: unknown) {
|
||||
content: notification,
|
||||
trigger:
|
||||
Platform.OS === 'android'
|
||||
? { channelId: LOCAL_NOTIFICATION_CHANNEL_ID }
|
||||
? { channelId: HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID }
|
||||
: null,
|
||||
});
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user