이전 글 (http://zeany.net/27) 에서 알아본 백그라운드에서 실행 중인 앱에 클라우드 메시지를 보내는 것에 더해
이제 포그라운드에서도 실행 중인 앱에서도 클라우드 메시지를 받을 수 있도록 해보겠습니다.
1. FirebaseMessagingService
FCM의 안드로이드 메시지 수신 (https://firebase.google.com/docs/cloud-messaging/android/receive?hl=ko) 에 나와있듯이 포그라운드에서 메시지를 받으려면 FirebaseMessagingService를 상속받아 프로젝트에 추가하고 onMessageReceived() 콜백을 재정의해야 합니다.
FCM console에서 데이터만 보내서 앱 상태에 상관없이 onMessageReceived()에서 처리하도록 할 수도 있겠지만, 제가 아는 한 FCM console에서는 알림 또는 모두만 보낼 수 있지, 데이터만 보낼 수는 없도록 되어 있습니다.
클라우드 메시지는 아래와 같은 JSON 형식으로 되어 있는데, 여기에서 notification이 '알림'이고 data는 '데이터'를 말합니다. 즉, 아래 메시지는 알림과 데이터가 '모두' 있는 형태이고, 이 메시지를 기기에서 받게 되면 앱이 백그라운드일 때는 notification의 title과 body를 작업표시줄에 보여주고, 앱이 포그라운드일 때는 data내의 값들을 onMessageReceived()에서 처리하게 됩니다.
예제에서는 아래 메시지를 FCM console을 가지고 전송했고, onMessageReceived()에서는 data의 title과 message를 작업표시줄에 보여주도록 했기 때문에, 앱이 백그라운드에 있을 때는 Background Message를 보여주고, 앱이 포그라운드에 있을 때는 Foreground Message를 보여주게 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 | { "to" : "dzs3phj...", "priority" : "high", "notification" : { "body" : "Background Message", "title" : "BG Title" }, "data" : { "title" : "FG Title", "message" : "Foreground Message" } } |
2. FirebaseInstanceIDService
그리고, 지금까지는 전체 앱(을 설치한 모든 단말)에 메시지를 보냈으나, 그 외의 방법으로 개별 기기에 보내는 방법과 각 Topic에 가입한 기기들에게만 메시지를 보내는 방법 등도 있습니다.
개별 기기에 메시지를 보내기 위해서는 해당 기기의 등록 토큰을 알야하는데, 이 토큰은 다음과 같은 경우에 변경될 수 있습니다.
- 앱에서 인스턴스 ID 삭제
- 새 기기에서 앱 복원
- 사용자가 앱 삭제/재설치
- 사용자가 앱 데이터 소거
등록 토큰이 변경될 경우에는 FirebaseInstanceIDService의 onTokenRefresh() 콜백 메소드가 호출되게 됩니다.
즉, 일반적으로 클라우드 메시지를 처리하는 앱에서는 위 메소드를 override해서 매번 token이 변경될 때마다 특정 서버에 API를 통해 저장해 놓아야 합니다. 이번 예제에서는 단순히 token 값을 안드로이드 log로 출력하는 수준으로 구현합니다.
3. 프로젝트에 FirebaseMessagingService, FirebaseInstanceIDService 추가
1) MyFirebaseMessagingService
FCM 예제에 나와 있듯이 클래스 이름은 단순하게 MyFirebaseMessagingService로 정했는데, 원하는 이름으로 변경 가능합니다. (단 아래의 AndroidManifest.xml에서의 서비스 이름도 동일하게 변경 필요합니다.)
onMessageReceived()를 보면 전달 받은 remoteMessage의 getData()의 title과 message를 showNotification()에 전달하고 거기서는 작업표시줄에 보여주도록 하고 있습니다. (이 부분의 예외 처리는 안했지만, 상용앱이라면 당연히 필요합니다.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public class MyFirebaseMessagingService extends FirebaseMessagingService { @Override public void onMessageReceived(RemoteMessage remoteMessage) { showNotification(remoteMessage.getData().get("title"), remoteMessage.getData().get("message")); } private void showNotification(String title, String message) { Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT); Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle(title) .setContentText(message) .setAutoCancel(true) .setSound(defaultSoundUri) .setContentIntent(pendingIntent); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(0, notificationBuilder.build()); } } |
2) MyFirebaseInstanceIDService
기기의 token 값이 변경될 때 마다 onTokenRefresh()가 호출되는 데 이 때는 보통 해당 값을 서버에 저장해놓고 필요한 작업을 해야 합니다. 하지만 여기서는 Log에 찍은 후 그 값을 가지고 아래에서 특정 기기에 대해서 출력하는 예제를 추가로 보도록 하겠습니다.
1 2 3 4 5 6 7 8 | public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService { @Override public void onTokenRefresh() { Log.d("MyFCM", "FCM token: " + FirebaseInstanceId.getInstance().getToken()); // TODO: 이후 생성등록된 토큰을 서버에 보내 저장해 두었다가 추가 작업을 할 수 있도록 한다. } } |
3) AndroidManifest.xml
위 2개의 서비스를 어떤 Intent 메시지를 전달 받을지와 함께 AndroidManifest.xml에 추가를 해줍니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <service android:name=".MyFirebaseMessagingService" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service> <service android:name=".MyFirebaseInstanceIDService" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.google.firebase.INSTANCE_ID_EVENT" /> </intent-filter> </service> </application> |
4. FCM 클라우드 메시지 전달
FCM console에서 메시지를 생성한 후 메시지 보내기를 클릭하면 앱의 상태에 따라 각각의 메시지가 아래 그림처럼 보여지게 됩니다. (FCM console은 중요한 부분을 제외하고는 편집했습니다.)
5. 단일 기기에 메시지 전달
앱을 설치 후 처음 실행하면 token이 생성되어 MyFirebaseInstanceIDService의 onTokenRefresh() 메소드가 호출됩니다. 이 때의 로그를 살펴보면 다음과 같습니다. 혹시 안보이면 앱을 지운 후 다시 설치하면 token을 새로 받게 됩니다.
FCM console의 Notifications 메뉴에서 메시지를 보낼 때 대상을 단일 기기로 선택 후 FCM 등록 토큰에 로그에 보이는 토큰을 복사&붙여넣기하고 메시지 보내기를 클릭하면 됩니다.
이상으로 FCM을 이용해서 안드로이드 앱으로 클라우드 메시지를 보내는 방법에 대해서 살펴봤습니다.
※ 이 프로젝트는 https://github.com/zeany/webview 에 있으며 아래 명령으로 소스를 가져올 수 있습니다.
(이미 git clone 으로 프로젝트를 내려 받은 경우에는 프로젝트 홈 디렉토리에서 git checkout 만 하면 됩니다.)
git clone https://github.com/zeany/webview.git
cd webview
git checkout -f step-11
'Android' 카테고리의 다른 글
cURL을 이용한 FCM 클라우드 메시지 전송 (2) | 2017.01.12 |
---|---|
FCM 클라우드 메시지의 형식 정리 (0) | 2017.01.12 |
FCM을 이용해 안드로이드 앱으로 메시지 전송 (1) (1) | 2017.01.10 |
안드로이드 앱에 Firebase 추가하기 (5) | 2017.01.09 |
안드로이드 Native에서 Angular JS로 구현된 웹페이지를 보여주는 WebView에 값을 전달하는 방법 (0) | 2017.01.09 |