Android Kotlin监听设备新短信事件功能失效问题排查及修复咨询
我帮你排查了代码里的几个关键问题,这些都是导致短信通知不工作的核心原因,咱们一步步来修复:
一、广播注册的致命错误
1. 静态注册的系统限制
Android 8.0(API 26)之后,系统严格限制了隐式广播的静态注册,android.provider.Telephony.SMS_RECEIVED就属于这类广播。你在AndroidManifest.xml里的静态注册,在高版本系统上根本不会被触发。
2. 动态注册的Action错误
你在MainActivity里注册广播时,监听的是自定义的com.forkthecoup.com22222.SmsListener Action,而不是短信系统广播的android.provider.Telephony.SMS_RECEIVED,这直接导致接收器收不到短信触发的广播信号。
修复方案:
移除Manifest里的静态广播注册(保留也不会生效,建议直接删除),在MainActivity里正确注册短信广播,并且记得在Activity销毁时注销接收器避免内存泄漏。
二、权限问题(容易遗漏的动态申请)
虽然你说已经授予权限,但Android 6.0(API 23)+ 需要动态申请危险权限:
RECEIVE_SMS:必须动态申请才能接收短信- Android 13(API 33)+ 还需要
POST_NOTIFICATIONS权限才能显示通知
如果没有动态申请,即使Manifest里声明了权限,系统也会直接拒绝应用的相关请求。
三、NotificationBuilder的兼容性漏洞
你的showNotification方法只处理了Android O及以上的情况,低于O的版本完全没有初始化builder,会直接抛出空指针异常,导致通知无法显示。应该用NotificationCompat.Builder来兼容所有系统版本。
四、PendingIntent的高版本适配
Android 12(API 31)+ 要求PendingIntent必须指定FLAG_IMMUTABLE或FLAG_MUTABLE,原来的FLAG_UPDATE_CURRENT需要和这两个flag结合使用,否则会抛出运行时异常。
五、异常捕获太宽泛,丢失调试信息
你在处理短信的try-catch里直接吞掉了所有异常,没有任何日志输出,出问题时根本无法定位错误原因。必须添加日志打印来记录异常细节。
修复后的完整代码
1. MainActivity(权限申请+动态广播注册)
class MainActivity : AppCompatActivity() { private lateinit var smsReceiver: SmsListener override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 先申请必要权限 requestRequiredPermissions() // 初始化并注册短信广播接收器 smsReceiver = SmsListener() val smsFilter = IntentFilter("android.provider.Telephony.SMS_RECEIVED") smsFilter.priority = 999 // 设置优先级,确保能优先收到广播(可选但实用) registerReceiver(smsReceiver, smsFilter) } private fun requestRequiredPermissions() { val permissionsToRequest = mutableListOf<String>() // 申请接收短信权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECEIVE_SMS) != PackageManager.PERMISSION_GRANTED) { permissionsToRequest.add(Manifest.permission.RECEIVE_SMS) } // Android 13+ 申请通知权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { permissionsToRequest.add(Manifest.permission.POST_NOTIFICATIONS) } } // 发起权限申请 if (permissionsToRequest.isNotEmpty()) { ActivityCompat.requestPermissions(this, permissionsToRequest.toTypedArray(), 1001) } } override fun onDestroy() { super.onDestroy() // 注销接收器,避免内存泄漏 unregisterReceiver(smsReceiver) } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 1001) { // 可以在这里处理权限被拒绝的情况,比如弹窗提示用户开启权限 } } }
2. SmsListener广播接收器
import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import android.content.Intent import android.graphics.BitmapFactory import android.graphics.Color import android.os.Build import android.provider.Telephony import android.util.Log import androidx.core.app.NotificationCompat class SmsListener : BroadcastReceiver() { private val channelId = "i.apps.notifications" private val channelName = "New SMS Notifications" override fun onReceive(context: Context?, intent: Intent?) { context ?: return intent ?: return if (intent.action == Telephony.Sms.Intents.SMS_RECEIVED_ACTION) { val bundle = intent.extras ?: return try { val pdus = bundle["pdus"] as? Array<Any> ?: return val smsMessages = arrayOfNulls<Telephony.SmsMessage>(pdus.size) for (i in smsMessages.indices) { smsMessages[i] = Telephony.SmsMessage.createFromPdu(pdus[i] as ByteArray) val sender = smsMessages[i]?.originatingAddress ?: "Unknown Sender" val messageBody = smsMessages[i]?.messageBody ?: "" Log.d("SmsListener", "Received SMS from $sender: $messageBody") if (messageBody.isNotEmpty()) { showNotification(context, messageBody, sender) } } } catch (e: Exception) { // 打印异常日志,方便调试 Log.e("SmsListener", "Failed to process SMS", e) } } } private fun showNotification(context: Context, message: String, sender: String) { val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // 创建通知渠道(仅Android O及以上需要) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val notificationChannel = NotificationChannel( channelId, channelName, NotificationManager.IMPORTANCE_HIGH ).apply { lightColor = Color.BLUE enableVibration(true) description = "Notification for incoming SMS messages" } notificationManager.createNotificationChannel(notificationChannel) } // 跳转至消息详情页的Intent val detailIntent = Intent(context, MessageDetailsActivity::class.java).apply { putExtra(MessageDetailsActivity.KEY_MESSAGE, message) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } // 适配Android 12+的PendingIntent Flag val pendingIntentFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE } else { PendingIntent.FLAG_UPDATE_CURRENT } val pendingIntent = PendingIntent.getActivity(context, 0, detailIntent, pendingIntentFlags) // 使用NotificationCompat.Builder兼容所有版本 val notificationBuilder = NotificationCompat.Builder(context, channelId) .setContentTitle("$sender: New message received") .setContentText(message.take(50)) .setSmallIcon(R.drawable.common_google_signin_btn_icon_dark) .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.ic_launcher_background)) .setContentIntent(pendingIntent) .setPriority(NotificationCompat.PRIORITY_HIGH) // 高优先级确保通知弹出 .setAutoCancel(true) // 点击通知后自动消失 .setDefaults(Notification.DEFAULT_VIBRATE) // 开启默认震动 // 发送通知 notificationManager.notify(12345, notificationBuilder.build()) } }
3. AndroidManifest.xml(权限声明)
<uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.READ_SMS" /> <!-- 可选,如需读取更多短信信息 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" android:minSdkVersion="33" /> <!-- 移除原来的静态receiver注册 -->
额外注意事项
- 如果应用被系统杀死,动态注册的广播接收器会失效。如果需要在应用完全关闭时也能接收短信,你需要改用前台服务结合动态广播,或者使用Google的
SMS Retriever API(但需要短信包含特定格式的哈希值)。 - 测试时请使用真实设备,模拟器的短信功能偶尔会有兼容性问题。
- 确保你的应用没有被系统电池优化限制,可以在系统设置里关闭对应应用的电池优化。
内容的提问来源于stack exchange,提问作者Wai Yan Hein




