Google Cloud Messaging (GCM) 메시지 컨셉과 옵션

google_developers_logo

Google Cloud Messaging API들은 다양한 옵션과 넓은 범위의 기능을 제공합니다. 이 문서는 GCM 메시지와 일반적으로 사용되는 메시지 옵션들을 통해 GCM API들을 사용해서 무엇을 할 수 있는지에 대한 설명을 할 예정입니다. GCM의 기본적인 개념에 대해서는 [Google Cloud Messaging (GCM) 개요]를 먼저 읽으시길 권장드립니다.

메시지의 컴포넌트들

앱서버는 타겟, 메시지 옵션, 페이로드와 같은 기본 컴포넌트들로부터 다운스트림 메시지를 생성합니다. 이 컴포넌트들은 GCM HTTP 및 XMPP 커넥션 서버의 프로토콜들 사이에서 일반적으로 사용되는 컴포넌트들입니다.

타겟 (Target)

필수사항입니다. 당신의 앱 서버가 메시지를 발송할 때 메시지가 도착할 목적지 타겟의 식별자들을 특정 지어주어야 합니다. 타겟을 지정하는데에는 to 필드를 사용합니다. 이 필드에는 하나의 Registration Token 또는 Topic 또는 Notification Key (디바이스 그룹 단위에 발송하는데에 사용)를 포함할 수 있습니다.

옵션 (Options)

앱 서버는 클라이언트 앱에 다운스트림 메시지를 발송할 때 가령 이 메시지가 다음 메시지로 교체될 수 있는 여부를 설정한다던지 등, 다양한 옵션을 설정할 수 있습니다. 이러한 메시지 옵션의 전체 목록을 보기위해서는 아래에 언급될 당신이 사용중인 서버 프로토콜에 적합한 레퍼런스를 참고하시기 바랍니다.

페이로드 (Payload)

다운스트림 메시지 발송에서, GCM은 노티피케이션(Notification)과 데이터(Data) 두가지 형태의 페이로드를 제공합니다. 노티피케이션은 더 가벼운 방법으로써 2KB의 제한을 가진 유저에게 보여질 사전 정의된 키입니다.데이터는 개발자가 최대 4KB 크기의 커스터마이징 가능한 키/값 쌍을 전송할 수 있게 해줍니다. 노티피케이션 메시지는 유저가 노티피케이션을 클릭했을 때 전달되게 되는 Data 페이로드도 포함할 수 있습니다.

  • 노티피케이션 : GCM은 클라이언트 앱을 대신해서 자동으로 메시지를 유저에게 보여줍니다. 노티피케이션은 미리 정의된 사용자에게 보여질 키들로 구성되어있습니다. notification 페이로드를 설정하면 되며 추가로 data 페이로드를 설정하는것도 가능합니다. 항상 최종 메시지만이 유저에게 노출됩니다. (기존의 푸시 메시지를 덮어 씀)
  • 데이터 : 클라이언트 앱은 데이터 메시지를 처리하기 위해 응답해야 합니다. 이 데이터 메시지는 개발자가 임의 지정한 키와 값의 쌍으로 이루어져있습니다. data 페이로드만을 사용해야 합니다. 최종 메시지만 노출되게 할지 모든 메시지를 노출할지 선택할 수 있습니다.

GCM이 당신의 앱을 대신하여 노티피케이션을 유저에게 보여 주길 원할 경우 노티피케이션 페이로드를 사용하면 되며 당신의 앱이 직접 그 노티피케이션을 보여주거나 조작하길 원한다면 데이터 페이로드를 활용하면 됩니다. 만약 당신이 GCM과 다이렉트 커넥션을 맺고 있는 상태의 iOS 디바이스에 메시지를 발송하길 원할때도 데이터 페이로드를 사용할 수 있습니다.

앱 서버는 노티피케이션과 데이터 페이로드 모두를 함께 발송할 수 있습니다. 이런 경우에 GCM이 노티피케이션 페이로드의 정보를 처리하고 클라이언트 앱이 데이터 페이로드를 처리하게 됩니다. 더 자세한 정보와 예제는 이후의 내용을 참고하시기 바랍니다.

gcm-versatile-messaging-targets

메시지 페이로드의 노티피케이션과 데이터

노티피케이션은 개발자에게 몇가지 미리 정의된 키들과 커스터마이징된 키/값 쌍을 사용하여 유저에게 보여줄 수 있는 메시지를 발송할 수 있는 쉬운 방법을 제공합니다. 데이터 페이로드는 개발자가 임의 정의한 커스텀 키/값 쌍만을 사용하며 클라이언트 앱은 반드시 이것을 어떻게 처리할지 구현이 되어있어야 합니다. 당신은 노티피케이션과 데이터 페이로드 둘을 모두 동시에 사용하여 발송 할 수 있습니다.

노티피케이션

노티피케이션을 발송하기 위해서는 유저에게 보여줄 노티피케이션을 이루는 미리 정의된 키들로 이루어져 있는 notification 을 설정해야 합니다. 예를 들어 인스턴트 메세징 어플리케이션의 노티피케이션 메시지를 JSON 포맷으로 구성해보면 다음과 같을 것입니다. 유저의 디바이스에 제목이 “Portugal vs. Denmark”이고 메시지는 “great match!” 라고 출력될 것을 예상할 수 있습니다.

{
  "to": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
  "notification": {
    "body": "great match!",
    "title": "Portugal vs. Denmark",
    "icon": "myicon"
  }
}

앱이 비활성화되어있는 상태에 메시지가 도착하게 되면 디바이스의 노티피케이션 트레이로 도착을 하게 됩니다. 활성화 되어있는 iOS 앱의 경우 노티피케이션은 didReceiveRemoteNotification: 으로 전달되게 됩니다. 활성화 되어있는 Android 앱의 경우 노티피케이션은 notification 키 아래의 페이로드가 onMessageReceived() 에 전달되게 됩니다.

데이터 메시지

당신의 클라이언트 앱에 전송하고자 하는 개발자 임의의 커스텀 키/값 쌍으로 구성된 data 를 설정합니다. 데이터 메시지는 최대 4KB의 크기를 가질 수 있습니다. 다음은 위와 같이 인스턴트 메세징 앱을 예로 들어본 예시입니다. 하지만 위의 컨텐츠를 data 에 좀 더 캡슐화 하여 정의하였습니다.

{
  "to": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
  "data": {
    "Nick": "Mario",
    "body": "great match!",
    "Room": "PortugalVSDenmark"
  }
}

Android에서 클라이언트 앱은 onMessageReceived() 에서 데이터 메시지를 수신받고 키/값 쌍을 처리할 수 있습니다. iOS에서는 GCM이 메시지를 보관하고 앱이 포그라운드로 복귀하고 GCM 커넥션을 맺을 때 메시지를 전송하게 됩니다.

이러한 플랫폼 별 세부사항을 정리해 보면 다음과 같습니다.

  • Android에서는 Intent를 이용해서 당신의 엑티비티를 실행하여 data 페이로드를 수신할 수 있습니다.
  • iOS에서는 didReceiveRemoteNotification: 안에서만 data 페이로드를 받을 수 있습니다.

만약 당신이 커스텀 키/값들로만 이루어진 메시지를 백그라운드 상태인 iOS 앱에 전송하고 싶다면 data 키에 원하는 커스텀 키/값을 설정하고 content_available 를 true로 설정하시기 바랍니다.

노티피케이션과 데이터 페이로드를 모두 포함한 하이브리드 메시지에 대해

노티피케이션과 데이터 페이로드를 모두 가지고 있는 메시지를 앱이 수신했을 때 어떻게 동작하는지는 앱이 백그라운드에 있는지 포그라운드에 있는지에 따라 다릅니다. 정리하자면 수신 시점에 앱이 활성화 되어있는지 아닌지에 따라 결정됩니다.

  • 백그라운드의 경우, 앱은 노티피케이션 트레이의 노티피케이션 페이로드를 수신받습니다. 그리고 유저가 이 노티피케이션을 탭하였을 경우에만 데이터 페이로드를 조작할 수 있습니다.
  • 포그라운드의 경우, 당신의 앱은 이 두가지 페이로드를 모두 수신받을 수 있습니다.

다음은 notification과 data 페이로드 둘 모두를 가진 JSON 포맷의 예제입니다.

{
  "to": "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
  "notification": {
    "body": "great match!",
    "title": "Portugal vs. Denmark",
    "icon": "myicon"
  },
  "data": {
    "Nick": "Mario",
    "Room": "PortugalVSDenmark"
  }
}

일반적으로 사용되는 메시지 옵션

이번에는 일반적으로 사용되는 단순한 형태의 다운스트림 메시지를 발송할 때 자주 사용되는 옵션에 대해 자세히 알아보겠습니다. 이러한 옵션에는 메시지 교체(Collapsible Messaging), 다중 발송자(Multiple Senders), 메시지 우선순위(Message Priority), 메시지 수명(Lifespan for Messages) 등이 있습니다.

교체 가능한/불가능한 메시지

정확한 영문 문서의 표기는 Collapsible / Non Collapsible Messages 입니다만. 이걸 한글로 옮겨적기에 적절한 단어가 아닌것 같아 “교체 가능/불가능” 정도로 번역해 보았습니다. 참고 부탁드립니다.

교체 불가능한(Non-collapsible) 메시지

교체 불가능한 메시지는 각각의 개별 메시지가 모두 디바이스에 도착하게 된다는 의미를 가지고 있습니다. 교체 불가능한 메시지는 어떤 유용한 컨텐츠등을 모바일 앱이 서버에 접속하여 데이터를 가져오게 한다던지 하는데에 사용될 수 있습니다. 항상 교체되는 노티피케이션을 제외하고 모든 메시지는 기본적으로 교체 불가능한 메시지입니다. GCM은 발송 순서 대기 도착하는 순서를 보장하지 않습니다.

몇몇 적절한 교체 불가능한 메시지의 사용예로는 채팅 메시지나 크리티컬 메시지가 있습니다. 예로 인스턴트 메세징 앱에서 당신은 모든 메시지를 GCM을 통해 전달하고 싶을 수 있습니다. 왜냐하면 각각의 메시지는 다른 컨텐츠이기 때문입니다.

참고 : 메시지는 기본적으로 최대 100개까지 교체되지 않고 보관될 수 있습니다. 이 제한에 도달하게 될 경우 모든 저장된 메시지는 버려집니다. 디바이스가 온라인으로 돌아오면 이 제한에 도달했음을 알리는 특별한 메시지가 수신됩니다. 이경우 앱은 서버와 전체 동기화 작업을 하는등의 적절한 대응을 해야 합니다.

교체 가능한(Collapsible) 메시지

교체 가능한 메시지는 같은 Collapse 키를 가진 새로운 메시지가 도착하면 기존의 메시지가 교체되는 메시지를 의미합니다.

이러한 교체 가능한 메시지의 일반적인 두가지 사용 예로는 동기 발송 메시지와 노티피케이션이 있습니다. 동기 발송 메시지는 모바일 앱이 서버와 데이터 동기화를 하도록 “Ping”을 보내는 역할을 하는 메시지 입니다. 예로 경기의 가장 최신 점수를 유저에게 보여주는 스포츠앱이 있다고 할 때, 가장 마지막에 발송한 메시지만이 유효한 정보일것입니다.

GCM은 앱서버가 디바이스에 언제든지 발송할 수 있는 Collapse 키를 최대 4개까지 지원합니다. 다른 말로 GCM 커넥션 서버는 각 디바이스에 동기 발송을 할 수 있수 교체 가능한 메시지를 각기 다른 Collapse 키를 사용하여 동시에 최대 4개까지 저장할 수 있음을 말합니다. 만약에 GCM이 정의한 이 4개의 제한을 초과 할 경우 어떤 Collapse 키가 유지될지 보장할 수 없습니다.

iOS 환경에서 앱 서버가 동기 메시지 발송을 할 필요가 있을 때 content_available 를 설정하면 비활성화 되어있는 클라이언트 앱이 백그라운드에서 당신이 정의한 로직을 수행하게 되며 앱이 포그라운드에 돌아올 때 didReceiveRemoteNotification: 에 메시지를 전달하게 됩니다.

무엇을 할 수 있나?

당신의 앱이 교체불가능한 메시지를 제공해야 할 필요가 없다면 퍼포먼스 관점에서 교체가능한 메시지를 사용하는것이 더 나은 선택입니다. 하지만 교체가능한 메시지를 사용할 경우 GCM은 Registration Token별로 GCM 커넥션 서버에 의해 최대 4개의 Collapse 키만이 허용된다는 점을 기억하시기 바랍니다. 절대로 이 제한을 초과해서는 안되며 이 경우 예측 불가능한 상황이 발생할 수 있습니다.

  • 교체 불가능한 메시지 : 클라이언트 앱 입장에서 모든 메시지가 중요할 경우에 사용하십시오. 노티피케이션 메시지를 제외하고 모든 메시지는 기본적으로 교체 불가능한 메시지입니다.
  • 교체 가능한 메시지 : 클라이언트 앱 입장에서 오래된 필요없어진 메시지가 더 새로운 메시지에 의해 교체될 필요가 있을때 사용합니다. GCM은 기존의 메시지를 교체합니다. 예로 동기 메시지 발송 목적이나 기한이 지난 메시지를 교체할 목적으로 사용합니다. collapse_key 파라미터를 설정하여 적용합니다.

메시지의 우선순위 설정하기

당신은 다운스트림 메시지에 대해 “일반”과 “높은” 우선순위 2가지의 메시지 전달 우선순위 옵션을 선택할 수 있습니다. 이 두가지 옵션은 다음과 같이 동작합니다.

  • 높은 우선순위 : GCM은 높은 우선순위를 가진 메시지를 전달하는 작업을 호출 즉시 시도합니다. GCM 서비스는 잠들어있는 디바이스를 가능할 때 깨우고 네트워크 연결을 복구하여 당신의 앱서버와 통신할 수 있도록 해줍니다. 예를 들어 인스턴트 메세징 앱과 같이 당신의 앱서버와 통신이 필요한 채팅, 보이스 콜 알림이 있을 경우 GCM은 디바이스에 딜레이 없이 바로 도착하도록 해 줄것입니다. 높은 우선순위 설정은 꼭 메시지가 도착 시간이 중요하고 유저가 바로 확인해야 하는 경우에만 사용하여야 하며, 이 높은 우선 순위를 가진 메시지를 일반 우선순위의 메시지에 비해 배터리 소모에 더 많은 기여를 하게 되므로 주의하여 사용할것을 권장합니다.
  • 보통 우선순위 : 이것은 메시지 전달의 기본이 되는 우선순위입니다. 보통 우선 순위 메시지는 잠들어 있는 디바이스에 대해 네트워크 커넥션을 맺지 않고 배터리 보호를 위해 메시지 전달이 늦어질 수 있습니다. 새로운 이메일의 도착이나 다른 필요한 데이터 싱크 작업과 같은 시간이 덜 중요한 메시지의 경우 보통 우선순위 메시지를 사용하시기 바랍니다.

이 파라미터의 올바른 값은 high와 normal입니다. 더 자세한 정보를 확인하려면 HTTP, XMPP 서버 레퍼런스를 확인하시기 바랍니다.

기존의 iOS앱의 경우 메시지 우선 순위를 명시적으로 설정하지 않았었습니다. GCM의 우선순위 정의가 2015년 8월 13일부로 변경되었으므로 당신의 앱의 동작에 변화가 생겼을 수 있습니다. 이런 경우 메시지 발송시에 우선순위를 “높은”으로 변경해주어야 딜레이 없이 바로 전달 할 수 있습니다.

iOS 클라이언트 앱의 경우 “일반”과 “높은” 우선순위의 경우 APNS의 우선순위 레벨 5와 10과 유사하게 정의됩니다. 자세한 내용은 iOS 의 [APNS 문서]를 참고하시기 바랍니다. Android의 경우에는 [도즈 및 스탠바이 최적화하기]를 참고하시기 바랍니다.

다음은 잡지 구독자에게 새로운 컨텐츠를 다운받을 수 있게 되었음을 알리는 “일반” 우선순위를 가진 알림 메시지를 발송하는 예시입니다.

{
  "to": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
  "priority": "normal",
  "notification": {
    "body": "This week’s edition is now available.",
    "title": "NewsMagazine.com",
    "icon": "new"
  },
  "data": {
    "volume": "3.21.15",
    "contents": "http://www.news-magazine.com/world-week/21659772"
  }
}

메시지 수명 설정하기

GCM은 보통 메시지를 발송하는 순간 즉시 전달을 합니다. 하지만 이것이 항상 가능한것은 아닙니다. 예를 들어 플랫폼이 Android라면 디바이스가 꺼져있거나 네트워크에 연결되어있지 않을때 혹은 다른 상황등에서 즉시 전달이 어려울 수 있습니다. 혹은 발송자가 delay_while_idle 플래그를 사용하여 디바이스가 활성화 될때까지 메시지를 전달하지 않도록 요청할 수 있습니다. 결과적으로 GCM은 앱이 과도한 자원낭비를 하게 되거나 배터리에 부정적인 영향을 끼칠 수 있는것을 막도록 메시지를 의도적으로 지연 발송할 수 있습니다.

이러한 일이 발생할 경우 GCM은 메시지를 보관했다가 가능할 때 메시지 전달을 재개합니다. 이러한 기능은 대부분의 경우에는 문제가 없지만 몇몇 앱에서는 이런 경우에 아예 전달되지 않는것이 좋은 경우도 있을 것입니다. 예를 들어 메시지가 전화나 영상통화가 오고 있음을 알리는 노티피케이션이라면 이것은 매우 짧은 순간동안만 유의미할것이며 전화를 받지 않아 결국 끊어진 이후에는 의미가 없을 것입니다. 또는 어떤 이벤트의 초대장을 포함한 메시지라면 이 이벤트가 끝난 뒤에는 의미가 없을것입니다.

이럴 경우 HTTP와 XMPP 요청 모두에서 time_to_live 파라미터를 사용하여 메시지의 최대 수명을 정의할 수 있습니다. 이 파라미터는 0에서 2,419,200초의 기간으로 설정되어야 하며 GCM이 메시지를 보관하고 전달하는데까지 걸리는 시간을 의미합니다. 요청이 이 필드를 설정하지 않을 경우 기본값이 4주로 설정됩니다.

다음과 같은 특별한 기능에 대해 사용할 수 있습니다. (예시)

  • 화상 통화 요청 콜
  • 이벤트 초대 만료
  • 달력 이벤트

메시지의 수명을 설정하는것은 또다른 장점으로는 time_to_live 를 0으로 설정함으로써 GCM이 발송 여부를 관리하지 않게 하는 방법이 있습니다. 다른말로 GCM은 “지금 아니면 필요없다”는 마음으로(?) 최선의 노력을 보장할 수 있습니다. 즉 time_to_live가 0으로 설정된다는 것은 지금 즉시 메시지를 전달할 수 없다면 이 메시지는 버려짐을 의미합니다. 이 메시지는 보관되지 않을것이기 때문에 노티피케이션을 발송하는데에 최고의 응답 속도를 제공할 수 있습니다.

다음은 TTL 설정이 포함되어있는 JSON 형태의 예제입니다.

 {
   "collapse_key" : "demo",
   "delay_while_idle" : true,
   "to" : "xyz",
   "data" : {
     "key1" : "value1",
     "key2" : "value2"
   },
   "time_to_live" : 3
 }

현재, time_to_live 설정은 iOS 환경의 노티피케이션 메시지를 지원하지 않습니다.

다중 발송자로부터 메시지 수신하기

GCM은 다수의 그룹에서 하나의 클라이언트 앱에 메시지를 발송하는것을 허용합니다. 예를 들어 다양한 컨텐츠 컨텐츠들의 글을 하나의 앱이 수집할 때 각각의 생산자들은 자신들의 새로운 글이 생성되었을 때 이 하나의 앱에 메시지를 발송하는 것이 가능합니다. 이 메시지에는 글의 다운로드 URL을 가질 수 있습니다. 모든 컨텐츠를 하나의 장소에 모을 필요없이 GCM은 각각의 생산자들이 자기 자신들의 메시지를 발송할 수 있게 해줍니다.

이것을 가능하게 하기 위해서는 각각의 발송자들은 자신들의 발송자 아이디(Sender ID)를 발급받아야 합니다. 클라이언트 문서를 확인하시고 자신에게 적절한 GCM 발송자 아이디를 발급받으시기 바랍니다. 등록 요청이 되면 클라이언트 앱은 각기 다른 발송자 아이디별로 여러번 토큰을 발급받게 됩니다.

결과적으로 각 앱서버에 대응되는 Registration 토큰을 공유하여 클라이언트 앱과 그들이 가지고 있는 인증 키를 이용하여 메시지 발송이 가능하게 됩니다. 이때에 최대 100개의 다중 발송자 제한이 있습니다.

메시지의 일생 (Lifetime)

앱 서버가 GCM 에 메시지를 전송하고 메시지 ID를 응답받았을 때 이것이 메시지가 이미 디바이스에 도착했다는것을 의미하는것은 아닙니다. 이것은 메시지 전달 요청을 받았음을 의미하며 이 메시지가 정상적으로 전달될 것인지는 다양한 경우의 수에 달려있게 됩니다.

최고의 시나리오는 디바이스가 GCM에 연결되어있고 스크린이 켜져있고 어떤 쓰로틀 제한도 없다면 이 메시지는 지체없이 즉시 전달될 것입니다.

만약 디바이스가 연결은 되어있지만 유휴상태라면 메시지는 delay_while_idle 플래그가 참으로 설정되어있지 않다는 조건하에 즉시 전달됩니다. 그렇지 않다면 이 메시지는 디바이스가 깨어날 때까지 GCM 커넥션 서버에 저장될 것입니다. 그리고 여기서 collapse_key 플래그에 맞추어 다른 동작을 하게 됩니다. 이미 디바이스에 같은 collapse_key를 가진 메시지가 존재할 경우 메시지의 수신을 기다린 후 기존의 메시지는 새로운 메시지에게 자리를 넘겨주고 폐기됩니다. 하지만 collapse_key가 설정되어있지 않다면 새로운 메시지는 기존의 메시지와 함께 보관되게 됩니다.

만약 디바이스가 GCM에 연결되어 있지 않다면 이 메시지는 다시 커넥션이 연결될 때까지 보관됩니다. (Collapse 키의 역할도 여전히 유지됩니다.) 커넥션이 다시 연결되면 GCM은 delay_while_idle 플래그 설정값과 상관없이 모든 지연된 메시지를 디바이스에 전송합니다. 만약 디바이스는 공장초기화와 같은 이유로 다시 연결이 되지 않는다면 이 메시지는 점진적으로 GCM 저장소에서 삭제되어나갈것입니다. 기본적인 유지 기간은 4주이며 time_to_live 플래그를 사용하여 임의의 원하는 시간을 설정할 수 있습니다.

마지막으로 GCM이 디바이스에 메시지 전송을 시도할 때 해당 앱이 삭제된 상태라면 GCM은 그 메시지를 즉시 삭제하고 Registration 토큰을 폐기합니다. 이후에 이 디바이스에 또 메시지 발송을 요청하면 NotRegistered 에러를 받게 됩니다.

참고 : https://developers.google.com/cloud-messaging/concept-options