mcpField
P
push-notifications

push-notifications

github.com/claude-dev-suite开发4635 次安装2 天前更新
代码仓库

关于 push-notifications

用于实现推送通知的开发参考技能,涵盖服务端与客户端代码,包括 FCM、Web Push、Expo Notifications 及运维实践。

主要功能

  1. 01FCM 服务端发送
  2. 02Web Push 订阅与 Service Worker
  3. 03Expo Notifications 令牌流程
  4. 04多平台通知服务模式
  5. 05发送可靠性检查清单

适用场景

  1. 01向 FCM 设备发送通知
  2. 02为 Web 应用添加浏览器推送
  3. 03在 React Native 中请求通知权限
  4. 04规划令牌清理与后台发送

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill push-notifications

安装后在 Claude Code 中输入/push-notifications确认已加载。

详细介绍

推送通知

Firebase Cloud Messaging (FCM) — 服务端

import admin from 'firebase-admin';

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
});

// Send to single device
await admin.messaging().send({
  token: deviceToken,
  notification: { title: 'New Order', body: 'Order #1234 confirmed' },
  data: { orderId: '1234', type: 'order_confirmed' },
  android: { priority: 'high' },
  apns: { payload: { aps: { sound: 'default', badge: 1 } } },
});

// Send to topic
await admin.messaging().send({
  topic: 'promotions',
  notification: { title: 'Flash Sale', body: '50% off today!' },
});

Web Push(Service Worker)

// Register service worker and subscribe
const registration = await navigator.serviceWorker.register('/sw.js');
const subscription = await registration.pushManager.subscribe({
  userVisibleNotification: true,
  applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY),
});

// Send subscription to server
await fetch('/api/push/subscribe', {
  method: 'POST',
  body: JSON.stringify(subscription),
  headers: { 'Content-Type': 'application/json' },
});
Service Worker(sw.js)
self.addEventListener('push', (event) => {
  const data = event.data.json();
  event.waitUntil(
    self.registration.showNotification(data.title, {
      body: data.body,
      icon: '/icon-192.png',
      badge: '/badge-72.png',
      data: { url: data.url },
    })
  );
});

self.addEventListener('notificationclick', (event) => {
  event.notification.close();
  event.waitUntil(clients.openWindow(event.notification.data.url));
});
服务端(web-push 库)
import webpush from 'web-push';

webpush.setVapidDetails('mailto:[email protected]', VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY);

await webpush.sendNotification(subscription, JSON.stringify({
  title: 'New Message',
  body: 'You have a new message from John',
  url: '/messages/123',
}));

Expo Notifications(React Native)

import * as Notifications from 'expo-notifications';

// Request permission
const { status } = await Notifications.requestPermissionsAsync();
if (status !== 'granted') return;

// Get push token
const token = (await Notifications.getExpoPushTokenAsync()).data;
// Send token to your server

// Handle received notification
Notifications.addNotificationReceivedListener((notification) => {
  console.log(notification.request.content);
});

// Handle notification tap
Notifications.addNotificationResponseReceivedListener((response) => {
  const data = response.notification.request.content.data;
  navigateTo(data.screen);
});

通知服务模式

class NotificationService {
  async send(userId: string, notification: NotificationPayload) {
    const devices = await this.deviceRepo.findByUser(userId);

    const results = await Promise.allSettled(
      devices.map((device) => {
        switch (device.platform) {
          case 'web': return this.sendWebPush(device, notification);
          case 'ios':
          case 'android': return this.sendFCM(device, notification);
        }
      })
    );

    // Remove invalid tokens
    for (const [i, result] of results.entries()) {
      if (result.status === 'rejected' && isInvalidToken(result.reason)) {
        await this.deviceRepo.remove(devices[i].id);
      }
    }
  }
}

反模式

反模式修复方法
同步发送推送使用后台作业队列
不清理令牌删除无效或已过期的设备令牌
缺少通知权限交互体验在合适的情境下说明原因并请求权限
未对通知分组按类型分组,避免通知轰炸
发送失败时不作处理记录失败情况,并重试暂时性错误

生产环境检查清单

  • 为 Web Push 生成 VAPID 密钥
  • 配置 FCM 服务账号
  • 存储并清理设备令牌
  • 用于批量发送的后台作业队列
  • 每位用户的通知偏好设置
  • 速率限制,防止垃圾信息
  • 分析:送达率、打开率

评论

支持 Markdown