Files
Genarrative/apps/mobile-shell/src/host-bridge/notifications.ts
T
kdletters c42afe86a6 收口移动通知响应边界
将 Expo 本地通知成功响应包装收口到 notifications 模块

让移动 dispatch 只委托本地通知请求

同步移动壳配置门禁和共享记忆
2026-06-20 01:11:39 +08:00

87 lines
2.3 KiB
TypeScript

import * as Notifications from 'expo-notifications';
import { Platform } from 'react-native';
import {
HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID,
type HostBridgeError,
type HostBridgeRequest,
type LocalNotificationPayload,
normalizeHostBridgeLocalNotification,
} from '../../../../packages/shared/src/contracts/hostBridge';
import { invalidRequest, ok } from './protocol';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowBanner: true,
shouldShowList: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
function hasNotificationPermission(
permission: Awaited<ReturnType<typeof Notifications.getPermissionsAsync>>,
) {
return (
permission.granted ||
permission.ios?.status === Notifications.IosAuthorizationStatus.PROVISIONAL
);
}
async function ensureNotificationPermission() {
const currentPermission = await Notifications.getPermissionsAsync();
if (hasNotificationPermission(currentPermission)) {
return;
}
const requestedPermission = await Notifications.requestPermissionsAsync({
ios: {
allowAlert: true,
allowBadge: false,
allowSound: false,
},
});
if (!hasNotificationPermission(requestedPermission)) {
throw {
code: 'host_error',
message: 'notification permission denied',
} satisfies HostBridgeError;
}
}
export async function showMobileLocalNotification(
notification: LocalNotificationPayload,
) {
await ensureNotificationPermission();
if (Platform.OS === 'android') {
await Notifications.setNotificationChannelAsync(
HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID,
{
name: 'Genarrative',
importance: Notifications.AndroidImportance.DEFAULT,
},
);
}
await Notifications.scheduleNotificationAsync({
content: notification,
trigger:
Platform.OS === 'android'
? { channelId: HOST_BRIDGE_MOBILE_LOCAL_NOTIFICATION_CHANNEL_ID }
: null,
});
return true;
}
export async function showMobileHostBridgeLocalNotification(
request: HostBridgeRequest,
) {
const notification = normalizeHostBridgeLocalNotification(request.payload);
if (!notification) {
throw invalidRequest('title is required');
}
await showMobileLocalNotification(notification);
return ok(request, true);
}