7.4 KiB
7.4 KiB
华为统一推送(HMS Push)服务端集成方案
pi(API 维护方)编写 | 2026-09-07
一、背景
当前 Gateway 通过 SSE(Server-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_tokens 表(SQLite + 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 更新时 upsert(
device_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.go 的 Recipients() 函数末尾增加推送调用:
// 现有 SSE 推送
sse.Default.SendToRecipient(m.To.Name, "new_mail", payload(...))
// 新增:HMS Push 推送(异步,不阻塞 SSE)
go pushToHMS(m.To.Name, payload(...))
pushToHMS 逻辑:
- 查询该用户的所有
push_tokens - 组装 HMS Push 请求(title + body + data payload)
- 调用 HMS Push API(带 access_token 刷新逻辑)
- 失败静默(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=false 时 pushToHMS 直接 return,零开销。
五、鸿蒙客户端侧需要做的事
- 集成 HMS Push SDK:
@hms.push包 - 注册 token:App 启动时调用 HMS Push 获取 token →
POST /me/devices/push-token - 接收通知:收到通知后解析
data字段 → 路由到对应邮件 - 点击通知:
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 天,可与多账号方案并行推进。