通知无法在 Android Oreo 中显示 (API 26)

Notifications fail to display in Android Oreo (API 26)

我在 Android O.

上尝试显示通知时收到此消息

Use of stream types is deprecated for operations other than volume control

通知直接来自示例文档,并在 Android 25 上正常显示。

从 Android O 开始,您需要配置一个 NotificationChannel,并在您尝试显示通知时引用该频道。

private static final int NOTIFICATION_ID = 1;
private static final String NOTIFICATION_CHANNEL_ID = "my_notification_channel";

...

NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_DEFAULT);

  // Configure the notification channel.
  notificationChannel.setDescription("Channel description");
  notificationChannel.enableLights(true);
  notificationChannel.setLightColor(Color.RED);
  notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
  notificationChannel.enableVibration(true);
  notificationManager.createNotificationChannel(notificationChannel);
}

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
  .setVibrate(new long[]{0, 100, 100, 100, 100, 100})
  .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
  .setSmallIcon(R.mipmap.ic_launcher)
  .setContentTitle("Content Title")
  .setContentText("Content Text");

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

一些重要说明:

  1. NotificationChannel 中指定的振动模式等设置会覆盖实际 Notification 中指定的设置。我知道,这是违反直觉的。您应该移动将更改为通知的设置,或者为每个配置使用不同的 NotificationChannel。
  2. 大多数 NotificationChannel 设置传递给 createNotificationChannel() 后,您将无法修改。您甚至不能调用 deleteNotificationChannel() 然后尝试重新添加它。使用已删除的 NotificationChannel 的 ID 会将其复活,并且它将与首次创建时一样不可变。它将继续使用旧设置,直到应用程序被卸载。所以你最好确定你的频道设置,如果你正在玩这些设置,请重新安装应用程序以使它们生效。

根据 this Google+ post 上的评论:

those [warnings] are currently expected when using NotificationCompat on Android O devices (NotificationCompat always calls setSound() even if you never pass in custom sound).

until the Support Library changes their code to use the AudioAttributes version of setSound, you'll always get that warning.

因此,对于此警告,您无能为力。根据 notification channels guide,Android O 完全不赞成在单个通知上设置声音,而是让您在特定类型的所有通知使用的通知通道上设置声音。

@sky-kelsey 描述的都很好,只是少量添加:

你不应该每次都注册同一个频道,如果它已经注册了,所以我有 Utils class 方法 为我创建一个频道:

public static final String NOTIFICATION_CHANNEL_ID_LOCATION = "notification_channel_location";

public static void registerLocationNotifChnnl(Context context) {
    if (Build.VERSION.SDK_INT >= 26) {
        NotificationManager mngr = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
        if (mngr.getNotificationChannel(NOTIFICATION_CHANNEL_ID_LOCATION) != null) {
            return;
        }
        //
        NotificationChannel channel = new NotificationChannel(
                NOTIFICATION_CHANNEL_ID_LOCATION,
                context.getString(R.string.notification_chnnl_location),
                NotificationManager.IMPORTANCE_LOW);
        // Configure the notification channel.
        channel.setDescription(context.getString(R.string.notification_chnnl_location_descr));
        channel.enableLights(false);
        channel.enableVibration(false);
        mngr.createNotificationChannel(channel);
    }
}

strings.xml:

<string name="notification_chnnl_location">Location polling</string>
<string name="notification_chnnl_location_descr">You will see notifications on this channel ONLY during location polling</string>

我每次在显示类型通知之前都会调用该方法:

    ...
    NotificationUtil.registerLocationNotifChnnl(this);
    return new NotificationCompat.Builder(this, NotificationUtil.NOTIFICATION_CHANNEL_ID_LOCATION)
            .addAction(R.mipmap.ic_launcher, getString(R.string.open_app),
                    activityPendingIntent)
            .addAction(android.R.drawable.ic_menu_close_clear_cancel, getString(R.string.remove_location_updates),
                    servicePendingIntent)
            .setContentText(text)
            ...

另一个典型问题 - 声道默认声音 - 描述如下:

在 Android O 中必须使用 NotificationChannel 并且 NotificationCompat.Builder 已弃用 (reference)。

下面是示例代码:

NotificationCompat.Builder mBuilder =
        new NotificationCompat.Builder(mContext.getApplicationContext(), "notify_001");
Intent ii = new Intent(mContext.getApplicationContext(), RootActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, ii, 0);

NotificationCompat.BigTextStyle bigText = new NotificationCompat.BigTextStyle();
bigText.bigText(verseurl);
bigText.setBigContentTitle("Today's Bible Verse");
bigText.setSummaryText("Text in detail");

mBuilder.setContentIntent(pendingIntent);
mBuilder.setSmallIcon(R.mipmap.ic_launcher_round);
mBuilder.setContentTitle("Your Title");
mBuilder.setContentText("Your text");
mBuilder.setPriority(Notification.PRIORITY_MAX);
mBuilder.setStyle(bigText);

NotificationManager mNotificationManager =
        (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    NotificationChannel channel = new NotificationChannel("notify_001",
            "Channel human readable title",
            NotificationManager.IMPORTANCE_DEFAULT);
    mNotificationManager.createNotificationChannel(channel);
}

mNotificationManager.notify(0, mBuilder.build());