feat: 支持 push

This commit is contained in:
richarjiang
2025-10-11 17:38:04 +08:00
parent 999fc7f793
commit 305a969912
30 changed files with 4582 additions and 1 deletions

View File

@@ -0,0 +1,474 @@
# iOS推送功能使用指南
## 概述
本文档详细介绍了如何使用iOS远程推送功能包括API接口使用、配置说明和代码示例。
## 环境配置
### 1. 环境变量配置
`.env`文件中添加以下配置:
```bash
# APNs配置
APNS_KEY_ID=your_key_id
APNS_TEAM_ID=your_team_id
APNS_KEY_PATH=path/to/APNsAuthKey_XXXXXXXXXX.p8
APNS_BUNDLE_ID=com.yourcompany.yourapp
APNS_ENVIRONMENT=production # or sandbox
# 推送服务配置
APNS_CLIENT_COUNT=2
APNS_CONNECTION_RETRY_LIMIT=3
APNS_HEARTBEAT=60000
APNS_REQUEST_TIMEOUT=5000
```
### 2. APNs认证文件
1. 登录 [Apple Developer Portal](https://developer.apple.com)
2. 导航到 "Certificates, Identifiers & Profiles"
3. 选择 "Keys"
4. 创建新的密钥,并启用 "Apple Push Notifications service"
5. 下载`.p8`格式的私钥文件
6. 将私钥文件安全地存储在服务器上
### 3. 数据库迁移
执行以下SQL脚本创建推送相关的数据表
```bash
mysql -u username -p database_name < sql-scripts/push-notifications-tables-create.sql
```
## API接口使用
### 1. 设备令牌管理
#### 注册设备令牌
```bash
POST /api/push-notifications/register-token
Authorization: Bearer <access_token>
Content-Type: application/json
{
"deviceToken": "a9d0ed10e9cfd022a61cb08753f49c5a0b0dfb383697bf9f9d750a1003da19c7",
"deviceType": "IOS",
"appVersion": "1.0.0",
"osVersion": "iOS 15.0",
"deviceName": "iPhone 13"
}
```
**响应示例:**
```json
{
"code": 0,
"message": "设备令牌注册成功",
"data": {
"success": true,
"tokenId": "uuid-token-id"
}
}
```
#### 更新设备令牌
```bash
PUT /api/push-notifications/update-token
Authorization: Bearer <access_token>
Content-Type: application/json
{
"currentDeviceToken": "old-device-token",
"newDeviceToken": "new-device-token",
"appVersion": "1.0.1",
"osVersion": "iOS 15.1"
}
```
#### 注销设备令牌
```bash
DELETE /api/push-notifications/unregister-token
Authorization: Bearer <access_token>
Content-Type: application/json
{
"deviceToken": "device-token-to-unregister"
}
```
### 2. 推送消息发送
#### 发送单个推送通知
```bash
POST /api/push-notifications/send
Content-Type: application/json
{
"userIds": ["user_123", "user_456"],
"title": "训练提醒",
"body": "您今天的普拉提训练还未完成,快来打卡吧!",
"payload": {
"type": "training_reminder",
"trainingId": "training_123"
},
"pushType": "ALERT",
"priority": 10,
"sound": "default",
"badge": 1
}
```
**响应示例:**
```json
{
"code": 0,
"message": "推送发送成功",
"data": {
"success": true,
"sentCount": 2,
"failedCount": 0,
"results": [
{
"userId": "user_123",
"deviceToken": "device-token-1",
"success": true
},
{
"userId": "user_456",
"deviceToken": "device-token-2",
"success": true
}
]
}
}
```
#### 使用模板发送推送
```bash
POST /api/push-notifications/send-by-template
Content-Type: application/json
{
"userIds": ["user_123"],
"templateKey": "training_reminder",
"data": {
"userName": "张三",
"trainingName": "核心力量训练"
},
"payload": {
"type": "training_reminder",
"trainingId": "training_123"
}
}
```
#### 批量发送推送
```bash
POST /api/push-notifications/send-batch
Content-Type: application/json
{
"userIds": ["user_123", "user_456", "user_789"],
"title": "系统通知",
"body": "系统将于今晚22:00进行维护请提前保存您的工作。",
"payload": {
"type": "system_maintenance",
"maintenanceTime": "22:00"
}
}
```
#### 发送静默推送
```bash
POST /api/push-notifications/send-silent
Content-Type: application/json
{
"userId": "user_123",
"payload": {
"type": "data_sync",
"syncData": true
}
}
```
### 3. 推送模板管理
#### 获取所有模板
```bash
GET /api/push-notifications/templates
Authorization: Bearer <access_token>
```
#### 创建推送模板
```bash
POST /api/push-notifications/templates
Authorization: Bearer <access_token>
Content-Type: application/json
{
"templateKey": "custom_reminder",
"title": "自定义提醒",
"body": "您好{{userName}}{{reminderContent}}",
"payloadTemplate": {
"type": "custom_reminder",
"reminderId": "{{reminderId}}"
},
"pushType": "ALERT",
"priority": 8
}
```
#### 更新推送模板
```bash
PUT /api/push-notifications/templates/:id
Authorization: Bearer <access_token>
Content-Type: application/json
{
"title": "更新后的标题",
"body": "更新后的内容:{{userName}}{{reminderContent}}",
"isActive": true
}
```
#### 删除推送模板
```bash
DELETE /api/push-notifications/templates/:id
Authorization: Bearer <access_token>
```
## 代码示例
### 1. 在业务服务中使用推送功能
```typescript
import { Injectable } from '@nestjs/common';
import { PushNotificationsService } from '../push-notifications/push-notifications.service';
@Injectable()
export class TrainingService {
constructor(
private readonly pushNotificationsService: PushNotificationsService,
) {}
async sendTrainingReminder(userId: string, trainingName: string): Promise<void> {
// 使用模板发送推送
await this.pushNotificationsService.sendNotificationByTemplate({
userIds: [userId],
templateKey: 'training_reminder',
data: {
userName: '用户', // 可以从用户服务获取
trainingName,
},
payload: {
type: 'training_reminder',
trainingId: 'training_123',
},
});
}
async sendWorkoutCompletionNotification(userId: string, workoutName: string, calories: number): Promise<void> {
// 直接发送推送
await this.pushNotificationsService.sendNotification({
userIds: [userId],
title: '训练完成',
body: `太棒了!您已完成${workoutName}训练,消耗了${calories}卡路里。`,
payload: {
type: 'workout_completed',
workoutId: 'workout_123',
calories,
},
sound: 'celebration.caf',
badge: 1,
});
}
}
```
### 2. 在控制器中处理设备令牌注册
```typescript
import { Controller, Post, Body, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
import { PushNotificationsService } from '../push-notifications/push-notifications.service';
import { RegisterDeviceTokenDto } from '../push-notifications/dto/register-device-token.dto';
import { CurrentUser } from '../common/decorators/current-user.decorator';
import { AccessTokenPayload } from '../users/services/apple-auth.service';
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
@ApiTags('用户设备')
@Controller('user/device')
@UseGuards(JwtAuthGuard)
export class UserDeviceController {
constructor(
private readonly pushNotificationsService: PushNotificationsService,
) {}
@Post('register-token')
@ApiOperation({ summary: '注册设备推送令牌' })
async registerDeviceToken(
@CurrentUser() user: AccessTokenPayload,
@Body() registerTokenDto: RegisterDeviceTokenDto,
) {
return this.pushNotificationsService.registerToken(user.sub, registerTokenDto);
}
}
```
## 预定义推送模板
系统已预置以下推送模板:
### 1. 训练提醒 (training_reminder)
- **用途**: 提醒用户完成训练
- **变量**: `{{userName}}`, `{{trainingName}}`
- **示例**: "您好张三,您今天的核心力量训练还未完成,快来打卡吧!"
### 2. 饮食记录提醒 (diet_record_reminder)
- **用途**: 提醒用户记录饮食
- **变量**: `{{userName}}`
- **示例**: "您好张三,您还没有记录今天的饮食,记得及时记录哦!"
### 3. 挑战进度 (challenge_progress)
- **用途**: 通知用户挑战进度
- **变量**: `{{challengeName}}`, `{{progress}}`
- **示例**: "恭喜您您已完成30天挑战的50%,继续加油!"
### 4. 会员到期提醒 (membership_expiring)
- **用途**: 提醒用户会员即将到期
- **变量**: `{{userName}}`, `{{days}}`
- **示例**: "您好张三您的会员将在7天后到期请及时续费以免影响使用。"
### 5. 会员已到期 (membership_expired)
- **用途**: 通知用户会员已到期
- **变量**: `{{userName}}`
- **示例**: "您好张三,您的会员已到期,请续费以继续享受会员服务。"
### 6. 成就解锁 (achievement_unlocked)
- **用途**: 庆祝用户解锁成就
- **变量**: `{{achievementName}}`
- **示例**: "恭喜您解锁了"连续训练7天"成就!"
### 7. 训练完成 (workout_completed)
- **用途**: 确认用户完成训练
- **变量**: `{{workoutName}}`, `{{calories}}`
- **示例**: "太棒了您已完成核心力量训练消耗了150卡路里。"
## 错误处理
### 常见错误码
| 错误码 | 描述 | 解决方案 |
|--------|------|----------|
| 400 | 请求参数错误 | 检查请求参数格式和必填字段 |
| 401 | 未授权访问 | 确保提供了有效的访问令牌 |
| 404 | 资源不存在 | 检查用户ID或模板键是否正确 |
| 429 | 请求频率过高 | 降低请求频率,实现退避重试 |
| 500 | 服务器内部错误 | 检查服务器日志,联系技术支持 |
### APNs错误处理
系统会自动处理以下APNs错误
- **Unregistered**: 自动停用无效的设备令牌
- **BadDeviceToken**: 记录错误并停用令牌
- **DeviceTokenNotForTopic**: 记录错误日志
- **TooManyRequests**: 实现退避重试机制
- **InternalServerError**: 自动重试
## 监控和日志
### 1. 推送状态监控
可以通过以下方式监控推送状态:
```typescript
// 获取推送统计
const stats = await this.pushMessageService.getMessageStats();
console.log(`推送成功率: ${stats.successRate}%`);
console.log(`错误分布:`, stats.errorBreakdown);
```
### 2. 日志查看
推送相关日志包含以下信息:
- 推送请求和响应
- APNs连接状态
- 错误详情和堆栈跟踪
- 性能指标
## 最佳实践
### 1. 推送时机
- 避免在深夜或凌晨发送推送
- 根据用户时区调整推送时间
- 尊重用户的推送偏好设置
### 2. 推送内容
- 保持推送内容简洁明了
- 使用个性化内容提高用户参与度
- 避免发送过于频繁的推送
### 3. 性能优化
- 使用批量推送减少网络请求
- 实现推送优先级管理
- 定期清理无效的设备令牌
### 4. 安全考虑
- 保护用户隐私数据
- 实现推送内容审核机制
- 使用HTTPS进行API通信
## 故障排除
### 1. 推送不生效
- 检查APNs配置是否正确
- 验证设备令牌是否有效
- 确认Bundle ID是否匹配
### 2. 推送延迟
- 检查网络连接状态
- 验证APNs服务器状态
- 调整推送优先级设置
### 3. 设备令牌失效
- 实现令牌自动更新机制
- 定期清理无效令牌
- 监控令牌失效率
## 扩展功能
### 1. 推送统计分析
- 实现推送打开率统计
- 分析用户行为数据
- 优化推送策略
### 2. A/B测试
- 实现推送内容A/B测试
- 比较不同推送策略效果
- 优化推送转化率
### 3. 多平台支持
- 扩展Android推送功能
- 统一推送接口设计
- 实现平台特定功能
## 总结
iOS推送功能已完全集成到系统中提供了完整的推送令牌管理、消息发送和模板系统。通过遵循本指南您可以轻松地在应用中实现各种推送场景提升用户体验和参与度。
如有任何问题或需要进一步的技术支持,请参考相关文档或联系开发团队。