【问题标题】:Notifications fail to display in Android Oreo (API 26)通知无法在 Android Oreo (API 26) 中显示
【发布时间】:2018-01-05 19:58:40
【问题描述】:

我在尝试在 Android O 上显示通知时收到此消息。

不推荐将流类型用于除卷以外的操作 控制

通知直接来自示例文档,在 Android 25 上显示良好。

【问题讨论】:

  • 该错误与您的通知未显示的原因无关。请附上您正在使用的完整 NotificationCompat 代码和您的 targetSdkVersion
  • 我最初计划回答我自己的问题,引用的错误是其他人会搜索的内容。现在我意识到这个错误与它没有显示的事实无关。这是因为我没有 NotificationChannel。 Android 应该在无法显示通知或抛出异常或其他情况时进行日志记录。

标签: android push-notification android-8.0-oreo android-8.1-oreo


【解决方案1】:

根据this Google+ post上的cmets:

目前在 Android O 设备上使用NotificationCompat 时会出现这些[警告](NotificationCompat 始终调用setSound(),即使您从未传入自定义声音)。

在支持库更改其代码以使用 setSoundAudioAttributes 版本之前,您将始终收到该警告。

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

【讨论】:

  • 谢谢@ianhanniballake。我很好奇为什么 NotificationChannels 在创建后不能被修改。我知道用户可以覆盖配置,例如降低频道的重要性,但如果他们没有这样做,为什么要阻止应用修改频道?
  • 如果用户进入设置,确认它们是合适的,然后你又更改了它们怎么办?让用户期望除非他们自己改变,否则他们永远不会改变,这是一个有用的保证。
  • 为什么不保留配置设置的副本,以及用户指定的设置(如果他们已更改)。对于每个更改的设置,将其应用到 NotificationChannel 配置之上。否则让他们改变。当前的行为使测试变得困难,并且认为在您注册频道的那一刻,它就为应用程序的生命奠定了基础,这很疯狂。就像您永远无法更改该频道一样。你只需要继续前进并创建一个新的——这正是应用程序开发人员要做的,然后你基本上回到了没有控制权的用户。
  • 您会看到用户对他们过去隐藏的通知又回来了感到沮丧。试图做正确事情的开发者将对此无能为力,但用户会指责 Android 存在缺陷。
  • Android O 已完成。请随时添加feature request 以获取未来版本的 Android。
【解决方案2】:

从 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 将使其复活,并且与首次创建时一样不可变。它将继续使用旧设置,直到应用程序被卸载。因此,您最好确定您的频道设置,如果您正在使用这些设置,请重新安装应用程序以使其生效。

【讨论】:

  • “您应该移动将更改到通知中的设置,或者...” - 这有效吗?或者 NotificationChannel 是否具有(覆盖)振动模式等的默认设置,即使您没有设置它们?
  • 我认为至少对于一些可选的设置,在频道配置中不设置它们可以让通知的设置优先。
  • 嗯,这个假设没有成功。未设置频道参数会影响选择默认通知声音、公共锁屏可见性、振动关闭或通知灯关闭。一旦应用创建了频道,用户甚至可以在应用创建任何通知之前查看和更改其设置。
【解决方案3】:

@sky-kelsey 所描述的一切都很好,只是少量补充

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

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)
            ...

另一个典型问题 - 频道默认声音 - 在这里描述:https://stackoverflow.com/a/45920861/2133585

【讨论】:

    【解决方案4】:

    在 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());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多