Android API レベル 26 以降では、フォアグラウンド サービスに継続的な通知が必要です。この要件は、特にバッテリーなど、システム リソースを過剰に消費する可能性があるサービスを非表示にすることを防ぐことを目的としています。この要件により、潜在的な問題が発生する可能性があります。複数のフォアグラウンド サービスを持つアプリで、通知がすべてのサービスで共有されるように慎重に管理されていない場合、閉じることができない通知が複数残り、通知のアクティブ リストが不要に混雑する可能性があります。
Navigation SDK などの SDK を使用すると、この問題はさらに複雑になります。これらの SDK は、アプリとは独立してフォアグラウンド サービスを実行し、独自の永続的な通知を持ち、統合が困難になります。こうした問題に対処するため、Navigation SDK v1.11 では、SDK 内を含むアプリ全体で永続的な通知を管理するためのシンプルな API が導入されました。
コンポーネント
フォアグラウンド サービス マネージャーは、Android フォアグラウンド サービス クラスと永続通知クラスをラップします。このラッパーの主な機能は、通知 ID の再利用を強制し、マネージャーを使用してすべてのフォアグラウンド サービスで通知を共有することです。
Navigation SDK には、ForegroundServiceManager
シングルトンの初期化と取得を行う静的メソッドが含まれています。このシングルトンは、Navigation SDK の存続期間中に 1 回だけ初期化できます。したがって、初期化呼び出し(initForegroundServiceManagerMessageAndIntent()
または initForegroundServiceManagerProvider()
)のいずれかを使用する場合は、そのパスが再入力された場合に備えて、try-catch ブロックで囲む必要があります。どちらのメソッドも複数回呼び出すと、Navigation SDK はランタイム例外をスローします。ただし、最初に ForegroundServiceManager
へのすべての参照を消去し、その後の呼び出しの前に clearForegroundServiceManager()
を呼び出すと、例外はスローされません。
initForegroundServiceManagerMessageAndIntent()
の 4 つのパラメータは、application
、notificationId
、defaultMessage
、resumeIntent
です。最後の 3 つのパラメータが null の場合、通知は標準の Navigation SDK 通知です。アプリ内の他のフォアグラウンド サービスをこの通知の背後に非表示にすることは可能です。notificationId
パラメータには、通知に使用する通知 ID を指定します。null の場合は、任意の値が使用されます。別の SDK からの通知など、他の通知との競合を回避するために、明示的に設定できます。defaultMessage
は、システムがナビゲートしていないときに表示される文字列です。resumeIntent
は、通知がクリックされたときにトリガーされるインテントです。resumeIntent
が null の場合、通知のクリックは無視されます。
initForegroundServiceManagerProvider()
の 3 つのパラメータは、application
、notificationId
、notificationProvider
です。最後の 2 つのパラメータが null の場合、通知は標準の Navigation SDK 通知です。notificationId
パラメータには、通知に使用する通知 ID を指定します。null の場合は、任意の値が使用されます。他の SDK からの通知などの他の通知との競合を回避するために、明示的に設定できます。notificationProvider
が設定されている場合、レンダリングされる通知の生成は常にプロバイダの責任となります。
Navigation SDK の getForegroundServiceManager()
メソッドは、フォアグラウンド サービス マネージャーのシングルトンを返します。まだ生成していない場合は、notificationId
、defaultMessage
、resumeIntent
に null パラメータを指定して initForegroundServiceManagerMessageAndIntent()
を呼び出す場合と同じです。
ForegroundServiceManager
には 3 つの簡単なメソッドがあります。最初の 2 つは、サービスをフォアグラウンドに移動したり、フォアグラウンドから移動したりするためのもので、通常は作成されたサービス内から呼び出されます。これらの方法を使用すると、サービスが共有された永続通知に関連付けられます。最後のメソッド updateNotification()
は、通知が変更され、再レンダリングが必要であることをマネージャーに通知します。
共有の永続通知を完全に制御する必要がある場合は、API で通知プロバイダを定義するための NotificationContentProvider
インターフェースが提供されます。このインターフェースには、現在のコンテンツを含む通知を取得するための単一のメソッドが含まれています。また、プロバイダの定義に役立つ基本クラスも用意されています。ベースクラスの主な目的の 1 つは、ForegroundServiceManager
にアクセスしなくても updateNotification()
を呼び出す方法を提供することです。通知プロバイダのインスタンスを使用して新しい通知メッセージを受信する場合は、この内部メソッドを直接呼び出して、通知にメッセージをレンダリングできます。
利用シナリオ
このセクションでは、共有永続通知を使用するユースケースについて詳しく説明します。
- 他のアプリのフォアグラウンド サービスの永続的な通知を非表示にする
- 最も簡単なシナリオは、現在の動作を維持し、Navigation SDK 情報をレンダリングする場合にのみ、永続的な通知を使用することです。他のサービスは、フォアグラウンド サービス マネージャーの
startForeground()
メソッドとstopForeground()
メソッドを使用して、この通知の背後に隠すことができます。 - 他のアプリのフォアグラウンド サービスの永続的な通知を非表示にしますが、ナビゲートしていないときに表示されるデフォルトのテキストを設定します。
- 2 番目に簡単なシナリオは、現在の動作を維持し、システムがナビゲートしていない場合を除き、Navigation SDK 情報をレンダリングするために永続通知のみを使用することです。システムがナビゲーションを行っていない場合、
initForegroundServiceManagerMessageAndIntent()
に指定された文字列が表示されます。デフォルトの Navigation SDK 文字列には「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
を作成したら、次のコードを使用して 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 は、通知プロバイダが通知に挿入するルート案内情報を取得するための簡単な手段を提供していません。