Android O - 通知频道 - 更改振动模式或声音类型

问题描述 投票:20回答:6

使用Android O,我们可以获得“通知频道”。

据我了解,这意味着用户无法再在APP内设置通知音或其他相关的通知设置。

用户需要转到“通知通道设置”并更改音调或振动等,因为NotificationBuilder中的所有方法(如setSound)都会被忽略。

所以真的没有办法通过代码将音调改为静音吗? 或者通过代码改变振动模式?

例如,用户可以在我的应用程序中设置振动模式。 或者他可以从警报类型而不是通知类型中选择音调。

这一切都不可能了吗? 这是对的还是有办法做到这一点?

android notifications
6个回答
17
投票

您仍然可以在应用中提供声音和振动自定义,但它需要不同的方法。简而言之,我们的想法是在Android O中手动播放声音和振动,而不是使用通知频道(它比看起来容易)。

这就是我做的方式:

NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId);

// builder.setSmallIcon(...)
// builder.setContentTitle(...)
// builder.setContentText(...)

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

    // play vibration
    vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
    vibrator.vibrate(VibrationEffect.createWaveform(vibrationPattern, -1));

    // play sound
    Intent serviceIntent = new Intent(context, SoundService.class);
    serviceIntent.setAction("ACTION_START_PLAYBACK");
    serviceIntent.putExtra("SOUND_URI", soundUri.toString());
    context.startForegroundService(serviceIntent);

    // the delete intent will stop the sound when the notification is cleared
    Intent deleteIntent = new Intent(context, SoundService.class);
    deleteIntent.setAction("ACTION_STOP_PLAYBACK");
    PendingIntent pendingDeleteIntent =
            PendingIntent.getService(context, 0, deleteIntent, 0);
    builder.setDeleteIntent(pendingDeleteIntent);

} else {

    builder.setVibrate(vibrationPattern);
    builder.setSound(soundUri);

}

notificationManager.notify(notificationId, builder.build());

SoundService.class是我用MediaPlayer播放声音的地方:

public class SoundService extends Service {

    MediaPlayer mMediaPlayer;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    public int onStartCommand(Intent intent, int flags, int startId) {

        // foreground notification
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationCompat.Builder builder =
                new NotificationCompat.Builder(this, otherChannelId);
            builder.setSmallIcon(...)
                    .setContentTitle(...)
                    .setContentText(...)
                    .setAutoCancel(true);
            startForeground(foregroundNotificationId, builder.build());
        }

        // check action
        String action = intent.getAction();
        switch (action) {
            case "ACTION_START_PLAYBACK":
                startSound(intent.getStringExtra("SOUND_URI"));
                break;
            case "ACTION_STOP_PLAYBACK":
                stopSound();
                break;
        }

        // service will not be recreated if abnormally terminated
        return START_NOT_STICKY;
    }

    private void startSound(String uriString) {

        // parse sound
        Uri soundUri;
        try {
            soundUri = Uri.parse(uriString);
        } catch (Exception e) {
            cleanup();
            return;
        }

        // play sound
        if (mMediaPlayer == null) {
            mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mp.start();
                }
            });
            mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mediaPlayer) {
                    cleanup();
                }
            });
        }
        try {
            mMediaPlayer.setDataSource(this, soundUri);
            mMediaPlayer.prepareAsync();
        } catch (Exception e) {
            cleanup();
        }

    }

    private void stopSound() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
        cleanup();
    }

    private void cleanup() {
        stopSelf();
    }

}

建议

  • 使用IMPORTANCE_DEFAULT(对于用户这是'高'),空声音(setSound(null,null))和空振动(setVibrationPattern(null))创建通知通道,并在通道描述中解释这是推荐设置,以避免与应用程序冲突自己的定制。
  • 将整个事情变成您的青睐:不是删除功能,而是为用户提供一个新功能。您可以让他们有机会使用您的自定义功能或通知渠道功能(例如,您可以检查当前渠道的重要性,并根据您可以使用的一个或另一个级别)。

前景通知

启动Android O后,必须从后台启动的服务作为前台服务启动。这意味着SoundService需要前台通知。你有一些选择:

  • 使用“停止播放”按钮创建一个漂亮的前景通知,以便用户可以在不删除启动声音的情况下停止声音。
  • 创建一个简单的通知并将其发送到禁用的通道(如果使用IMPORTANCE_NONE创建它们,则可以创建禁用的通道)。执行此操作时,将显示默认系统“应用程序在后台运行”通知而不是前台通知,但用户可以根据需要隐藏状态栏中的此通知。

编辑:在Android 8.1中,使用IMPORTANCE_NONE创建禁用频道似乎没有用,因为在发送通知时将自动启用该频道。最好从一开始就使用IMPORTANCE_LOW创建它,并让用户根据需要更改重要性。


5
投票

在你的情况下可能会有所帮助。如果您显示了一条通知,则可以通过设置.setOnlyAlertOnce(true)来更新此通知时禁用声音。此解决方案仅在更新通知时有效。


3
投票

这是正确的,一旦创建了一个频道,你就不能再对其进行更改了。

一旦创建通知通道并将其提交给通知管理器,您就无法以编程方式修改通知通道的行为

https://developer.android.com/preview/features/notification-channels.html

你需要做什么delete the channel并创建一个具有不同id的新的


1
投票

对我来说,Android> = 8.0的正确方法是隐藏您的声音/振动选项,并使用以下方法将用户重定向到您的应用通知设置:

  Intent intent = new Intent();
                intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
                intent.putExtra("android.provider.extra.APP_PACKAGE", context.getPackageName());
                context.startActivity(intent);

0
投票

所以真的没有办法通过代码将音调改为静音吗?

Use setSound() on NotificationChannel并指向一个包含一点点沉默的声音文件。

或者通过代码改变振动模式?

Use setVibrationPattern() on NotificationChannel


0
投票

手动播放声音不是一个好主意。最好的方法是拥有两个(或更多)通道 - 每个声道/振动一个你想要播放。

在代码中,您可以决定使用哪个频道,具体取决于您想要播放的声音。

这是我的代码,我根据客户端的设置播放默认通知声音或自定义声音。该代码还会在API 26之前处理运行Android的设备:

String sound = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("NotificationsSound", getString(R.string.settingsNotificationSiren));
Uri soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"+ getApplicationContext().getPackageName() + "/" + R.raw.siren);
NotificationManager mNotificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel mChannel;
String channel_id = Utils.CHANNEL_DEFAULT_ID;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    if (sound.toLowerCase().equals(getString(R.string.settingsNotificationSiren).toLowerCase())) {
        channel_id = Utils.CHANNEL_SIREN_ID;
        mChannel = new NotificationChannel(Utils.CHANNEL_SIREN_ID, Utils.CHANNEL_SIREN_NAME, NotificationManager.IMPORTANCE_HIGH);
        mChannel.setLightColor(Color.GRAY);
        mChannel.enableLights(true);
        mChannel.setDescription(Utils.CHANNEL_SIREN_DESCRIPTION);
        AudioAttributes audioAttributes = new AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                .build();
        mChannel.setSound(soundUri, audioAttributes);
    } else {
        mChannel = new NotificationChannel(Utils.CHANNEL_DEFAULT_ID, Utils.CHANNEL_DEFAULT_NAME, NotificationManager.IMPORTANCE_HIGH);
        mChannel.setLightColor(Color.GRAY);
        mChannel.enableLights(true);
        mChannel.setDescription(Utils.CHANNEL_DEFAULT_DESCRIPTION);
    }
    if (mNotificationManager != null) {
        mNotificationManager.createNotificationChannel( mChannel );
    }
}

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, channel_id)
        .setSmallIcon(R.drawable.ic_stat_maps_local_library)
        .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.mipmap.ic_launcher))
        .setTicker(title)
        .setContentTitle(contentTitle)
        .setContentText(contentText)
        .setAutoCancel(true)
        .setLights(0xff0000ff, 300, 1000) // blue color
        .setWhen(System.currentTimeMillis())
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
    if (sound.toLowerCase().equals(getString(R.string.settingsNotificationSiren).toLowerCase())) {
        mBuilder.setSound(soundUri);
    } else {
        mBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
    }
}

int NOTIFICATION_ID = 1; // Causes to update the same notification over and over again.
if (mNotificationManager != null) {
    mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
© www.soinside.com 2019 - 2024. All rights reserved.