整合行動裝置通知

從 Android API 級別 26 開始,前景服務必須使用持續通知。這項規定旨在避免您隱藏可能對系統資源 (特別是電池) 造成過度需求的服務。這項規定會造成潛在問題:如果應用程式有多個前景服務,但未仔細管理通知,以便在所有服務間共用,則可能會有多個無法關閉的持續性通知,導致通知的有效清單中出現不必要的雜亂。

使用 Navigation 等 SDK 時,這個問題會更加棘手 SDK,這類 SDK 是用於執行前景服務,不受 因此會造成獨立永久通知,導致系統難以整合。 為解決這些問題,Navigation SDK 1.11 版推出了簡單的 API,可協助管理應用程式 (包括 SDK 內) 中的持續性通知。

整合持續通知

元件

前景服務管理員會在 Android 前景服務類別和持續通知類別周圍提供包裝函式。這個包裝函式的主功能是強制重複使用 Notification ID,以便透過管理員在所有前景服務中共用通知。


Navigation SDK 包含用於初始化及取得 ForegroundServiceManager 單例模式。這個單例模式只能初始化 只需在 Navigation SDK 生命週期內執行一次因此,如果您使用了 初始化呼叫 (initForegroundServiceManagerMessageAndIntent()initForegroundServiceManagerProvider()),則您應該 並加上 try-catch 區塊,這樣系統才能重新輸入該路徑Navigation SDK 會在您多次呼叫任何方法時擲回執行階段例外狀況,除非您 請先清除 ForegroundServiceManager 的所有參照,並呼叫 再呼叫 clearForegroundServiceManager()

initForegroundServiceManagerMessageAndIntent() 的四個參數是 applicationnotificationIddefaultMessageresumeIntent。如果 最後三個參數為空值,接著通知是標準參數 Navigation SDK 通知。你仍然可以隱藏其他前景 選用 Google Cloud 服務notificationId 參數會指定應用於通知的通知 ID。如果是 空值,則會使用任意值。您可以明確設定,以便解決與其他通知 (例如其他 SDK 的通知) 發生衝突的問題。defaultMessage 是系統未導覽時顯示的字串。resumeIntent 是通知時觸發的意圖 即可。如果 resumeIntent 為空值,系統會忽略通知的點擊次數。

initForegroundServiceManagerProvider() 的三個參數為 applicationnotificationIdnotificationProvider。如果最後兩個參數為空值,則通知為標準 Navigation SDK 通知。notificationId 參數會指定應用於通知的通知 ID。如果為空值,則會使用任意值。您可以明確設定,以便解決與其他通知 (例如其他 SDK 的通知) 發生衝突的問題。如果 notificationProvider 是 供應商就必須負責 產生要顯示的通知

Navigation SDK getForegroundServiceManager() 方法會傳回 前景服務管理工具單例模式如果您尚未產生一個,那麼這就等同於使用 notificationIddefaultMessageresumeIntent 的空參數呼叫 initForegroundServiceManagerMessageAndIntent()

ForegroundServiceManager 有三個簡單方法。前兩個用於 將服務移入及移出前景,通常都是從 建立位於建立的 Service 中使用這些方法可確保 都會與共用永久通知建立關聯最後一個 方法 updateNotification(),會標記通知含有通知的管理員 並應重新轉譯。

如果您需要完全控制共用持續性通知,API 會提供 NotificationContentProvider 介面,用於定義通知提供者,其中包含取得包含目前內容的通知的單一方法。此 API 也提供基礎類別,您可以 視需要用來定義供應器基礎類別的主要用途之一,是提供一種方法,讓您不必存取 ForegroundServiceManager 即可呼叫 updateNotification()。如果您使用通知供應器的例項來接收新的通知訊息,可以直接呼叫這個內部方法,在通知中顯示訊息。

使用情境

本節詳細說明使用共用永久儲存空間的情境 通知。

隱藏其他應用程式前景服務的持續通知
最簡單的情境是保留目前行為,並只使用 轉譯 Navigation SDK 資訊的永久通知。其他服務可以使用前景服務管理器 startForeground()stopForeground() 方法,隱藏在該通知後方。
隱藏其他應用程式前景服務的持續通知,但已設定 未導航時顯示的預設文字
第二個最簡單的情況是保留目前行為,並只在系統未導覽時使用持續性通知來轉譯 Navigation SDK 資訊。系統沒有進行導覽時 提供給 initForegroundServiceManagerMessageAndIntent() 的字串 ,而不是先前提到的 「Google 地圖」。您也可以使用這個呼叫來設定在點選通知時觸發的繼續意圖。
完全掌控持續性通知的顯示設定
最後一種情況需要定義及建立通知供應器,並使用 initForegroundServiceManagerProvider() 將其傳遞至 ForegroundServiceManager。這個選項可讓您完全控制通知中顯示的內容,但也會將 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 後,請將 使用下列程式碼導覽 SDK:

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

注意事項與未來計畫

  • 請務必提早呼叫 initForegroundServiceManagerMessageAndIntent()initForegroundServiceManagerProvider(),以便明確定義預期的使用情境。您必須先呼叫這個方法,才能建立新的 Navigator。
  • 請務必找出與 initForegroundServiceManagerMessageAndIntent()initForegroundServiceManagerProvider() (如果程式碼路徑為 重複輸入。在 Navigation SDK 2.0 版中,呼叫此方法 多次擲回已檢查的例外狀況,而非執行階段例外狀況。
  • Google 可能還要做一些努力,才能使樣式更加一致 符合標頭樣式的通知的生命週期。
  • 定義通知供應程式時,您可以控制抬頭通知行為 與優先權
  • Google 無法提供簡便的即時路線擷取方法 通知供應程式可能插入通知中的資訊。