Android Oreo及以上版本自定义通知音和振动失效问题排查
你的代码在Android Oreo及以上版本无法生效的核心问题是每次发送通知时重复创建NotificationChannel——Android系统规定,NotificationChannel一旦创建,后续调用createNotificationChannel()不会修改已有channel的配置(包括声音、振动等)。如果第一次调用sendNotif时isSoundEnabled或isVibrationEnabled为false,后续即使传入true,channel的配置也不会更新,导致通知始终无声音/振动。
除此之外还有几个细节问题需要修正:
具体问题点
NotificationChannel创建时机错误
你在每次发送通知时都创建channel,正确做法是在App初始化阶段(比如Application的onCreate()或主Activity的onCreate())只创建一次,后续发送通知直接复用已创建的channel。振动设置冗余
当isVibrationEnabled为false时,设置vibrationEmpty = {0}是多余的,直接调用channel.enableVibration(false)即可禁用振动。PendingIntent Flag适配问题
Android 12+(API 31)要求PendingIntent必须指定FLAG_IMMUTABLE或FLAG_MUTABLE,你当前使用的FLAG_CANCEL_CURRENT在高版本可能会抛出异常。
修复后的代码示例
第一步:在App初始化时创建NotificationChannel
将channel创建逻辑移到Application类或主Activity的onCreate中:
// 在Application的onCreate()中执行 private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { String channelName = "EEE"; String channelId = "CHANNEL_1"; NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH); channel.enableLights(true); // 初始化时设置默认的声音和振动配置 NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } }
第二步:修改sendNotif方法,移除重复创建channel的逻辑
private void sendNotif(String title, String text, boolean isSoundEnabled, boolean isVibrationEnabled) { NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); String channelId = "CHANNEL_1"; long[] vibrationPattern = new long[]{40, 75, 75, 75, 75, 75, 75, 750}; Uri soundUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + R.raw.notification); Intent intent = new Intent(context, ActivityOne.class); // 适配Android 12+的PendingIntent Flag int flag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_CANCEL_CURRENT; PendingIntent pIntent = PendingIntent.getActivity(context, 0, intent, flag); NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle(title) .setContentText(text) .setPriority(NotificationCompat.PRIORITY_MAX) .setAutoCancel(true) .setContentIntent(pIntent); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // 低版本直接设置声音和振动 if (isSoundEnabled) { builder.setSound(soundUri); } if (isVibrationEnabled) { builder.setVibrate(vibrationPattern); } else { builder.setVibrate(new long[]{0}); } } else { // Oreo+版本注意:代码无法动态修改已创建channel的声音/振动配置 // 若需根据参数动态切换,需提前创建多个不同配置的channel(例如CHANNEL_1_SOUND_ON、CHANNEL_1_SOUND_OFF) // 发送通知时根据isSoundEnabled和isVibrationEnabled选择对应channelId } notificationManager.notify(new Random().nextInt(10000), builder.build()); }
关键说明
Android Oreo+的NotificationChannel设计核心是让用户拥有更高控制权,一旦channel创建,开发者无法通过代码修改其声音、振动、重要性等核心配置,只能引导用户到系统设置页面修改。如果需要动态切换通知的声音和振动状态,正确做法是提前创建多个不同配置的NotificationChannel,发送通知时根据参数选择对应的channelId。
另外,可再次确认R.raw.notification文件是否存在且格式支持(推荐mp3或wav格式),低版本正常说明文件本身无问题,但路径需确保正确。
内容的提问来源于stack exchange,提问作者bruno13

