更新
This commit is contained in:
parent
4e211ed1fe
commit
7eb8c3a5ad
@ -4,10 +4,10 @@
|
||||
<selectionStates>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DropdownSelection timestamp="2026-03-25T08:24:18.087919900Z">
|
||||
<DropdownSelection timestamp="2026-03-26T12:09:09.946169900Z">
|
||||
<Target type="DEFAULT_BOOT">
|
||||
<handle>
|
||||
<DeviceId pluginId="Default" identifier="serial=emulator-5554;connection=1f9ceb70" />
|
||||
<DeviceId pluginId="PhysicalDevice" identifier="serial=lvzdxotknne6u4nv" />
|
||||
</handle>
|
||||
</Target>
|
||||
</DropdownSelection>
|
||||
|
||||
6
SMS/.idea/vcs.xml
Normal file
6
SMS/.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
首次进入 App 会让你填写:
|
||||
|
||||
- `backendUrl`:例如 `http://192.168.1.10:7788`
|
||||
- `backendUrl`:例如 `https://yzsms.yunzer.cn`
|
||||
- `apiKey`:后端 `.env` 里的 `SMS_GATEWAY_API_KEY`
|
||||
- (不再需要 `deviceId`:由后端根据 `apiKey` 自动归属任务/短信)
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -2,6 +2,7 @@
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
<uses-permission android:name="android.permission.READ_SMS" />
|
||||
<uses-permission android:name="android.permission.SEND_SMS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
18
SMS/app/src/main/java/com/yunzer/sms/SmsDeliverReceiver.kt
Normal file
18
SMS/app/src/main/java/com/yunzer/sms/SmsDeliverReceiver.kt
Normal file
@ -0,0 +1,18 @@
|
||||
package com.yunzer.sms
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
/**
|
||||
* 用于接收 SMS_DELIVER(默认短信应用角色相关)。
|
||||
* 这里复用现有 SmsReceiver 的处理逻辑。
|
||||
*/
|
||||
class SmsDeliverReceiver : BroadcastReceiver() {
|
||||
private val delegate = SmsReceiver()
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
delegate.onReceive(context, intent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,6 +68,13 @@ npm start
|
||||
- `onlyMatched=true`:只返回 `parseStatus=matched` 的验证码
|
||||
- 返回:`{ inbounds: [...] }`
|
||||
|
||||
6. 业务系统查询出站发送任务状态(新增)
|
||||
- `GET /api/v1/business/outbound-tasks?limit=50&status=&phone=`
|
||||
- 请求头:`X-Api-Key: <SMS_GATEWAY_API_KEY>`
|
||||
- status 取值:
|
||||
- `pending` / `sending` / `failed` / `success`
|
||||
- 返回:`{ tasks: [{ taskId, phone, content, status, ...}] }`
|
||||
|
||||
## 数据表
|
||||
|
||||
- `inbound_sms`
|
||||
|
||||
BIN
backend/backend.zip
Normal file
BIN
backend/backend.zip
Normal file
Binary file not shown.
@ -183,6 +183,65 @@ router.post("/api/v1/business/outbound-tasks", (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 6) 业务侧查询发送任务状态(用于业务系统展示)
|
||||
router.get("/api/v1/business/outbound-tasks", (req, res) => {
|
||||
const deviceId = getDeviceIdFromHeader(req);
|
||||
if (!deviceId) return res.status(401).json({ error: "missing api key for device identification" });
|
||||
|
||||
const limit = Math.min(Number(req.query.limit || 50), 200);
|
||||
const status = req.query.status ? String(req.query.status) : "";
|
||||
const phone = req.query.phone ? safeString(req.query.phone) : "";
|
||||
|
||||
try {
|
||||
const where = ["device_id = ?"];
|
||||
const params = [deviceId];
|
||||
|
||||
if (status !== "") {
|
||||
where.push("status = ?");
|
||||
params.push(status);
|
||||
}
|
||||
if (phone !== "") {
|
||||
where.push("phone LIKE ?");
|
||||
params.push(`%${phone}%`);
|
||||
}
|
||||
|
||||
const rows = db
|
||||
.prepare(
|
||||
`
|
||||
SELECT
|
||||
task_id,
|
||||
phone,
|
||||
content,
|
||||
status,
|
||||
retry_count,
|
||||
last_error,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM outbound_tasks
|
||||
WHERE ${where.join(" AND ")}
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ?
|
||||
`
|
||||
)
|
||||
.all(...params, limit);
|
||||
|
||||
res.json({
|
||||
tasks: rows.map((r) => ({
|
||||
taskId: r.task_id,
|
||||
phone: r.phone,
|
||||
content: r.content,
|
||||
status: r.status,
|
||||
retryCount: r.retry_count,
|
||||
lastError: r.last_error,
|
||||
createdAt: r.created_at,
|
||||
updatedAt: r.updated_at,
|
||||
})),
|
||||
});
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: "failed to query outbound tasks", detail: String(e?.message || e) });
|
||||
}
|
||||
});
|
||||
|
||||
// 5) 业务侧读取入站验证码(MVP 用)
|
||||
router.get("/api/v1/business/inbound-sms", (req, res) => {
|
||||
const deviceId = getDeviceIdFromHeader(req);
|
||||
|
||||
@ -60,6 +60,15 @@
|
||||
|
||||
## 5. Android 权限与系统能力
|
||||
|
||||
### 5.3 默认短信应用角色(ROLE_SMS)
|
||||
部分 Android 系统/ROM 在后台/静默发送短信时,会要求应用先成为“默认短信应用”(`ROLE_SMS`)。
|
||||
如果你发现需要手动确认发送(或发送会被系统拦截),请按以下方式处理:
|
||||
|
||||
1. 首次启动 App,点击保存配置后等待系统弹出“默认短信应用”角色授权(系统界面可能叫“短信应用/默认短信应用”)
|
||||
2. 授权完成后,App 的前台服务会继续轮询并自动发送,无需每次手动确认
|
||||
|
||||
> 说明:`ROLE_SMS` 授权至少需要一次用户确认,之后应自动生效。
|
||||
|
||||
## 5.1 必要权限
|
||||
|
||||
在 `AndroidManifest.xml` 中声明:
|
||||
|
||||
@ -46,7 +46,25 @@ npm start
|
||||
3. 安卓端把入站验证码短信通过 `POST /api/v1/sms/inbound` 上报后端
|
||||
4. 你业务系统再从后端读取/查询验证码结果(你可在现有业务端对接这些接口)
|
||||
|
||||
## 4. 后续扩展建议
|
||||
## 4. 业务系统接入(对接示例:TP 管理后台)
|
||||
如果你的业务系统是 ThinkPHP(例如你现在的 TP 后台管理页),建议不要直接写本仓库的数据库表,而是调用本短信网关后端提供的入队接口:
|
||||
|
||||
1) 确保安卓端填写的 `backendUrl` 指向本短信网关后端(例如 `https://yzsms.yunzer.cn`)
|
||||
2) 确保安卓端填写的 `apiKey` 与后端 `.env` 里的 `SMS_GATEWAY_API_KEY` 完全一致
|
||||
3) 业务系统发送短信时,调用:
|
||||
- `POST {backendUrl}/api/v1/business/outbound-tasks`
|
||||
- 请求头:`X-Api-Key: SMS_GATEWAY_API_KEY`
|
||||
- body:`{ "phone": "+8613712345678", "content": "短信测试验证码:123456" }`
|
||||
4) 安卓端会通过轮询:
|
||||
- `GET {backendUrl}/api/v1/device/tasks`
|
||||
自动拉取任务并发送,然后回传到:
|
||||
- `POST {backendUrl}/api/v1/sms/outbound/result`
|
||||
|
||||
5) 查询发送任务状态(可选,用于业务侧展示)
|
||||
- `GET {backendUrl}/api/v1/business/outbound-tasks?limit=50`
|
||||
- 请求头:`X-Api-Key: SMS_GATEWAY_API_KEY`
|
||||
|
||||
## 5. 后续扩展建议
|
||||
|
||||
- 增加任务重试与失败原因字段
|
||||
- 增加短信去重与解析规则配置(正则规则下发)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user