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

时间:2017-07-13 13:18:34

标签: android notifications

使用 Android O ,我们会获得" 通知渠道"。

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

用户需要转到" 通知渠道设置"并更改音调振动此处,因为 NotificationBuilder 中的所有方法 setSound 被忽略了。

所以有 NO 方式通过代码音调改为静音? 或者通过代码改变振动模式?

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

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

6 个答案:

答案 0 :(得分: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创建它,并让用户根据需要更改重要性。

答案 1 :(得分:5)

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

答案 2 :(得分:2)

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

  

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

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

您需要做什么delete the channel并创建一个ID不同的新

答案 3 :(得分:1)

对我而言,Android&gt; = 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);

答案 4 :(得分:0)

  

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

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

  

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

Use setVibrationPattern() on NotificationChannel

答案 5 :(得分: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());
}