모바일 알림 통합

Android API 수준 26부터 포그라운드 서비스에는 지속적인 알림이 필요합니다. 이 요구사항은 특히 배터리를 비롯한 시스템 리소스에 과도한 요구를 할 수 있는 서비스를 숨기는 것을 방지하기 위한 것입니다. 이 요구사항은 잠재적인 문제를 야기합니다. 포그라운드 서비스가 여러 개인 앱이 모든 서비스에서 공유되도록 알림을 신중하게 관리하지 않으면 영구적이고 닫을 수 없는 알림이 여러 개 표시되어 활성 알림 목록이 불필요하게 어수선해질 수 있습니다.

이 문제는 자체 독립적인 지속적 알림이 있어 통합하기 어려운 앱과 독립적으로 포그라운드 서비스를 실행하는 탐색 SDK와 같은 SDK를 사용하는 경우 더욱 어려워집니다. 이러한 문제를 해결하기 위해 Navigation SDK v1.11에서는 SDK 내를 비롯해 앱 전반에서 지속적인 알림을 관리하는 데 도움이 되는 간단한 API를 도입했습니다.

지속적 알림 통합

구성요소

포그라운드 서비스 관리자는 Android 포그라운드 서비스 클래스와 지속적인 알림 클래스에 래퍼를 제공합니다. 이 래퍼의 기본 기능은 관리자를 사용하여 모든 포그라운드 서비스에서 알림이 공유되도록 알림 ID의 재사용을 강제하는 것입니다.


Navigation SDK에는 ForegroundServiceManager 싱글톤을 초기화하고 가져오는 정적 메서드가 포함되어 있습니다. 이 싱글톤은 Navigation SDK의 수명 주기에서 한 번만 초기화할 수 있습니다. 따라서 초기화 호출 (initForegroundServiceManagerMessageAndIntent() 또는 initForegroundServiceManagerProvider()) 중 하나를 사용하는 경우 경로가 다시 입력될 수 있으므로 try-catch 블록으로 묶어야 합니다. ForegroundServiceManager에 대한 모든 참조를 먼저 지우고 후속 호출 전에 clearForegroundServiceManager()를 호출하지 않는 한 두 메서드 중 하나를 두 번 이상 호출하면 Navigation SDK에서 런타임 예외가 발생합니다.

initForegroundServiceManagerMessageAndIntent()의 네 가지 매개변수는 application, notificationId, defaultMessage, resumeIntent입니다. 마지막 세 매개변수가 null이면 알림은 표준 Navigation SDK 알림입니다. 이 알림 뒤에 앱의 다른 포그라운드 서비스를 숨기는 것은 여전히 가능합니다. notificationId 매개변수는 알림에 사용해야 하는 알림 ID를 지정합니다. null이면 임의의 값이 사용됩니다. 다른 SDK의 알림과 같은 충돌을 해결하기 위해 명시적으로 설정할 수 있습니다. defaultMessage는 시스템이 탐색하지 않을 때 표시되는 문자열입니다. resumeIntent는 알림을 클릭할 때 실행되는 인텐트입니다. resumeIntent이 null이면 알림 클릭이 무시됩니다.

initForegroundServiceManagerProvider()의 세 매개변수는 application, notificationId, notificationProvider입니다. 마지막 두 매개변수가 null이면 알림은 표준 Navigation SDK 알림입니다. notificationId 매개변수는 알림에 사용해야 하는 알림 ID를 지정합니다. null이면 임의의 값이 사용됩니다. 다른 SDK의 알림과 같은 충돌을 해결하기 위해 명시적으로 설정할 수 있습니다. notificationProvider가 설정된 경우 제공자는 항상 렌더링할 알림을 생성해야 합니다.

Navigation SDK getForegroundServiceManager() 메서드는 포그라운드 서비스 관리자 싱글톤을 반환합니다. 아직 생성하지 않은 경우 notificationId, defaultMessage, resumeIntent에 null 매개변수를 사용하여 initForegroundServiceManagerMessageAndIntent()를 호출하는 것과 같습니다.

ForegroundServiceManager에는 세 가지 간단한 메서드가 있습니다. 처음 두 개는 서비스를 포그라운드로 이동하거나 포그라운드에서 이동하는 데 사용되며 일반적으로 생성된 서비스 내에서 호출됩니다. 이러한 방법을 사용하면 서비스가 공유된 지속적 알림과 연결됩니다. 마지막 메서드인 updateNotification()는 알림이 변경되었으며 다시 렌더링해야 함을 관리자에게 알립니다.

공유된 지속적 알림을 완전히 제어해야 하는 경우 API는 알림 제공자를 정의하는 NotificationContentProvider 인터페이스를 제공합니다. 이 인터페이스에는 현재 콘텐츠가 포함된 알림을 가져오는 단일 메서드가 포함되어 있습니다. 또한 제공자를 정의하는 데 선택적으로 사용할 수 있는 기본 클래스도 제공합니다. 기본 클래스의 주요 목적 중 하나는 ForegroundServiceManager에 액세스하지 않고도 updateNotification()를 호출하는 방법을 제공하는 것입니다. 알림 제공자 인스턴스를 사용하여 새 알림 메시지를 수신하는 경우 이 내부 메서드를 직접 호출하여 알림에 메시지를 렌더링할 수 있습니다.

사용 시나리오

이 섹션에서는 공유 영구 알림을 사용하는 사용 사례를 자세히 설명합니다.

다른 앱 포그라운드 서비스의 지속적 알림 숨기기
가장 쉬운 시나리오는 현재 동작을 유지하고 탐색 SDK 정보를 렌더링하는 데만 지속적인 알림을 사용하는 것입니다. 다른 서비스는 포그라운드 서비스 관리자 startForeground()stopForeground() 메서드를 사용하여 이 알림 뒤에 숨길 수 있습니다.
다른 앱 포그라운드 서비스의 지속적인 알림을 숨기지만 탐색하지 않을 때 표시되는 기본 텍스트를 설정합니다.
두 번째로 쉬운 시나리오는 현재 동작을 유지하고 시스템이 탐색하지 않는 경우를 제외하고 탐색 SDK 정보를 렌더링하는 데만 지속적인 알림을 사용하는 것입니다. 시스템이 탐색하지 않을 때는 initForegroundServiceManagerMessageAndIntent()에 제공된 문자열이 'Google 지도'를 언급하는 기본 Navigation SDK 문자열 대신 표시됩니다. 이 호출을 사용하여 알림을 클릭할 때 실행되는 재개 인텐트를 설정할 수도 있습니다.
지속적인 알림의 렌더링을 완전히 제어
마지막 시나리오에서는 알림 제공자를 정의하고 만들어 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()를 일찍 호출해야 합니다. 새 Navigator를 만들기 전에 이 메서드를 호출해야 합니다.
  • 코드 경로가 두 번 이상 입력되는 경우를 대비하여 initForegroundServiceManagerMessageAndIntent() 또는 initForegroundServiceManagerProvider() 호출에서 예외를 포착해야 합니다. Navigation SDK v2.0에서는 이 메서드를 여러 번 호출하면 런타임 예외가 아닌 검사 예외가 발생합니다.
  • Google은 알림 수명 동안 헤더 스타일과 일치하는 일관된 스타일을 적용하기 위해 작업을 해야 할 수 있습니다.
  • 알림 제공자를 정의할 때 우선순위로 알림 동작을 제어할 수 있습니다.
  • Google은 알림 제공자가 알림에 삽입할 수 있는 턴바이턴 정보를 가져오는 간단한 수단을 제공하지 않습니다.