474 lines
11 KiB
Markdown
474 lines
11 KiB
Markdown
# 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推送功能已完全集成到系统中,提供了完整的推送令牌管理、消息发送和模板系统。通过遵循本指南,您可以轻松地在应用中实现各种推送场景,提升用户体验和参与度。
|
||
|
||
如有任何问题或需要进一步的技术支持,请参考相关文档或联系开发团队。 |