如何实现Android短信应用在关闭或销毁时接收短信?
解决Android短信应用关闭后无法接收短信的问题
看起来你遇到的是Android 8.0+系统对广播接收器的限制导致的问题——静态注册的广播接收器在应用处于停止状态(被关闭后)无法接收隐式广播,这是系统为了优化电池和性能引入的规则。你的SmsBroadcastReceiver是静态注册在Manifest里的,所以一旦应用被关闭,系统就不会再把短信/彩信广播分发给它了。
下面是具体的解决方案,一步步来:
核心思路:用前台服务+动态注册广播接收器
前台服务的优先级远高于普通后台服务,只要前台服务在运行,应用就不会被系统标记为"停止状态"。我们可以在前台服务里动态注册广播接收器,这样即使应用界面被关闭,服务仍然会持续监听短信广播。
1. 补充Manifest权限与服务注册
首先更新你的Manifest,添加必要的权限和前台服务的注册:
<!-- 前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- 接收WAP Push(彩信)的权限 --> <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" /> <!-- 如果需要接收普通短信,加上这个 --> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <!-- Android 13+ 需要通知权限才能显示前台服务通知 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- 注册前台服务 --> <service android:name=".SmsForegroundService" android:foregroundServiceType="dataSync" /> <!-- dataSync适合数据同步/监听场景 --> <!-- 可以保留原来的静态接收器,但它只在应用运行时生效,主要依赖动态注册 --> <receiver android:name=".SmsBroadcastReceiver" android:enabled="true" android:exported="true" android:permission="android.permission.BROADCAST_WAP_PUSH"> <intent-filter android:priority="999" > <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" /> <!-- 普通短信的话加上这个 --> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>
2. 创建前台服务类
新建一个SmsForegroundService类,在里面动态注册广播接收器,并启动前台服务:
class SmsForegroundService : Service() { private lateinit var smsReceiver: SmsBroadcastReceiver override fun onCreate() { super.onCreate() // 初始化并注册广播接收器 smsReceiver = SmsBroadcastReceiver() val intentFilter = IntentFilter().apply { addAction("android.provider.Telephony.WAP_PUSH_DELIVER") addAction("android.provider.Telephony.SMS_RECEIVED") // 可选,普通短信监听 priority = 999 } registerReceiver(smsReceiver, intentFilter) // 创建前台服务通知(必须,否则系统会杀服务) val notificationChannelId = "SMS_LISTENER_CHANNEL" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( notificationChannelId, "短信监听通道", NotificationManager.IMPORTANCE_LOW // 低优先级,避免打扰用户 ) getSystemService(NotificationManager::class.java).createNotificationChannel(channel) } val notification = NotificationCompat.Builder(this, notificationChannelId) .setContentTitle("短信服务运行中") .setContentText("应用正在后台接收短信/彩信") .setSmallIcon(R.drawable.ic_notification) // 替换成你的通知图标 .setPriority(NotificationCompat.PRIORITY_LOW) .build() // 启动前台服务 startForeground(1001, notification) } override fun onDestroy() { super.onDestroy() // 注销接收器,避免内存泄漏 unregisterReceiver(smsReceiver) } override fun onBind(intent: Intent): IBinder? { return null // 不需要绑定服务,返回null即可 } }
3. 启动前台服务
在应用启动时(比如MainActivity的onCreate方法)启动这个前台服务,确保服务随应用启动而运行:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 检查权限并启动前台服务 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val permissions = arrayOf( Manifest.permission.RECEIVE_WAP_PUSH, Manifest.permission.RECEIVE_SMS, Manifest.permission.POST_NOTIFICATIONS ) if (checkSelfPermission(permissions[0]) != PackageManager.PERMISSION_GRANTED || checkSelfPermission(permissions[1]) != PackageManager.PERMISSION_GRANTED || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && checkSelfPermission(permissions[2]) != PackageManager.PERMISSION_GRANTED) ) { requestPermissions(permissions, 100) } else { startForegroundService() } } else { startForegroundService() } } private fun startForegroundService() { val intent = Intent(this, SmsForegroundService::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(intent) } else { startService(intent) } } // 处理权限申请结果 override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 100 && grantResults.all { it == PackageManager.PERMISSION_GRANTED }) { startForegroundService() } }
关键注意点
- 前台服务必须显示通知:从Android 8.0开始,前台服务必须绑定一个可见的通知,你可以把通知设置为低优先级,减少对用户的打扰。
- 动态权限申请:
RECEIVE_WAP_PUSH、RECEIVE_SMS和POST_NOTIFICATIONS都是危险权限,必须在运行时向用户申请,不能只依赖Manifest声明。 - 避免内存泄漏:在服务销毁时一定要注销广播接收器,否则会导致内存泄漏。
这样改造后,即使用户关闭了应用的界面,前台服务仍然会在后台运行,广播接收器也能持续接收到短信/彩信广播了。
内容的提问来源于stack exchange,提问作者user8515823
相关产品推荐
相关产品推荐

