Android最高优先级本地通知开发问题:需支持免打扰及锁屏显示
问题解决方案
一、修复通知锁屏显示、声音及震动问题
你的代码存在几个关键问题导致通知无锁屏显示、无声音震动:
通知渠道优先级不足
Android 8.0+ 中,通知的优先级由NotificationChannel的importance决定,而非NotificationCompat.Builder的priority。你当前设置的IMPORTANCE_DEFAULT优先级不够,无法触发锁屏显示、声音和震动。需要将其改为IMPORTANCE_HIGH或IMPORTANCE_MAX(后者为紧急通知,会弹出全屏提示)。未配置震动属性
当前代码仅设置了声音,未开启震动功能,需要为渠道添加震动配置。渠道创建后无法修改优先级
注意:通知渠道一旦创建,importance等核心属性无法通过代码修改,若之前已安装过应用,需卸载重装或清除应用数据才能生效。
修改后的createNotificationChannelWithSound方法:
@RequiresApi(api = Build.VERSION_CODES.O) public static String createNotificationChannelWithSound(Context context, String channelId, String channelName, Uri rawPathUri) { // 使用IMPORTANCE_HIGH确保高优先级 NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH); channel.setLightColor(Color.BLUE); // 设置锁屏可见性,PRIVATE表示隐藏敏感内容,PUBLIC显示全部内容 channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); // 配置声音属性 AudioAttributes att = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_NOTIFICATION) .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) .build(); channel.setSound(rawPathUri, att); // 添加震动配置 channel.enableVibration(true); channel.setVibrationPattern(new long[]{0, 1000, 500, 1000}); // 震动节奏:立即震动1秒,停0.5秒,再震动1秒 channel.setShowBadge(false); NotificationManager service = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); service.createNotificationChannel(channel); return channelId; }
同时,在sendNotification方法中,补充设置通知可见性(与渠道配置对应):
with(builder) { // ... 原有代码 priority = NotificationCompat.PRIORITY_MAX // 兼容8.0以下版本 setVisibility(NotificationCompat.VISIBILITY_PRIVATE) // 对应渠道的锁屏可见性 setContentIntent(intent) }
二、实现静音/免打扰模式下接收通知
要让通知在静音、免打扰模式下正常接收,需完成两步:
- 申请绕过免打扰权限
在AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
- 检查并请求权限
在发送通知前,检查是否已获得权限,若未获得,跳转至系统设置页面让用户开启:
private fun canBypassDnd(): Boolean { val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { notificationManager.isNotificationPolicyAccessGranted } else { true // 6.0以下无需权限 } } private fun requestBypassDndPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val intent = Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS) startActivity(intent) } }
发送通知前调用:
if (!canBypassDnd()) { requestBypassDndPermission() return } // 继续发送通知逻辑
三、实现每日至多显示1次通知
使用SharedPreferences记录上次发送通知的日期,每次发送前判断是否当天已发送:
private fun shouldSendToday(): Boolean { val sp = getSharedPreferences("NotificationPrefs", Context.MODE_PRIVATE) val lastSendDate = sp.getLong("LastSendDate", 0) val today = Calendar.getInstance().apply { set(Calendar.HOUR_OF_DAY, 0) set(Calendar.MINUTE, 0) set(Calendar.SECOND, 0) set(Calendar.MILLISECOND, 0) }.timeInMillis return lastSendDate < today } private fun markNotificationSentToday() { val sp = getSharedPreferences("NotificationPrefs", Context.MODE_PRIVATE) val today = Calendar.getInstance().apply { set(Calendar.HOUR_OF_DAY, 0) set(Calendar.MINUTE, 0) set(Calendar.SECOND, 0) set(Calendar.MILLISECOND, 0) }.timeInMillis sp.edit().putLong("LastSendDate", today).apply() }
在sendNotification方法开头添加判断:
private fun sendNotification( notificationId: Int, title: String, message: String, intent: PendingIntent? = null ) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return // 检查是否今日已发送 if (!shouldSendToday()) { Timber.d("今日已发送过通知,跳过") return } // 检查免打扰权限 if (!canBypassDnd()) { requestBypassDndPermission() return } Timber.d("sendNotification") // ... 原有创建通知逻辑 // 发送后标记今日已发送 markNotificationSentToday() notificationManager.notify(notificationId, builder.build()) }
内容的提问来源于stack exchange,提问作者Sunbey13
相关产品推荐
相关产品推荐

