> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monad.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# 如何向 Farcaster Mini App 用户发送通知

本指南将带您了解如何向 Mini App 用户发送通知。

本指南使用 [Monad Mini App 模板](https://github.com/monad-developers/monad-miniapp-template),该模板已经包含发送通知的代码;您只需修改几行代码。

如果您没有使用该模板,仍可以按照本指南操作;可根据需要从模板中复制代码。

## 演示

如果您想体验 Mini App 通知效果,可以尝试 [Monad Mini App 模板](https://farcaster.xyz/miniapps/ODHcbibktF7T/monad-farcaster-miniapp-template) 应用。

## 修改 Mini App manifest

<Note>
  在 Mini App 能够发送通知之前,必须完成 Mini App 账户关联流程。
</Note>

Mini Apps 可以在以下情形下向用户发送通知:

* 用户已添加 Mini App 并未手动关闭通知
* 用户明确订阅了来自 Mini App 的通知

Farcaster 应用或客户端会向 Mini App 的 webhook 端点发送 `miniapp_added`、`miniapp_removed`、`notifications_disabled` 和 `notifications_enabled` 等事件,这使 Mini App 能够跟踪它可以向哪些用户发送通知。

`webhookUrl` 必须在 Mini App manifest 文件中指定:

```ts title="app/.well-known/farcaster.json/route.ts" theme={null}
...

export async function GET() {
  const farcasterConfig = {
    // TODO: Add your own account association
    frame: {
        version: "1",
        name: "Monad Farcaster Mini App Template",
        ...
        splashBackgroundColor: "#ffffff",
        webhookUrl: `${APP_URL}/api/webhook`, // <--- Edit this
    },
};

...
```

如果您使用的是 [Monad Mini App 模板](https://github.com/monad-developers/monad-miniapp-template),则无需编辑 `webhookUrl`。

## 处理 Farcaster 客户端事件

处理 webhook 事件的代码位于文件 `/app/api/webhook/route.ts` 中。

### 验证 webhook 事件

事件由用户的 app key 使用 [JSON Farcaster Signature](https://github.com/farcasterxyz/protocol/discussions/208) 进行签名。这使 Mini Apps 可以验证生成通知的 Farcaster 客户端以及所对应的 Farcaster 用户。

验证事件很重要,以确保 Mini App 正确跟踪它可以向哪些用户发送通知。

如果您使用的是 [Monad Mini App 模板](https://github.com/monad-developers/monad-miniapp-template),验证事件的代码已经存在于 [`/app/api/webhook/route.ts`](https://github.com/monad-developers/monad-miniapp-template/blob/main/app/api/webhook/route.ts)。如果没有使用模板,您可以从同一文件复制代码。

<Info>
  需要 Neynar API key 才能验证 webhook 事件。您可以在 [Neynar](https://neynar.com/) 服务上注册并免费获取 API key。

  获取后,在您的 `.env` 文件中添加一个名为 `NEYNAR_API_KEY` 的环境变量。
</Info>

### 处理 webhook 载荷

一旦指定了 `webhookUrl`,Farcaster 应用和客户端将向该 webhook 端点发送客户端事件。

`miniapp_added` 和 `notifications_enabled` 事件由 Mini App 与 `fid` 和 `notificationDetails` 一起接收。

`notificationDetails` 包含一个 `url` 和一个 `token`,可用于向特定 Farcaster 用户发送通知。

Webhook 载荷示例:

```json theme={null}
{
    "fid": 17979,
    "event": {
        "event": "notifications_enabled",
        "notificationDetails": {
            "url": "https://api.farcaster.xyz/v1/frame-notifications",
            "token": "a05059ef2415c67b08ecceb539201cbc6"
        }
    }
}
```

您可以在 [`/app/api/webhook/route.ts`](https://github.com/monad-developers/monad-miniapp-template/blob/main/app/api/webhook/route.ts) 中找到处理 Farcaster 客户端事件的代码。

Mini App 可以使用任何自选的数据库服务来存储 `url` 和 `token`,并在发送通知时使用它们。

[Monad Mini App 模板](https://github.com/monad-developers/monad-miniapp-template) 使用 [Upstash 的 Redis](https://console.upstash.com/redis) 服务存储 `notificationDetails`,如果您希望使用不同的数据库,可以在 [`/lib/kv.ts`](https://github.com/monad-developers/monad-miniapp-template/blob/main/lib/kv.ts) 中修改。

<Note>
  由于 [Monad Mini App 模板](https://github.com/monad-developers/monad-miniapp-template) 使用 Redis 存储通知的 url 和 token,`.env` 中需要 `UPSTASH_REDIS_REST_URL` 和 `UPSTASH_REDIS_REST_TOKEN` 环境变量。

  在您注册 [Upstash](https://console.upstash.com/redis) 服务并创建 Redis 数据库后,便可获得这些环境变量。

  如果您计划使用其他数据库,请相应地调整环境变量。
</Note>

将通知详情存储到 Redis 的示例:

```ts title="/lib/kv.ts" theme={null}
...

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL,
  token: process.env.UPSTASH_REDIS_REST_TOKEN,
});

...

export async function setUserNotificationDetails(
    fid: number,
    notificationDetails: MiniAppNotificationDetails
): Promise<void> {
    // Modify lines that use redis to use your own database implementation
    await redis.set(getUserNotificationDetailsKey(fid), notificationDetails);  
}

...
```

## 发送通知

<img src="https://mintcdn.com/monadfoundation-40611fb6/-TCPhWHMfGzx9j3a/static/img/templates/farcaster-miniapp/sending-notifications/1.png?fit=max&auto=format&n=-TCPhWHMfGzx9j3a&q=85&s=204e9c9aed64df212be58d2ca204132d" alt="Example of a notification sent from a Farcaster Mini App" style={{marginLeft: "auto", marginRight: "auto"}} width="1238" height="168" data-path="static/img/templates/farcaster-miniapp/sending-notifications/1.png" />

一旦您获取了用户的通知 token,即可通过向该 token 关联的 URL 发送 `POST` 请求来向用户发送通知。

如果您使用的是 [Monad Mini App 模板](https://github.com/monad-developers/monad-miniapp-template),发送通知的代码已经存在于文件 [`/app/api/send-notification/route.ts`](https://github.com/monad-developers/monad-miniapp-template/blob/main/app/api/send-notification/route.ts) 中。如果没有,您可以从 [`/lib/notifs.ts`](https://github.com/monad-developers/monad-miniapp-template/blob/main/lib/notifs.ts) 和 [`/app/api/send-notification/route.ts`](https://github.com/monad-developers/monad-miniapp-template/blob/main/app/api/send-notification/route.ts) 复制代码。

### 个性化通知内容

您可以在 [`/app/api/send-notification/route.ts`](https://github.com/monad-developers/monad-miniapp-template/blob/main/app/api/send-notification/route.ts) 文件中修改几行代码来个性化通知:

```ts title="/app/api/send-notification/route.ts" theme={null}
...

// This function sends the notification
const sendResult = await sendFrameNotification({
    fid: requestBody.data.fid,
    // You can modify/personalize the below line to make the title of the notification dynamic based on the fid (user)
    title: "Test notification",
    // You can modify/personalize the below line to make the body of the notification dynamic based on the fid (user)
    body: "Sent at " + new Date().toISOString(),
});

...
```

<Warning>
  #### 通知速率限制

  Farcaster 强制执行的标准速率限制为:

  * 每个 token 每 30 秒 1 条通知
  * 每个 token 每天 100 条通知
</Warning>

如果您使用的是 [Monad Mini App 模板](https://github.com/monad-developers/monad-miniapp-template),您可以通过对 `/api/send-notification` 端点发起 `POST` 请求,从服务器或 Mini App 发送通知!

这就是您向 Mini App 用户发送通知所需的全部!
