Files
MailUI4Agents/docs/HMS-PUSH-PLAN.md

7.4 KiB
Raw Permalink Blame History

华为统一推送HMS Push服务端集成方案

piAPI 维护方)编写 | 2026-09-07


一、背景

当前 Gateway 通过 SSEServer-Sent Events向在线客户端实时推送新邮件。但当客户端在后台或被系统杀死时SSE 断开用户无法收到新邮件通知。华为鸿蒙统一推送HMS Push可在设备关闭应用时仍推送通知——点击通知打开应用并跳转对应邮件。

目标Gateway 在 SSE 之外增加推送管道,当 new_mail 到达时,对所有已注册推送 token 的设备发送 HMS Push 通知。


二、HMS Push API 工作方式

客户端 (鸿蒙)                      服务端 (Gateway)               华为 Push API
  │                                  │                              │
  │── 注册 HMS Push获取 token ──→  │                              │
  │                                  │                              │
  │── POST /me/devices/push-token ──→│ 存储 token                   │
  │                                  │                              │
  │  ...应用关闭/进入后台...           │                              │
  │                                  │                              │
  │  ← new_mail SSE 断开 ──────────  │                              │
  │                                  │                              │
  │                                  │── 调用 HMS Push API ────────→│
  │                                  │   (POST v1/messages:send)    │
  │                                  │                              │
  │                                  │              ← 推送到设备 ──│
  │  ← 通知栏弹出 ──────────────────  │                              │
  │── 用户点击通知 ──→ 打开应用 ──────│  │                           │

HMS Push API 核心接口

POST https://push-api.cloud.huawei.com/v1/{app_id}/messages:send
Authorization: Bearer {access_token}
Body: {
  "validate_only": false,
  "message": {
    "token": ["push_token_1", ...],
    "notification": {
      "title": "新邮件:{subject}",
      "body": "发件人:{from_name}"
    },
    "data": {
      "mail_id": "...",
      "session_id": "...",
      "action": "open_mail"
    }
  }
}

认证:需要华为开发者账号的 App ID + App Secret → 获取 access_token有效期 1 小时,需刷新)。


三、服务端架构

3.1 数据模型

新增 push_tokensSQLite + PostgreSQL 通用):

CREATE TABLE push_tokens (
    user_id     TEXT NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
    push_token  TEXT NOT NULL,           -- HMS Push token设备唯一
    platform    TEXT NOT NULL DEFAULT 'harmonyos',  -- 标识来源(未来可扩展)
    device_id   TEXT NOT NULL DEFAULT '', -- 客户端生成的设备唯一 ID
    created_at  DATETIME DEFAULT (datetime('now')),
    updated_at  DATETIME DEFAULT (datetime('now')),
    PRIMARY KEY (user_id, push_token)
);
  • 每个用户可注册多个设备(手机、平板)
  • 同一设备的 token 更新时 upsertdevice_id 去重)
  • 用户删除时级联清理

3.2 API 端点

POST /me/devices/push-token   注册/更新推送 token
DELETE /me/devices/push-token  注销推送 token
GET  /me/devices/push-tokens   查询已注册的设备列表

请求体(注册):

{
  "push_token": "CAHPxxx...",
  "device_id": "device-uuid-xxx",
  "platform": "harmonyos"
}

3.3 推送触发点

notify/mail.goRecipients() 函数末尾增加推送调用:

// 现有 SSE 推送
sse.Default.SendToRecipient(m.To.Name, "new_mail", payload(...))

// 新增HMS Push 推送(异步,不阻塞 SSE
go pushToHMS(m.To.Name, payload(...))

pushToHMS 逻辑:

  1. 查询该用户的所有 push_tokens
  2. 组装 HMS Push 请求title + body + data payload
  3. 调用 HMS Push API带 access_token 刷新逻辑)
  4. 失败静默SSE 已保证在线设备收到Push 是补充通道)

3.4 access_token 管理

HMS Push API 需要 OAuth 2.0 access_token有效期 ~3600s

type HMSTokenManager struct {
    appID     string
    appSecret string
    token     string
    expiresAt time.Time
}

func (m *HMSTokenManager) getToken() (string, error) {
    if time.Now().Before(m.expiresAt) {
        return m.token, nil
    }
    // POST https://oauth-login.cloud.huawei.com/oauth2/v3/token
    // grant_type=client_credentials&client_id=appID&client_secret=appSecret
    // ...
    return newToken, nil
}

3.5 推送内容模板

标题:新邮件
正文:{from_name}{subject}
数据:{ mail_id, session_id, from_name, subject, action: "open_mail" }

客户端收到通知后,打开应用并路由到对应邮件详情页。


四、配置项

# HMS Push 配置(环境变量)
HMS_APP_ID=10xxxxxx          # 华为开发者 App ID
HMS_APP_SECRET=xxxxxx        # App Secret
HMS_ENABLED=true             # 开关false 时只走 SSE 不推 HMS

HMS_ENABLED=falsepushToHMS 直接 return零开销。


五、鸿蒙客户端侧需要做的事

  1. 集成 HMS Push SDK@hms.push
  2. 注册 tokenApp 启动时调用 HMS Push 获取 token → POST /me/devices/push-token
  3. 接收通知:收到通知后解析 data 字段 → 路由到对应邮件
  4. 点击通知action: "open_mail" → 跳转到 mail_id 对应的邮件详情

六、时机与限制

场景 行为
客户端在线SSE 连接) SSE 已推送,Push 不发(避免重复通知)
客户端后台/SSE 断开 Push 发送,唤醒设备
用户已禁用通知 服务端不知情Push 发送但被系统拦截(正常行为)
同一用户多设备 所有注册的 token 都推送
推送频率限制 HMS Push 免费版有 QPS 限制(按 App 而定),大量并发时需队列化

SSE 与 Push 的切换判断:最简实现是无条件推送SSE 在线时 Push 也会发,但客户端收到 SSE 后可以忽略 Push。如果要精确判断客户端在线时上报一个 push_active 标记,服务端据此跳过。但最简方案更可靠——依赖客户端状态判断有延迟风险。


七、鸿蒙端集成要点(供 dsh 参考)

// 鸿蒙端伪代码
import push from '@hms.push';

// App 启动时
async function registerPushToken() {
  const token = await push.getToken({ scope: 'message' });
  if (token) {
    await fetch(`${gateway}/me/devices/push-token`, {
      method: 'POST',
      headers: { Authorization: `Bearer ${userKey}` },
      body: JSON.stringify({ push_token: token, device_id: deviceId })
    });
  }
}

// 收到推送
push.onMessage((data) => {
  if (data.action === 'open_mail') {
    navigateToMail(data.mail_id);
  }
});

八、实施阶段

阶段 内容 估时
P1 push_tokens 表 + API 端点 + HMS access_token 管理 1 天
P2 notify/mail.go 接入 + 推送触发逻辑 0.5 天
P3 鸿蒙客户端集成dsh 侧) 由 dsh 实施
P4 测试 + 边界token 刷新失败、推送频率、多设备) 0.5 天

总计 Gateway 侧 1.5 天,可与多账号方案并行推进。