整合移动通知

从 Android API 级别 26 开始, 前台服务。此要求旨在防止 可能会对系统资源提出过多需求的服务,包括 尤其是电池此要求可能会带来潜在问题:如果应用 没有仔细管理通知,因此 如果它在所有服务之间共享,则可以有多个永久性 不可关闭的通知,导致有效列表中的 通知。

当您使用 Navigation 等 SDK SDK,它们独立于应用本身运行前台服务, 单独的持续性通知,这使得它们难以整合。 为了解决这些问题,Navigation SDK v1.11 引入了一个简单的 API, 帮助管理整个应用中的永久通知,包括在 SDK 内显示的通知。

整合常驻通知

组件

前台服务管理器提供 Android 前台使用的封装容器 服务类和持久性通知类。这个封装容器的主要 功能是强制重复使用通知 ID, 使用该管理器在所有前台服务之间共享。


Navigation SDK 包含用于初始化和获取 ForegroundServiceManager 单例。此单例只能初始化 在 Navigation SDK 的生命周期内触发一次。因此,如果您使用 初始化调用(initForegroundServiceManagerMessageAndIntent()initForegroundServiceManagerProvider()),则应该将 请使用 try-catch 代码块,以防用户再次进入该路径。Navigation SDK 则会抛出运行时异常,除非您 首先清除对 ForegroundServiceManager 的所有引用,然后调用 clearForegroundServiceManager(),然后再进行后续调用。

initForegroundServiceManagerMessageAndIntent() 的四个参数为 applicationnotificationIddefaultMessageresumeIntent。如果 最后三个参数为 null,则通知是标准 Navigation SDK 通知。仍然可以隐藏其他前景 。notificationId 参数 指定应该用于通知的通知 ID。如果 null,则使用任意值。您可以明确将其设置为在 与其他 SDK 的通知(如来自其他 SDK 的通知)冲突。通过 defaultMessage 是一个字符串,系统会在 导航。resumeIntent 是在通知发出时触发的 intent 。如果 resumeIntent 为 null,则点击通知 将会被忽略。

initForegroundServiceManagerProvider() 的三个参数为 applicationnotificationIdnotificationProvider。如果最后一个 两个参数为 null,则通知是标准 Navigation SDK 通知。notificationId 参数用于指定 。如果该值为 null,则任意值 。您可以明确设置该属性以解决与其他 通知,例如来自其他 SDK 的通知。如果 notificationProvider 为 那么提供程序会始终负责 生成要呈现的通知。

Navigation SDK getForegroundServiceManager() 方法会返回 前台服务管理器单例。如果您尚未生成代码,则 相当于调用 initForegroundServiceManagerMessageAndIntent()notificationIddefaultMessageresumeIntent

ForegroundServiceManager 有三种简单的方法。前两项是针对 将服务移入和移出前台,通常由 创建 Deployment 清单使用这些方法可确保 与共享的常驻通知相关联。最后一个 方法 updateNotification(),用于标记通知具有的管理器 并且应重新呈现

如果您需要完全控制共享的常驻通知, 该 API 会提供 NotificationContentProvider 接口,用于定义 通知提供程序,其中包含用于接收通知的单一方法 与当前内容相关联。它还提供了一个基类,您可以 您可以视需要使用,以帮助定义提供程序。基类的一个主类 其目的在于,它提供了一种在不使用updateNotification() 需要访问ForegroundServiceManager。如果您使用 通知提供程序以接收新通知消息,您可以调用此 内部方法直接呈现消息在通知中。

使用场景

本部分详细介绍了使用共享永久性磁盘 通知。

隐藏其他应用前台服务的常驻通知
最简单的方案是保留当前行为,并且仅使用 用于呈现 Navigation SDK 信息的常驻通知。其他服务 可以使用前台服务管理器隐藏此通知 startForeground()stopForeground() 方法。
隐藏其他应用前台服务的常驻通知,但已设置 不浏览时显示的默认文字
第二种最简单的场景是保留当前行为,仅使用 用于呈现 Navigation SDK 信息的常驻通知,但以下情况除外: 。当系统未进行导航时, 提供给 initForegroundServiceManagerMessageAndIntent() 的字符串 而不是提及 “Google 地图”。您还可以使用此调用来设置 在用户点击通知时触发。
完全控制常驻通知的呈现
最后一种情况需要定义并创建通知提供程序 并使用以下代码将其传递给 ForegroundServiceManagerinitForegroundServiceManagerProvider()。通过这个选项 可以完全控制通知中呈现的内容, 会断开 Navigation SDK 通知信息与 从而删除了 通知。Google 没有提供一种简单的方法来检索此内容, 信息,并将其插入通知。

通知提供程序示例

以下代码示例演示了如何创建和返回通知 使用简单的通知内容提供程序。

public class NotificationContentProviderImpl
   extends NotificationContentProviderBase
   implements NotificationContentProvider {
 private String channelId;
 private Context context;
 private String message;

 /** Constructor */
 public NotificationContentProviderImpl(Application application) {
   super(application);
   message = "-- uninitialized --";
   channelId = null;
   this.context = application;
 }

 /**
  * Sets message to display in the notification. Calls updateNotification
  * to display the message immediately.
  *
  * @param msg The message to display in the notification.
  */
 public void setMessage(String msg) {
   message = msg;
   updateNotification();
 }

 /**
  * Returns the notification as it should be rendered.
  */
 @Override
 public Notification getNotification() {
   Notification notification;

   if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
     Spanned styledText = Html.fromHtml(message, FROM_HTML_MODE_LEGACY);
     String channelId = getChannelId(context);
     notification =
         new Notification.Builder(context, channelId)
             .setContentTitle("Notifications Demo")
             .setStyle(new Notification.BigTextStyle()
                 .bigText(styledText))
             .setSmallIcon(R.drawable.ic_navigation_white_24dp)
             .setTicker("ticker text")
             .build();
   } else {
     notification = new Notification.Builder(context)
         .setContentTitle("Notification Demo")
         .setContentText("testing non-O text")
         .build();
   }

   return notification;
 }

 // Helper to set up a channel ID.
 private String getChannelId(Context context) {
   if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
     if (channelId == null) {
       NotificationManager notificationManager =
           (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
       NotificationChannel channel = new NotificationChannel(
           "default", "navigation", NotificationManager.IMPORTANCE_DEFAULT);
       channel.setDescription("For navigation persistent notification.");
       notificationManager.createNotificationChannel(channel);
       channelId = channel.getId();
     }
     return channelId;
   } else {
     return "";
   }
 }
}

创建 NotificationContentProviderImpl 后,您需要将 Navigation SDK 使用以下代码:

ForegroundServiceManager f = NavigationApi.getForegroundServiceManager(getApplication());
mNotification = new NotificationContentProviderImpl(getApplication());
NavigationApi.clearForegroundServiceManager();
NavigationApi.initForegroundServiceManagerProvider(getApplication(), null, mNotification);

注意事项和未来的计划

  • 请务必提前调用 initForegroundServiceManagerMessageAndIntent()initForegroundServiceManagerProvider(), 明确了预期的使用场景您必须调用此方法 然后再创建新的导航器。
  • 请务必捕获对 initForegroundServiceManagerMessageAndIntent()initForegroundServiceManagerProvider()(如果代码路径是 多次输入。在 Navigation SDK v2.0 中,调用此方法 则会抛出已检查的异常,而不是运行时异常。
  • Google 可能仍需做一些工作,以确保在 与标题样式匹配的通知的生命周期。
  • 定义通知提供程序时,您可以控制浮动通知行为 相应的优先级
  • Google 没有提供一种简单的方法用于检索精细导航信息 通知提供程序可能在通知中插入的信息。