모바일 알림 통합

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

이 문제는 자체의 독립적인 영구 알림이 있는 앱과 별개로 포그라운드 서비스를 실행하는 Navigation 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이면 알림이 표준 내비게이션 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()를 호출하는 방법을 제공하는 것입니다. 알림 제공업체의 인스턴스를 사용하여 새 알림 메시지를 수신하는 경우 이 내부 메서드를 직접 호출하여 알림에 메시지를 렌더링할 수 있습니다.

사용 시나리오

이 섹션에서는 공유 영구 알림 사용 시나리오를 자세히 설명합니다.

다른 앱 포그라운드 서비스의 지속적 알림 숨기기
가장 쉬운 시나리오는 현재 동작을 유지하고 Navigation SDK 정보를 렌더링하는 데만 영구 알림을 사용하는 것입니다. 다른 서비스는 포그라운드 서비스 관리자 startForeground()stopForeground() 메서드를 사용하여 이 알림 뒤에 숨길 수 있습니다.
다른 앱 포그라운드 서비스의 영구 알림을 숨기지만 탐색하지 않을 때 표시되는 기본 텍스트를 설정합니다.
두 번째로 쉬운 시나리오는 현재 동작을 유지하고 시스템이 탐색하지 않는 경우를 제외하고 Navigation SDK 정보를 렌더링하는 데만 영구 알림을 사용하는 것입니다. 시스템이 탐색 중이 아닐 때는 initForegroundServiceManagerMessageAndIntent()에 제공된 문자열이 'Google 지도'를 언급하는 기본 내비게이션 SDK 문자열 대신 표시됩니다. 이 호출을 사용하여 알림을 클릭할 때 실행되는 재개 인텐트를 설정할 수도 있습니다.
영구 알림 렌더링을 완전히 제어합니다.
마지막 시나리오에서는 알림 제공자를 정의하고 만들고 initForegroundServiceManagerProvider()를 사용하여 ForegroundServiceManager에 전달해야 합니다. 이 옵션을 사용하면 알림에 렌더링되는 항목을 완전히 제어할 수 있지만, 내비게이션 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은 알림 제공업체가 알림에 삽입할 수 있는 세부 경로 정보를 검색하는 간단한 방법을 제공하지 않습니다.