使用Android O,我们可以获得“通知频道”。
据我了解,这意味着用户无法再在APP内设置通知音或其他相关的通知设置。
用户需要转到“通知通道设置”并更改音调或振动等,因为NotificationBuilder中的所有方法(如setSound)都会被忽略。
所以真的没有办法通过代码将音调改为静音吗? 或者通过代码改变振动模式?
例如,用户可以在我的应用程序中设置振动模式。 或者他可以从警报类型而不是通知类型中选择音调。
这一切都不可能了吗? 这是对的还是有办法做到这一点?
您仍然可以在应用中提供声音和振动自定义,但它需要不同的方法。简而言之,我们的想法是在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();
}
}
建议
setSound(null,null)
)和空振动(setVibrationPattern(null)
)创建通知通道,并在通道描述中解释这是推荐设置,以避免与应用程序冲突自己的定制。前景通知
启动Android O后,必须从后台启动的服务作为前台服务启动。这意味着SoundService需要前台通知。你有一些选择:
编辑:在Android 8.1中,使用IMPORTANCE_NONE创建禁用频道似乎没有用,因为在发送通知时将自动启用该频道。最好从一开始就使用IMPORTANCE_LOW创建它,并让用户根据需要更改重要性。
在你的情况下可能会有所帮助。如果您显示了一条通知,则可以通过设置.setOnlyAlertOnce(true)
来更新此通知时禁用声音。此解决方案仅在更新通知时有效。
这是正确的,一旦创建了一个频道,你就不能再对其进行更改了。
一旦创建通知通道并将其提交给通知管理器,您就无法以编程方式修改通知通道的行为
https://developer.android.com/preview/features/notification-channels.html
你需要做什么delete the channel并创建一个具有不同id的新的
对我来说,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);
手动播放声音不是一个好主意。最好的方法是拥有两个(或更多)通道 - 每个声道/振动一个你想要播放。
在代码中,您可以决定使用哪个频道,具体取决于您想要播放的声音。
这是我的代码,我根据客户端的设置播放默认通知声音或自定义声音。该代码还会在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());
}