news 2026/8/23 12:22:48

剖析 Connect You 短信模块源码:BroadcastReceiver 与 HeadlessSmsSendService 如何实现离线收发短信

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
剖析 Connect You 短信模块源码:BroadcastReceiver 与 HeadlessSmsSendService 如何实现离线收发短信

剖析 Connect You 短信模块源码:BroadcastReceiver 与 HeadlessSmsSendService 如何实现离线收发短信

【免费下载链接】ConnectYouPrivacy focused contacts and SMS messenger app built with MD3项目地址: https://gitcode.com/gh_mirrors/co/ConnectYou

Connect You 是一款注重隐私的开源联系人 + 短信应用,采用 Material Design 3 风格构建。它的短信模块完全运行在设备本地:不依赖任何第三方服务器,收信靠 Android 系统广播BroadcastReceiver,发信靠系统SmsManager加回执接收器,配合一个名为HeadlessSmsSendService的无头服务,实现了真正的"离线收发短信"。本文带你逐层拆解这套机制,新手也能看懂。

短信模块全景:4 个 Receiver + 1 个 Service

整个短信收发链路由以下几类组件协作完成,核心代码集中在app/src/main/java/com/bnyro/contacts/util/目录下:

组件位置职责
SmsReceiverapp/src/main/java/com/bnyro/contacts/util/receivers/SmsReceiver.kt接收系统SMS_DELIVER广播,入库并弹通知
ReplyReceiverapp/src/main/java/com/bnyro/contacts/util/receivers/ReplyReceiver.kt处理通知栏"快速回复"
SmsSentReceiverapp/src/main/java/com/bnyro/contacts/util/receivers/SmsSentReceiver.kt接收发送回执,更新状态
SmsDeliveredReceiverapp/src/main/java/com/bnyro/contacts/util/receivers/SmsDeliveredReceiver.kt接收对方送达回执,更新状态
HeadlessSmsSendServiceapp/src/main/java/com/bnyro/contacts/util/services/HeadlessSmsSendService.kt声明为短信类应用,支持系统快速回复

一条短信从"进入手机"到"发出并回执",完整闭环如下:

收到短信: 基带 → SMS_DELIVER 广播 → SmsReceiver → 系统短信库 → 通知栏(可回复/删除) 发出短信: 用户点击发送 → SmsUtil.sendSms() → 先入库 → SmsManager.sendTextMessage() → SmsSentReceiver(发送回执) → SmsDeliveredReceiver(送达回执) → 状态更新

收短信:BroadcastReceiver 如何拦截 SMS_DELIVER 广播

Android 收到短信后,会向系统广播一条android.provider.Telephony.SMS_DELIVER广播。Connect You 的 SmsReceiver 就是专门监听这个广播的"守门员",它的处理流程分三步:

  1. 过滤广播onReceive第一行就检查intent.action != SMS_DELIVER,只处理短信到达事件,其余广播直接忽略;
  2. 解析并入库:用Telephony.Sms.Intents.getMessagesFromIntent()拆出短信内容(长短信会拆成多条,需要逐条处理),取出号码、正文、时间戳,通过仓库层smsRepo.getOrCreateThreadId()找到对话线程 ID,再调用persistSms()写入系统短信数据库;
  3. 弹出可交互通知:入库后立刻构建一条 Material 风格的MessagingStyle通知,包含三个动作按钮——"回复"(带RemoteInput输入框)、"删除",以及一个隐藏彩蛋:如果短信正文中检测到 6 位数字验证码(正则(?<!\d)\d{6}(?!\d),见 SmsReceiver.kt#L176),会额外加一个"一键复制验证码"按钮。

值得一提的是,通知里的每个按钮都不是普通跳转,而是通过PendingIntent指向另一个BroadcastReceiver:点"回复"触发 ReplyReceiver,它取出用户输入的文本后,在 IO 协程中调用SmsUtil.sendSms()直接发出回复——整个过程不需要打开应用界面,这就是"通知栏回短信"的实现原理。

发短信:先入库再发送,用两个回执 Receiver 跟踪状态

发送逻辑的核心是 SmsUtil 这个工具对象,关键方法有:

  • sendSms()(第 46-74 行):发送前先检查信号(ConnectionHelper.hasSignalForSms()),然后把消息以SmsStatus.NONE状态持久化进短信库,拿到自增 ID 后再真正发送;
  • sendSmsInternal()(第 92-115 行):构造两个PendingIntent回执——"已发送"指向SmsSentReceiver,"已送达"指向SmsDeliveredReceiver,连同短信 ID 一起传给SmsManager.sendTextMessage()
  • 双卡支持getSmsManager()通过SmsManager.getSmsManagerForSubscriptionId()指定用哪张 SIM 卡发送。

两个回执接收器各司其职:

  • SmsSentReceiver:resultCode == RESULT_OK则把状态改为SENT,否则标记ERROR(界面上会显示重发按钮);
  • SmsDeliveredReceiver:收到对方网络的回执后把状态更新为DELIVERED,即消息气泡变成"双勾"。

此外,SmsUtil.kt#L117-L150 还实现了短信长度规则:纯 ASCII 每段 160 字符,含 Unicode(如中文表情)每段 70 字符,超长文本自动拆分成多条发送。

HeadlessSmsSendService:源码只有 7 行,为什么重要?

打开 HeadlessSmsSendService,你会发现它几乎是个空类——onBind直接返回 null。这正是 Google 官方推荐的"无头短信发送服务"写法:系统检测到应用声明了这个服务后,就把它认定为一个短信类应用,从而:

  1. 获得进入系统"短信应用选择器"的资格,可被设为主短信应用;
  2. 支持通话中的"快速回复"(Quick Reply)场景——系统通过RESPOND_VIA_MESSAGE动作唤起该服务代为发送短信。

它的注册在 AndroidManifest.xml#L282-L296:声明android.permission.SEND_RESPOND_VIA_MESSAGE权限保护,并监听smssmstomms等 scheme 的 intent-filter。真正"干活"的发送逻辑仍由SmsManager完成,服务本身只是一个身份声明

AndroidManifest 中的权限与组件注册清单

离线收发的能力,一半写在了 AndroidManifest.xml 里,主要有三处:

  • 三大短信权限(第 20-23 行):READ_SMS(读历史短信)、RECEIVE_SMS(接收短信广播)、SEND_SMS(发送短信);
  • 高优先级短信接收器(第 239-247 行):SmsReceiver使用android.permission.BROADCAST_SMS系统保护权限,且 intent-filter 设置priority="999",保证比系统短信应用更早收到广播;
  • 隐私关键一行(第 43-45 行):tools:node="remove"移除了依赖库引入的ACCESS_NETWORK_STATE网络权限——配合"移除网络权限"的思路,从底层证明该应用短信功能零联网。

本地存储还是系统短信库?一键切换

Connect You 的仓库层做了抽象:应用启动时,App.kt#L35-L41 的initSmsRepo()会根据"本地存储短信"设置,决定使用LocalSmsRepo(内置 Room 数据库,完全脱离系统短信库)或默认的 DeviceSmsRepo。

DeviceSmsRepo通过系统ContentProviderTelephony.Sms.CONTENT_URI)直接读写 Android 内置短信数据库,并用ContentObserver监听数据变化、以Flow推送给界面——所以在 Connect You 里发送的短信,系统短信应用同样能看到,真正做到"本地即系统"。

总结

Connect You 的短信模块是一套教科书级的"纯本地短信收发"实现:

  • 📥SmsReceiver以 999 优先级拦截SMS_DELIVER广播 → 系统短信库 → 可回复/删除/复制验证码的通知;
  • 📤SmsUtil先入库再交给SmsManager,两个回执 Receiver 跟踪"已发送 / 已送达"状态;
  • 🧩资格声明:7 行代码的HeadlessSmsSendService让应用获得系统短信应用身份与快速回复能力;
  • 🔒离线保障:移除网络权限、零服务器依赖,短信数据只存在你自己的设备里。

理解了"广播接收器负责进出、回执接收器负责状态、服务负责身份"这三个角色,你就能读懂绝大多数 Android 短信类应用的源码结构了。

【免费下载链接】ConnectYouPrivacy focused contacts and SMS messenger app built with MD3项目地址: https://gitcode.com/gh_mirrors/co/ConnectYou

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/23 12:21:29

概率模型:从核心概念到蒙特卡洛与贝叶斯实战应用

1. 从确定性到不确定性&#xff1a;为什么概率模型是建模的“另一只眼睛” 在数学建模的早期阶段&#xff0c;我们接触的大多是确定性模型。比如&#xff0c;用微分方程描述种群增长&#xff0c;用线性规划求解最优运输方案。这些模型有一个共同点&#xff1a;给定输入&#xf…

作者头像 李华
网站建设 2026/8/23 12:20:25

ProperTree:一款让 OpenCore 配置不再靠猜的 GUI plist 编辑器

ProperTree&#xff1a;一款让 OpenCore 配置不再靠猜的 GUI plist 编辑器 【免费下载链接】ProperTree Cross platform GUI plist editor written in python. 项目地址: https://gitcode.com/gh_mirrors/pr/ProperTree 第一次改 OpenCore 的 config.plist&#xff0c;我…

作者头像 李华
网站建设 2026/8/23 12:19:22

从数学建模到工程实践:高速列车操纵策略优化全解析

1. 项目概述&#xff1a;从一道赛题到工业级优化思维的实战 去年带队参加亚太赛&#xff0c;B题“高速列车的优化设计”一出来&#xff0c;我们团队就意识到&#xff0c;这绝不仅仅是一道数学建模题&#xff0c;而是一个高度凝练的、面向真实工程问题的优化沙盘。它把我们从课本…

作者头像 李华