接上回书,我用旧的小米 9 搭了一个我的世界服务器,用的是手机流量。但是有一个问题,我每次看还剩多少话费还得解锁手机,万一我忘了有这回事,错过了运营商发的扣费短信怎么办?我得想个办法随时看到手机短信。于是有了这套方案。
QQ 机器人
我刚好有一个 QQ 机器人,用的 nonebot 框架,python 写的。QQ 能干的它都能干(除了红包相关的),所以我决定加一个功能,轮询手机里的短信,把新的短信发送到我的 QQ 私聊里。
开始搞机
首先得知道手机短信到底存在哪里。我在网上搜到了短信存放在一个 SQLite 格式的 db 文件里,路径是 /data/data/com.android.providers.telephony/databases/mmssms.db
。想在 Linux Deploy 里看到这个文件还需要启动 Linux 的时候配置挂载安卓上的资源,我把安卓上的 /data/data 目录挂载到 Linux 上的 /data/data 目录。
这时就可以读这个文件了。Linux 系统默认会装 sqlite3,如果没有的话可以用 apt 或者 yum 装一下。
对了,先研究一下表结构。把文件下载到 windows,然后用 Data Grip 看看里面到底长啥样。
表结构
有用的表就 2 个,分别是 sms 和 canonical_addresses。
sms
sms 表是每一条短信的各种信息,我们重点关注下面几个字段。
create table sms
(
-- 主键
_id INTEGER
primary key,
-- 发信人地址
address TEXT,
-- 是否已读,0 表示未读,1 表示已读
read INTEGER default 0,
-- 消息的内容
body TEXT,
);
canonical_addresses
这个表存储了发信人地址和发信人的名字。比如说 10001 是中国电信。
create table canonical_addresses
(
-- 主键
_id INTEGER
primary key autoincrement,
-- 发信人地址
address TEXT,
-- 发信人名字
name TEXT
);
查询 sql
查询的时候只要把这两张表连接起来,就能一起查到发信人名字和信息的内容了。
select
sms._id,
sms.body,
sms.address,
case
when ca.name is null
then '未知号码'
else ca.name
end as address_name
from
sms left join canonical_addresses as ca on sms.address=ca.address
where sms.type=1 and sms.read=0
把 read 字段为 0 (也就是未读)的短信查出来,遍历结果集,把结果集里的每一条短信每隔 5 秒发送私聊消息给我的 QQ,发送完之后把 read 字段置为 1,表示我已经读过了。
update sms set read=1 where _id={data.get('_id')}
这里用了 python 的 fstring 拼接字符串,还是挺方便的,也没有 sql 注入啥的问题。
结尾
重启机器人后顺利收到了消息,但我并不想在这一篇文里谈机器人的细节,所以就这样吧。
有兴趣的话可以自己看看 nonebot 文档 和 gocqhttp 文档。
![](https://www.chenz.icu/post-images/1664713557294.jpg)