API 26 上的通知声音

34

我有一个自定义的mp3声音,我用它来通知。在API 26以下的所有设备上都可以正常工作。我尝试在通知渠道上设置声音,但仍然无法工作。它播放默认的声音。

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
            .setAutoCancel(true)
            .setSmallIcon(R.drawable.icon_push)
            .setColor(ContextCompat.getColor(this, R.color.green))
            .setContentTitle(title)
            .setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.notification))
            .setDefaults(Notification.DEFAULT_VIBRATE)
            .setStyle(new NotificationCompat.BigTextStyle().bigText(message))
            .setContentText(message);
        Notification notification = builder.build();
        NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
            AudioAttributes audioAttributes = new AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
                    .build();
            channel.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.notification), audioAttributes);
            notificationManager.createNotificationChannel(channel);
        }
        notificationManager.notify(1, notification);

你把默认通知声音调成静音了吗?我也遇到了同样的问题。我不想在 NotificationManager.IMPORTANCE_MAX 的情况下播放任何提示音。你能帮我解决一下吗? - BHARAT GUPTA
我唯一让它工作的方式是使用RingtoneManager,但我已从代码中删除了它。使用RingtoneManager,用户无法静音通知。我的应用程序正在使用Android 8上的默认声音。我仍然不知道如何让自定义声音与通道一起工作。 - Rodrigo Manguinho
6个回答

52

你可能最初使用默认音频创建了该通道。一旦通道被创建,就无法更改。您需要重新安装应用程序或使用新的通道ID创建通道。


2
要更改重要性、声音、灯光、震动、锁屏或DND设置,请卸载该应用并重新安装以清除通道。请参见https://developer.android.com/guide/topics/ui/notifiers/notifications.html#ManageChannels,特别是标题为“删除通知渠道”的部分。 - BitByteDog
这让我领悟到放弃所有现有频道并创建一个“ChannelManager”来管理频道并在应用初始化期间进行设置。 - Vishnu Haridas
这很奇怪。用户不是可以在设置中更改频道通知声音吗? - neobie
@neobie 如果您使用默认铃声,例如 RingtoneManager.TYPE_ALARM,那么是的,用户可以在设置中更改它。但是,OP使用了自定义音频。 - Vadim Kotov

16

我使用了RingtoneManager,它对我很有效。尝试一下这段代码:

 NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this);
    builder.setSmallIcon(android.R.drawable.ic_dialog_alert);
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com/"));
    PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, 0);
    builder.setContentIntent(pendingIntent);
    builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
    builder.setContentTitle("Notification title");
    builder.setContentText("Notification message.");
    builder.setSubText("Url link.");

    try {
        Uri notification = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.custom_ringtone);
        Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
        r.play();
    } catch (Exception e) {
        e.printStackTrace();
    }

    NotificationManager notificationManager = (NotificationManager) this.getSystemService(NOTIFICATION_SERVICE);
    notificationManager.notify(1, builder.build());

7
该解决方案存在的问题在于用户无法将通知声音静音,它总是会播放声音。 - Rodrigo Manguinho
4
NotificationCompat.Builder(Context)已被弃用,现在必须使用NotificationCompat.Builder(context, String)指定通知的NotificationChannel Id。因此,这对于Oreo / API 26来说不是最佳解决方案。 - Mudar
3
我想知道为什么setSound函数不起作用?根据文档,通知渠道的重要性必须至少为“IMPORTANCE_HIGH”才能播放声音。但它仍然无法工作。 - Nolesh
1
@FaxriddinAbdullayev,它不起作用。此外,“setDefaults”在“Oreo”中已被弃用。 - Nolesh
4
这个问题针对API 26,但是这个答案甚至没有提到NotificationChannel。在Android 8.0+设备上你将完全收不到通知,更别提改变通知的声音了。 - Chandler
显示剩余4条评论

2

1
默认声音会覆盖任何声音。
你需要将这段代码放入你的代码中:
notification.defaults = Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE;

参考:

Android通知


6
在添加那段代码之前,你必须清除测试通道,可以通过重新安装应用程序或清除与应用程序相关联的数据来实现。请注意不要改变原始意思,简化语言并使其易于理解。 - Towfik Alrazihi
好的,我今晚再试一次。谢谢。 - Rodrigo Manguinho

0
除了Faxriddin的回答之外,您还可以通过检查通知渠道的重要性和启用通知参数来确定何时应该关闭通知声音。
NotificationChannel channel = notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID);
if(notificationManager.areNotificationsEnabled() && channel.getImportance() != NotificationManager.IMPORTANCE_NONE) {
  try {
     Ringtone r = RingtoneManager.getRingtone(ctx, soundUri);
     r.play();
  } catch (Exception e) { }
}

1
更好的测试方式:使用 channel.getSound() == null 而不是 importance。 - grebulon

0

我一直在开发具有类似功能的应用程序。正如Paweł Nadolski所提到的,我们每次更改铃声都需要重新创建通道。为此,我编写了一个帮助程序。希望能对某人有所帮助。

@RequiresApi(Build.VERSION_CODES.O)
object ChannelHelper {
    // channel id for 8.0 OS version and higher
    private const val OREO_CHANNEL_ID = "com.ar.app.notifications"
    private const val CHANNEL_ID_PREF = "com.ar.app.notifications_prefs"

    @JvmStatic
    fun createChannel(context: Context, playSound: Boolean, isVibrated: Boolean, uri: Uri) {
        // establish name and importance of channel
        val name = context.getString(R.string.main_channel_name)
        val importance = if (playSound) {
            NotificationManager.IMPORTANCE_DEFAULT
        } else {
            NotificationManager.IMPORTANCE_LOW
        }

        // create channel
        val channelId = OREO_CHANNEL_ID + UUID.randomUUID().toString()
        saveChannelId(context, channelId)

        val channel = NotificationChannel(channelId, name, importance).apply {
            enableLights(true)
            lightColor = Color.GREEN

            lockscreenVisibility = Notification.VISIBILITY_PUBLIC

            // add vibration
            enableVibration(isVibrated)
            vibrationPattern = longArrayOf(0L, 300L, 300L, 300L)

            // add sound
            val attr = AudioAttributes.Builder()
                    .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
                    .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                    .build()

            setSound(uri, attr)
        }

        // register the channel in the system
        val notificationManager = context.getSystemService(NotificationManager::class.java)
        notificationManager.createNotificationChannel(channel)
    }

    @JvmStatic
    fun rebuildChannel(context: Context, playSound: Boolean, isVibrated: Boolean, uri: Uri) {
        val notificationManager = context.getSystemService(NOTIFICATION_SERVICE)
                as NotificationManager
        notificationManager.deleteNotificationChannel(
            getChannelId(context) ?: OREO_CHANNEL_ID
        )

        createChannel(context, playSound, isVibrated, uri)
    }

    @JvmStatic
    fun getChannel(context: Context): NotificationChannel? {
        val notificationManager = context.getSystemService(NOTIFICATION_SERVICE)
                as NotificationManager

        return notificationManager.getNotificationChannel(
                getChannelId(context) ?: OREO_CHANNEL_ID
        )
    }

    @JvmStatic
    fun isChannelAlreadyExist(context: Context) = getChannel(context) != null

    @JvmStatic
    fun getChannelId(context: Context) =
            PreferenceManager.getDefaultSharedPreferences(context)
                    .getString(CHANNEL_ID_PREF, OREO_CHANNEL_ID)

    private fun saveChannelId(context: Context, channelId: String) =
            PreferenceManager.getDefaultSharedPreferences(context)
                    .edit()
                    .putString(CHANNEL_ID_PREF, channelId)
                    .apply()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接