726 lines
18 KiB
Markdown
726 lines
18 KiB
Markdown
# 后端 API 开发指南
|
||
|
||
> 本文档为 Flutter 前端已实现功能提供后端 API 接口规范,供后端开发参考。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [APK 在线升级 API](#1-apk-在线升级-api)
|
||
2. [遥测系统 API](#2-遥测系统-api)
|
||
3. [数据库设计](#3-数据库设计)
|
||
4. [Redis 数据结构](#4-redis-数据结构)
|
||
5. [定时任务](#5-定时任务)
|
||
|
||
---
|
||
|
||
## 1. APK 在线升级 API
|
||
|
||
### 1.1 版本检测接口
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /api/app/version/check
|
||
```
|
||
|
||
**Query 参数**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| platform | string | 是 | 平台类型: `android` / `ios` |
|
||
| currentVersion | string | 是 | 当前版本号,如 `1.0.0` |
|
||
| currentVersionCode | int | 是 | 当前版本代码,如 `1` |
|
||
|
||
**响应示例 - 有新版本**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"hasUpdate": true,
|
||
"version": "1.1.0",
|
||
"versionCode": 2,
|
||
"downloadUrl": "https://cdn.rwadurian.com/releases/app-v1.1.0.apk",
|
||
"fileSize": 52428800,
|
||
"fileSizeFriendly": "50.0 MB",
|
||
"sha256": "a1b2c3d4e5f6...完整64字符哈希",
|
||
"forceUpdate": false,
|
||
"updateLog": "1. 新增挖矿动画效果\n2. 修复已知BUG\n3. 性能优化",
|
||
"releaseDate": "2024-01-15T10:00:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
**响应示例 - 已是最新版本**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"hasUpdate": false
|
||
}
|
||
}
|
||
```
|
||
|
||
**前端对应代码**
|
||
|
||
```dart
|
||
// lib/core/updater/version_checker.dart
|
||
Future<VersionInfo?> checkForUpdate() async {
|
||
final response = await _dio.get(
|
||
'/api/app/version/check',
|
||
queryParameters: {
|
||
'platform': 'android',
|
||
'currentVersion': packageInfo.version,
|
||
'currentVersionCode': int.parse(packageInfo.buildNumber),
|
||
},
|
||
);
|
||
// ...
|
||
}
|
||
```
|
||
|
||
### 1.2 APK 下载
|
||
|
||
**要求**
|
||
|
||
- 下载链接必须使用 HTTPS
|
||
- 支持断点续传 (Range 请求头)
|
||
- 提供正确的 `Content-Length` 响应头
|
||
- 提供 SHA-256 校验值供前端验证文件完整性
|
||
|
||
**前端下载流程**
|
||
|
||
```
|
||
1. 请求版本检测接口获取下载信息
|
||
2. 使用 Dio 下载 APK 到应用私有目录
|
||
3. 计算下载文件 SHA-256 与服务器返回值比对
|
||
4. 校验通过后调用系统安装器安装
|
||
```
|
||
|
||
### 1.3 版本管理后台 (建议)
|
||
|
||
建议实现后台管理界面支持:
|
||
|
||
- 上传新版本 APK
|
||
- 自动计算文件大小和 SHA-256
|
||
- 设置强制更新标志
|
||
- 填写更新日志
|
||
- 查看各版本下载统计
|
||
|
||
---
|
||
|
||
## 2. 遥测系统 API
|
||
|
||
### 2.1 事件上报接口
|
||
|
||
**请求**
|
||
|
||
```
|
||
POST /api/v1/analytics/events
|
||
```
|
||
|
||
**请求头**
|
||
|
||
```
|
||
Content-Type: application/json
|
||
Authorization: Bearer <token> // 可选,用户已登录时携带
|
||
```
|
||
|
||
**请求体**
|
||
|
||
```json
|
||
{
|
||
"events": [
|
||
{
|
||
"eventId": "550e8400-e29b-41d4-a716-446655440000",
|
||
"name": "page_view",
|
||
"type": "page_view",
|
||
"level": "info",
|
||
"installId": "device-unique-install-id",
|
||
"deviceContextId": "ctx-abc123",
|
||
"sessionId": "session-xyz789",
|
||
"userId": "user-123",
|
||
"timestamp": "2024-01-15T10:30:00.000Z",
|
||
"properties": {
|
||
"page": "/ranking",
|
||
"referrer": "/splash"
|
||
}
|
||
},
|
||
{
|
||
"eventId": "550e8400-e29b-41d4-a716-446655440001",
|
||
"name": "button_click",
|
||
"type": "user_action",
|
||
"level": "info",
|
||
"installId": "device-unique-install-id",
|
||
"deviceContextId": "ctx-abc123",
|
||
"sessionId": "session-xyz789",
|
||
"userId": "user-123",
|
||
"timestamp": "2024-01-15T10:30:05.000Z",
|
||
"properties": {
|
||
"button": "start_mining",
|
||
"page": "/mining"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**事件类型枚举 (EventType)**
|
||
|
||
| 值 | 说明 |
|
||
|---|------|
|
||
| `page_view` | 页面浏览 |
|
||
| `user_action` | 用户操作 |
|
||
| `api_call` | API 调用 |
|
||
| `performance` | 性能指标 |
|
||
| `error` | 错误 |
|
||
| `crash` | 崩溃 |
|
||
| `session` | 会话事件 |
|
||
| `presence` | 在线状态 |
|
||
|
||
**事件级别枚举 (EventLevel)**
|
||
|
||
| 值 | 说明 |
|
||
|---|------|
|
||
| `debug` | 调试 |
|
||
| `info` | 信息 |
|
||
| `warning` | 警告 |
|
||
| `error` | 错误 |
|
||
|
||
**响应**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success"
|
||
}
|
||
```
|
||
|
||
**前端对应代码**
|
||
|
||
```dart
|
||
// lib/core/telemetry/uploader/telemetry_uploader.dart
|
||
Future<bool> uploadBatch({int batchSize = 20}) async {
|
||
final events = storage.dequeueEvents(batchSize);
|
||
final response = await _dio.post(
|
||
'/api/v1/analytics/events',
|
||
data: {
|
||
'events': events.map((e) => e.toJson()).toList(),
|
||
},
|
||
);
|
||
// ...
|
||
}
|
||
```
|
||
|
||
### 2.2 心跳接口 (在线状态)
|
||
|
||
**请求**
|
||
|
||
```
|
||
POST /api/v1/presence/heartbeat
|
||
```
|
||
|
||
**请求头**
|
||
|
||
```
|
||
Content-Type: application/json
|
||
Authorization: Bearer <token> // 可选
|
||
```
|
||
|
||
**请求体**
|
||
|
||
```json
|
||
{
|
||
"installId": "device-unique-install-id",
|
||
"sessionId": "session-xyz789",
|
||
"userId": "user-123",
|
||
"timestamp": "2024-01-15T10:30:00.000Z"
|
||
}
|
||
```
|
||
|
||
**响应**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success"
|
||
}
|
||
```
|
||
|
||
**前端行为**
|
||
|
||
- 应用在前台时,每 **60 秒** 发送一次心跳
|
||
- 应用进入后台时暂停心跳
|
||
- 应用恢复前台时立即发送心跳并恢复定时器
|
||
|
||
**前端对应代码**
|
||
|
||
```dart
|
||
// lib/core/telemetry/presence/heartbeat_service.dart
|
||
void _sendHeartbeat() {
|
||
_dio.post(
|
||
'/api/v1/presence/heartbeat',
|
||
data: {
|
||
'installId': _installId,
|
||
'sessionId': _sessionId,
|
||
'userId': _userId,
|
||
'timestamp': DateTime.now().toUtc().toIso8601String(),
|
||
},
|
||
);
|
||
}
|
||
```
|
||
|
||
### 2.3 遥测配置接口
|
||
|
||
**请求**
|
||
|
||
```
|
||
GET /api/telemetry/config
|
||
```
|
||
|
||
**响应**
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"enabled": true,
|
||
"samplingRate": 1.0,
|
||
"enabledEventTypes": ["page_view", "user_action", "error", "crash", "session", "presence"],
|
||
"maxQueueSize": 1000,
|
||
"uploadBatchSize": 20,
|
||
"uploadIntervalSeconds": 30,
|
||
"heartbeatIntervalSeconds": 60,
|
||
"sessionTimeoutMinutes": 30
|
||
}
|
||
}
|
||
```
|
||
|
||
**字段说明**
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| enabled | bool | 全局开关,false 时前端停止所有遥测 |
|
||
| samplingRate | double | 采样率 0.0~1.0,用于控制上报比例 |
|
||
| enabledEventTypes | string[] | 启用的事件类型列表 |
|
||
| maxQueueSize | int | 本地队列最大容量 |
|
||
| uploadBatchSize | int | 每批上传事件数量 |
|
||
| uploadIntervalSeconds | int | 上传间隔秒数 |
|
||
| heartbeatIntervalSeconds | int | 心跳间隔秒数 |
|
||
| sessionTimeoutMinutes | int | 会话超时分钟数 |
|
||
|
||
**前端对应代码**
|
||
|
||
```dart
|
||
// lib/core/telemetry/models/telemetry_config.dart
|
||
class TelemetryConfig {
|
||
final bool enabled;
|
||
final double samplingRate;
|
||
final List<String> enabledEventTypes;
|
||
final int maxQueueSize;
|
||
final int uploadBatchSize;
|
||
final int uploadIntervalSeconds;
|
||
final int heartbeatIntervalSeconds;
|
||
final int sessionTimeoutMinutes;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 数据库设计
|
||
|
||
### 3.1 应用版本表 (app_versions)
|
||
|
||
```sql
|
||
CREATE TABLE app_versions (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
platform ENUM('android', 'ios') NOT NULL,
|
||
version VARCHAR(20) NOT NULL COMMENT '版本号 如 1.0.0',
|
||
version_code INT NOT NULL COMMENT '版本代码 如 1',
|
||
download_url VARCHAR(500) NOT NULL COMMENT 'APK/IPA 下载地址',
|
||
file_size BIGINT NOT NULL COMMENT '文件大小(字节)',
|
||
sha256 CHAR(64) NOT NULL COMMENT 'SHA-256 哈希值',
|
||
force_update TINYINT(1) DEFAULT 0 COMMENT '是否强制更新',
|
||
update_log TEXT COMMENT '更新日志',
|
||
release_date DATETIME NOT NULL COMMENT '发布时间',
|
||
is_active TINYINT(1) DEFAULT 1 COMMENT '是否激活',
|
||
download_count INT DEFAULT 0 COMMENT '下载次数',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
|
||
UNIQUE KEY uk_platform_version (platform, version_code),
|
||
INDEX idx_platform_active (platform, is_active)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用版本管理';
|
||
```
|
||
|
||
### 3.2 遥测事件表 (analytics_events)
|
||
|
||
```sql
|
||
CREATE TABLE analytics_events (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
event_id VARCHAR(36) NOT NULL COMMENT '事件唯一ID (UUID)',
|
||
name VARCHAR(100) NOT NULL COMMENT '事件名称',
|
||
type ENUM('page_view', 'user_action', 'api_call', 'performance', 'error', 'crash', 'session', 'presence') NOT NULL,
|
||
level ENUM('debug', 'info', 'warning', 'error') DEFAULT 'info',
|
||
install_id VARCHAR(100) NOT NULL COMMENT '设备安装ID',
|
||
device_context_id VARCHAR(100) COMMENT '设备上下文ID',
|
||
session_id VARCHAR(100) COMMENT '会话ID',
|
||
user_id VARCHAR(100) COMMENT '用户ID',
|
||
properties JSON COMMENT '事件属性',
|
||
event_time DATETIME(3) NOT NULL COMMENT '事件发生时间',
|
||
received_at DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '服务器接收时间',
|
||
|
||
UNIQUE KEY uk_event_id (event_id),
|
||
INDEX idx_install_id (install_id),
|
||
INDEX idx_user_id (user_id),
|
||
INDEX idx_session_id (session_id),
|
||
INDEX idx_type_time (type, event_time),
|
||
INDEX idx_event_time (event_time)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='遥测事件记录'
|
||
PARTITION BY RANGE (TO_DAYS(event_time)) (
|
||
PARTITION p_default VALUES LESS THAN MAXVALUE
|
||
);
|
||
```
|
||
|
||
> 建议按天分区,便于数据清理和查询优化
|
||
|
||
### 3.3 设备上下文表 (device_contexts)
|
||
|
||
```sql
|
||
CREATE TABLE device_contexts (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
context_id VARCHAR(100) NOT NULL COMMENT '上下文ID',
|
||
install_id VARCHAR(100) NOT NULL COMMENT '设备安装ID',
|
||
platform VARCHAR(20) NOT NULL COMMENT '平台 android/ios',
|
||
brand VARCHAR(50) COMMENT '品牌',
|
||
model VARCHAR(100) COMMENT '型号',
|
||
manufacturer VARCHAR(100) COMMENT '制造商',
|
||
is_physical_device TINYINT(1) COMMENT '是否真机',
|
||
os_version VARCHAR(50) COMMENT '系统版本',
|
||
sdk_int INT COMMENT 'SDK版本号',
|
||
android_id VARCHAR(100) COMMENT 'Android ID',
|
||
screen_width INT COMMENT '屏幕宽度',
|
||
screen_height INT COMMENT '屏幕高度',
|
||
screen_density DECIMAL(4,2) COMMENT '屏幕密度',
|
||
app_name VARCHAR(100) COMMENT '应用名称',
|
||
package_name VARCHAR(200) COMMENT '包名',
|
||
app_version VARCHAR(20) COMMENT '应用版本',
|
||
build_number VARCHAR(20) COMMENT '构建号',
|
||
build_mode VARCHAR(20) COMMENT '构建模式 debug/release',
|
||
locale VARCHAR(20) COMMENT '语言区域',
|
||
timezone VARCHAR(50) COMMENT '时区',
|
||
network_type VARCHAR(20) COMMENT '网络类型',
|
||
is_dark_mode TINYINT(1) COMMENT '是否深色模式',
|
||
collected_at DATETIME(3) NOT NULL COMMENT '采集时间',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
|
||
UNIQUE KEY uk_context_id (context_id),
|
||
INDEX idx_install_id (install_id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备上下文信息';
|
||
```
|
||
|
||
### 3.4 日活统计表 (analytics_daily_active)
|
||
|
||
```sql
|
||
CREATE TABLE analytics_daily_active (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
stat_date DATE NOT NULL COMMENT '统计日期',
|
||
total_dau INT DEFAULT 0 COMMENT '总DAU',
|
||
new_users INT DEFAULT 0 COMMENT '新用户数',
|
||
returning_users INT DEFAULT 0 COMMENT '回访用户数',
|
||
total_sessions INT DEFAULT 0 COMMENT '总会话数',
|
||
avg_session_duration INT DEFAULT 0 COMMENT '平均会话时长(秒)',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
|
||
UNIQUE KEY uk_stat_date (stat_date)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日活统计汇总';
|
||
```
|
||
|
||
### 3.5 在线快照表 (analytics_online_snapshots)
|
||
|
||
```sql
|
||
CREATE TABLE analytics_online_snapshots (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
snapshot_time DATETIME NOT NULL COMMENT '快照时间',
|
||
online_count INT NOT NULL COMMENT '在线人数',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
|
||
INDEX idx_snapshot_time (snapshot_time)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='在线人数快照';
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Redis 数据结构
|
||
|
||
### 4.1 在线用户集合 (实时在线统计)
|
||
|
||
**Key**: `presence:online_users`
|
||
**Type**: Sorted Set (ZSET)
|
||
**Score**: 最后心跳时间戳 (Unix timestamp)
|
||
**Member**: `installId` 或 `userId` (取决于是否登录)
|
||
|
||
```redis
|
||
# 用户发送心跳时
|
||
ZADD presence:online_users <timestamp> <installId>
|
||
|
||
# 获取在线人数 (2分钟内有心跳的用户)
|
||
ZCOUNT presence:online_users <now - 120> <now>
|
||
|
||
# 清理过期用户 (可选,定时任务执行)
|
||
ZREMRANGEBYSCORE presence:online_users -inf <now - 120>
|
||
```
|
||
|
||
**在线判定规则**
|
||
|
||
用户最后心跳时间在 **2 分钟** 内视为在线(心跳间隔 60 秒,允许 1 次丢失)
|
||
|
||
### 4.2 日活去重集合
|
||
|
||
**Key**: `analytics:dau:<date>` (如 `analytics:dau:2024-01-15`)
|
||
**Type**: Set
|
||
**Member**: `installId`
|
||
**TTL**: 48 小时
|
||
|
||
```redis
|
||
# 记录日活
|
||
SADD analytics:dau:2024-01-15 <installId>
|
||
EXPIRE analytics:dau:2024-01-15 172800
|
||
|
||
# 获取当日DAU
|
||
SCARD analytics:dau:2024-01-15
|
||
```
|
||
|
||
### 4.3 会话缓存
|
||
|
||
**Key**: `session:<sessionId>`
|
||
**Type**: Hash
|
||
**TTL**: 30 分钟 (随活动更新)
|
||
|
||
```redis
|
||
HSET session:xyz789
|
||
installId "device-xxx"
|
||
userId "user-123"
|
||
startTime "2024-01-15T10:00:00Z"
|
||
lastActiveTime "2024-01-15T10:30:00Z"
|
||
|
||
EXPIRE session:xyz789 1800
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 定时任务
|
||
|
||
### 5.1 DAU 统计任务
|
||
|
||
**执行频率**: 每天凌晨 00:05
|
||
|
||
```python
|
||
# 伪代码
|
||
def calculate_daily_dau():
|
||
yesterday = date.today() - timedelta(days=1)
|
||
date_str = yesterday.strftime('%Y-%m-%d')
|
||
|
||
# 从 Redis 获取昨日 DAU
|
||
dau_key = f'analytics:dau:{date_str}'
|
||
total_dau = redis.scard(dau_key)
|
||
|
||
# 或从数据库统计 (session_start 事件去重)
|
||
total_dau = db.query("""
|
||
SELECT COUNT(DISTINCT install_id)
|
||
FROM analytics_events
|
||
WHERE type = 'session'
|
||
AND name = 'session_start'
|
||
AND DATE(event_time) = %s
|
||
""", [date_str])
|
||
|
||
# 统计新用户 (首次出现的 install_id)
|
||
new_users = db.query("""
|
||
SELECT COUNT(*) FROM (
|
||
SELECT install_id
|
||
FROM analytics_events
|
||
WHERE type = 'session' AND name = 'session_start'
|
||
GROUP BY install_id
|
||
HAVING MIN(DATE(event_time)) = %s
|
||
) t
|
||
""", [date_str])
|
||
|
||
# 写入统计表
|
||
db.upsert('analytics_daily_active', {
|
||
'stat_date': date_str,
|
||
'total_dau': total_dau,
|
||
'new_users': new_users,
|
||
'returning_users': total_dau - new_users
|
||
})
|
||
```
|
||
|
||
### 5.2 在线人数快照任务
|
||
|
||
**执行频率**: 每 5 分钟
|
||
|
||
```python
|
||
# 伪代码
|
||
def snapshot_online_count():
|
||
now = datetime.now()
|
||
threshold = now - timedelta(minutes=2)
|
||
|
||
# 从 Redis 获取在线人数
|
||
online_count = redis.zcount(
|
||
'presence:online_users',
|
||
threshold.timestamp(),
|
||
now.timestamp()
|
||
)
|
||
|
||
# 写入快照表
|
||
db.insert('analytics_online_snapshots', {
|
||
'snapshot_time': now,
|
||
'online_count': online_count
|
||
})
|
||
```
|
||
|
||
### 5.3 过期数据清理任务
|
||
|
||
**执行频率**: 每天凌晨 03:00
|
||
|
||
```python
|
||
# 伪代码
|
||
def cleanup_expired_data():
|
||
# 清理 30 天前的事件数据
|
||
retention_days = 30
|
||
cutoff_date = date.today() - timedelta(days=retention_days)
|
||
|
||
db.execute("""
|
||
DELETE FROM analytics_events
|
||
WHERE event_time < %s
|
||
LIMIT 100000
|
||
""", [cutoff_date])
|
||
|
||
# 清理 Redis 过期在线状态
|
||
redis.zremrangebyscore(
|
||
'presence:online_users',
|
||
'-inf',
|
||
(datetime.now() - timedelta(minutes=5)).timestamp()
|
||
)
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 前端关键行为说明
|
||
|
||
### 6.1 会话管理
|
||
|
||
**会话开始条件**:
|
||
- 应用冷启动
|
||
- 应用从后台恢复且距上次活动超过 30 分钟
|
||
|
||
**会话结束条件**:
|
||
- 应用进入后台
|
||
|
||
**前端发送事件**:
|
||
|
||
```dart
|
||
// 会话开始
|
||
TelemetryService().trackEvent(
|
||
name: SessionEvents.sessionStart,
|
||
type: EventType.session,
|
||
properties: {'trigger': 'app_launch'},
|
||
);
|
||
|
||
// 会话结束
|
||
TelemetryService().trackEvent(
|
||
name: SessionEvents.sessionEnd,
|
||
type: EventType.session,
|
||
properties: {
|
||
'duration_seconds': duration,
|
||
'trigger': 'app_pause',
|
||
},
|
||
);
|
||
```
|
||
|
||
### 6.2 事件上报策略
|
||
|
||
- **队列阈值触发**: 本地队列 ≥10 条时触发上传
|
||
- **定时触发**: 每 30 秒检查一次
|
||
- **应用退出触发**: 强制上传全部队列
|
||
- **批量大小**: 每批最多 20 条
|
||
|
||
### 6.3 设备上下文
|
||
|
||
前端采集设备信息后生成唯一 `deviceContextId`,同一设备配置不变时复用相同 ID。设备信息变化(如系统升级)时生成新 ID。
|
||
|
||
---
|
||
|
||
## 7. API 错误码规范
|
||
|
||
| code | 说明 |
|
||
|------|------|
|
||
| 0 | 成功 |
|
||
| 1001 | 参数错误 |
|
||
| 1002 | 认证失败 |
|
||
| 2001 | 服务器内部错误 |
|
||
| 2002 | 数据库错误 |
|
||
| 3001 | 版本不存在 |
|
||
| 3002 | 下载链接已过期 |
|
||
|
||
---
|
||
|
||
## 8. 安全建议
|
||
|
||
1. **APK 下载**
|
||
- 使用 HTTPS
|
||
- 提供 SHA-256 校验
|
||
- 下载链接可设置有效期
|
||
|
||
2. **遥测数据**
|
||
- 不采集敏感个人信息 (如通讯录、短信)
|
||
- installId 使用 UUID 生成,不关联设备硬件标识
|
||
- 支持用户关闭遥测 (通过远程配置)
|
||
|
||
3. **心跳接口**
|
||
- 防刷限流 (每个 installId 每分钟最多 2 次)
|
||
- 异常流量监控
|
||
|
||
---
|
||
|
||
## 附录: 前端代码目录结构
|
||
|
||
```
|
||
lib/core/
|
||
├── updater/ # APK升级模块
|
||
│ ├── models/
|
||
│ │ ├── version_info.dart # 版本信息模型
|
||
│ │ └── update_config.dart # 更新配置模型
|
||
│ ├── channels/
|
||
│ │ ├── google_play_updater.dart # Google Play更新器
|
||
│ │ └── self_hosted_updater.dart # 自建服务器更新器
|
||
│ ├── version_checker.dart # 版本检测器
|
||
│ ├── download_manager.dart # 下载管理器
|
||
│ ├── apk_installer.dart # APK安装器
|
||
│ ├── app_market_detector.dart # 应用市场检测
|
||
│ └── update_service.dart # 统一更新服务
|
||
│
|
||
└── telemetry/ # 遥测模块
|
||
├── models/
|
||
│ ├── device_context.dart # 设备上下文模型
|
||
│ ├── telemetry_event.dart # 遥测事件模型
|
||
│ └── telemetry_config.dart # 遥测配置模型
|
||
├── collectors/
|
||
│ └── device_info_collector.dart # 设备信息采集器
|
||
├── storage/
|
||
│ └── telemetry_storage.dart # 本地事件存储
|
||
├── uploader/
|
||
│ └── telemetry_uploader.dart # 事件上传器
|
||
├── session/
|
||
│ ├── session_events.dart # 会话事件常量
|
||
│ └── session_manager.dart # 会话管理器
|
||
├── presence/
|
||
│ ├── presence_config.dart # 心跳配置
|
||
│ └── heartbeat_service.dart # 心跳服务
|
||
└── telemetry_service.dart # 遥测服务入口
|
||
```
|