您仍然可以在应用中提供声音和振动自定义,但需要采用不同的方法。简而言之,这个想法是在 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 需要前台通知。你有一些选择:
编辑:在 Android 8.1 中,使用 IMPORTANCE_NONE 创建禁用的频道似乎没有用,因为当您发送通知时该频道将自动启用。最好从一开始就使用 IMPORTANCE_LOW 创建它,并让用户根据需要更改重要性。