80ee99e564a2376cf7502e69163aa86098a190c5
SMS Monitor
一个基于 Android + Node.js 的个人短信监控系统。Android App 读取手机短信并上传至服务器,Web Dashboard 提供网页端查看与管理。
项目架构
┌─────────────────┐ HTTP / JSON ┌─────────────────┐ SQL ┌──────────┐
│ Android App │ ────────────────────→ │ Node.js Server │ ──────────→ │ SQLite │
│ (Flutter) │ │ (Express) │ │ │
└─────────────────┘ └────────┬────────┘ └──────────┘
│
│ REST API
▼
┌─────────────────┐
│ Web Dashboard │
│ (React + Vite) │
└─────────────────┘
- App 端:Flutter 编写,仅支持 Android。读取系统短信数据库 + 实时监听新短信,支持自动/手动上传。
- 服务端:Node.js + Express 提供 REST API,JWT 鉴权,SQLite 存储。
- Web 端:React + Vite SPA,Material You 风格,登录后查看/筛选/删除短信。
技术栈
| 层级 | 技术 | 说明 |
|---|---|---|
| Android App | Flutter 3.2+ | dynamic_color Material You 主题 |
| 短信读取 | sms_maintained |
查询系统短信数据库 + 接收新短信广播 |
| 权限管理 | permission_handler |
Android SMS 权限 |
| 后端框架 | Express 4.x | TypeScript 编写 |
| 数据库 | better-sqlite3 | WAL 模式,同步 API |
| 鉴权 | JWT (jsonwebtoken) | 30 天有效期 |
| 密码加密 | bcryptjs | 10 轮哈希 |
| 前端框架 | React 18 + Vite 6 | TypeScript |
| HTTP 客户端 | fetch (内置) | 无额外依赖 |
目录结构
transfer_sms/
├── server/
│ ├── package.json
│ ├── tsconfig.json
│ └── src/
│ ├── index.ts # Express 入口,挂载路由
│ ├── db.ts # SQLite 初始化 + 自动建表
│ ├── types.ts # TypeScript 类型定义
│ ├── middleware/
│ │ └── auth.ts # JWT Bearer Token 鉴权中间件
│ └── routes/
│ ├── auth.ts # POST /api/auth/register, /api/auth/login
│ ├── sms.ts # POST /api/sms/upload, GET /api/sms, DELETE /api/sms/:id
│ └── devices.ts # POST /api/devices/register
├── web/
│ ├── package.json
│ ├── vite.config.ts # 开发代理 /api → localhost:3000
│ └── src/
│ ├── main.tsx # 入口
│ ├── App.tsx # 路由:未登录 → Login,已登录 → SmsList
│ ├── api.ts # 封装 fetch 调用
│ ├── index.css # Material You CSS 变量 + 基础样式
│ └── pages/
│ ├── Login.tsx / .css # 登录/注册页
│ └── SmsList.tsx / .css # 短信列表 + 详情面板 + 筛选
└── app/
├── pubspec.yaml
└── lib/
├── main.dart # 入口,DynamicColorBuilder 主题
├── models/
│ └── sms_message.dart # SmsMessage 数据类 + JSON 序列化
├── services/
│ ├── api_service.dart # HTTP 客户端
│ ├── sms_reader_service.dart # 查询/监听系统短信
│ └── settings_service.dart # SharedPreferences 读写
└── screens/
├── login_screen.dart # 服务器地址 + 用户名密码登录
├── home_screen.dart # NavigationBar Tab 容器
├── sms_list_screen.dart # 短信列表 + 选择上传 + 自动模式
└── settings_screen.dart # 服务器信息 + 上传模式 + 登出
快速开始
1. 启动服务端
cd server
npm install
npm run dev
# 服务运行在 http://localhost:3000
2. 启动 Web Dashboard
cd web
npm install
npm run dev
# 访问 http://localhost:5173
Vite 开发服务器已配置 API 代理,/api/* 请求会自动转发到 localhost:3000。
3. 运行 Flutter App
cd app
flutter pub get
flutter run
需要 Android 设备或模拟器,且需要安装 Flutter SDK。
API 文档
所有 API 均返回 JSON。需要鉴权的接口在 Header 中携带 Authorization: Bearer <token>。
认证
POST /api/auth/register
注册新用户,成功后直接返回 JWT token。
Request:
{
"username": "alice", // 3-50 字符
"password": "123456" // 6-100 字符
}
Response 201:
{
"token": "eyJhbG...",
"userId": 1
}
Error 409: { "error": "Username already taken" }
Error 400: { "error": [...] } // 参数校验失败
POST /api/auth/login
登录已有用户。
Request:
{
"username": "alice",
"password": "123456"
}
Response 200:
{
"token": "eyJhbG...",
"userId": 1
}
Error 401: { "error": "Invalid credentials" }
短信
POST /api/sms/upload
批量上传短信,单次不超过 5MB。
Headers: Authorization: Bearer <token>
Request:
[
{
"phone_number": "+8613800138000",
"contact_name": "张三", // 可选
"content": "你好,明天见面聊",
"type": "received", // "received" | "sent"
"sms_date": "2026-04-28T10:30:00.000Z" // ISO 8601
}
]
Response 200:
{
"uploaded": 1 // 成功插入条数
}
GET /api/sms
分页查询当前用户的短信。
Headers: Authorization: Bearer <token>
Query:
page - 页码,默认 1
limit - 每页条数,默认 20,最大 100
phone - 按手机号模糊搜索(可选)
type - 按类型筛选,"received" | "sent"(可选)
Response 200:
{
"messages": [ ... ],
"total": 42,
"page": 1,
"limit": 20,
"totalPages": 3
}
GET /api/sms/:id
查看单条短信详情。
Response 200:
{
"id": 1,
"user_id": 1,
"phone_number": "+8613800138000",
"contact_name": "张三",
"content": "你好,明天见面聊",
"type": "received",
"sms_date": "2026-04-28T10:30:00.000Z",
"created_at": "2026-04-28 12:00:00"
}
Error 404: { "error": "Not found" }
DELETE /api/sms/:id
删除一条短信(仅限自己的)。
Response 200: { "deleted": true }
Error 404: { "error": "Not found" }
设备
POST /api/devices/register
注册设备,重复注册同名设备会更新同步时间。
Request:
{
"device_name": "Pixel 8 Pro"
}
Response 201: { "deviceId": 1 }
数据库
使用 SQLite,数据库文件自动创建在 server/data.db。
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE sms_messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id),
phone_number TEXT NOT NULL,
contact_name TEXT,
content TEXT NOT NULL,
type TEXT NOT NULL CHECK(type IN ('received', 'sent')),
sms_date DATETIME NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_sms_user ON sms_messages(user_id, sms_date);
CREATE TABLE devices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id),
device_name TEXT NOT NULL,
last_sync_at DATETIME
);
App 功能说明
登录
- 首次使用需填写服务器地址、用户名和密码
- 支持注册新用户或登录已有账号
- 配置自动保存至 SharedPreferences
短信列表
- 读取手机所有短信(收件箱 + 已发送)
- 每条短信显示联系人、内容摘要、类型箭头图标
- 多选模式:点击短信或圆圈图标选中,选中的显示对号
- 点击云上传按钮上传已选中的短信
- 点击右下角悬浮按钮一键上传全部短信
上传模式
- 手动模式(默认):用户选择短信后点击上传
- 自动模式:开启后实时监听新短信,自动上传到服务器
- 自动模式下新的入站短信会立即出现在列表中
设置
- 查看当前服务器地址和 Token 状态
- 切换自动/手动上传模式
- 登出按钮清除 Token 并返回登录页
Web Dashboard 功能说明
登录页
- 用户名 + 密码登录或注册
- Material You 风格卡片布局
短信列表页
- 表格展示所有上传的短信
- 按手机号码模糊搜索
- 按类型(发送/接收)下拉筛选
- 分页浏览,支持 Prev/Next
- 点击行查看详情面板(右侧)
- 每条短信可单独删除
安全说明
- 密码经 bcrypt(10轮)哈希存储,不保存明文
- JWT token 有效期 30 天
- 所有短信接口均需认证,用户只能访问自己的数据
- 生产环境请修改
JWT_SECRET环境变量
JWT_SECRET=your-secret-key npm run dev
环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
PORT |
3000 | 服务端口 |
JWT_SECRET |
内置默认值 | JWT 签名密钥,生产环境必须修改 |
验证测试
# 注册用户
curl -s -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"123456"}'
# 登录获取 token
TOKEN=$(curl -s -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"123456"}' | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
# 上传短信
curl -s -X POST http://localhost:3000/api/sms/upload \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '[{"phone_number":"+8613800138000","contact_name":"张三","content":"你好","type":"received","sms_date":"2026-04-28T10:30:00.000Z"}]'
# 查询短信列表
curl -s http://localhost:3000/api/sms -H "Authorization: Bearer $TOKEN"
# 删除
curl -s -X DELETE http://localhost:3000/api/sms/1 -H "Authorization: Bearer $TOKEN"
Description
Languages
HTML
56.7%
Dart
11.6%
C++
10.5%
CMake
8.1%
TypeScript
7%
Other
6%