티스토리 뷰

반응형

GCM(Goolge Cloud Messaging) 에서 FCM(Firebase Cloud Messaging)으로 변경 및 권장한지도 벌써 몇년이 지나고 있습니다. 개발적 이슈 및 기타 이유로 아직도 GCM 을 사용하는 개발자들도 있습니다. 만약 신규 앱을 Push Messaging 사용하려면 FCM 으로 접속하여야 합니다.

그렇다면 어떻게 FCM 을 사용할 수 있을까?

이미 Google에서 'Android FCM' 이라고 검색만 하여도 깔끔하게 정리된 블로그를 쉽게 만날 수 있습니다. 다른 분들과 겹칠 수 있으나 제가 사용하는 FCM 적용 방법을 공유 드리려고 합니다.

 

Firebase 앱 등록

우선 Firebase 에서 Clould Messaging 을 사용하기 위해서 Firebase에 앱을 등록해야합니다.

 

Firebase 접속 > 프로젝트 생성 > 개요 > 안드로이드 앱 추가

안드로이드 앱 추가 시도하면 다음과 같이 스텝 별로 친절히 그림과 함께 어떻게 설정할지 알려줍니다.

 

프로젝트에서 FCM 설정

프로젝트 안에서 FCM 설정할 시 bulid.gradle 에서 dependecies 의 firebase-messaging 을 추가합니다.

 

implementation 'com.google.firebase:firebase-core:16.0.0'implementation 'com.google.firebase:firebase-messaging:12.0.1'

 

 

앱 매니페스트 수정 (파이어베이스 가이드 내용)

앱의manifests 다음을 추가합니다.

MyFirebaseMessagingService, MyFirebaseInstanceIDService 정의가 안되어 있어서 error 메시지가 보일 것입니다. 각 클래스에 대한 정의는 각 역할에 따른 구현할 때 설명하겠습니다.

  • FirebaseMessagingService를 확장하는 서비스를 추가합니다. 백그라운드에서 앱의 알림을 수신하는 것 외에 다른 방식으로 메시지를 처리하려는 경우에 필요합니다. 포그라운드 앱의 알림 수신, 데이터 페이로드 수신, 업스트림 메시지 전송 등을 수행하려면 이 서비스를 확장해야 합니다.
  • AndroidManifest.xml
  • <service    android:name=".MyFirebaseMessagingService">    <intent-filter>        <action android:name="com.google.firebase.MESSAGING_EVENT"/>    </intent-filter></service>
  • 등록 토큰 생성, 순환, 업데이트를 처리하기 위해 FirebaseInstanceIdService를 확장하는 서비스를 추가합니다. 특정 기기로 전송하거나 기기 그룹을 만드는 경우에 필요합니다.
  • AndroidManifest.xml
  • <service    android:name=".MyFirebaseInstanceIDService">    <intent-filter>        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>    </intent-filter></service>
  • (선택사항) 애플리케이션 구성요소에 기본 아이콘 및 색상을 설정하는 메타데이터 요소를 추가합니다. Android는 수신 메시지에 아이콘 또는 색상이 명시적으로 설정되지 않은 경우 이 값을 사용합니다.
  • AndroidManifest.xml
  • <!-- Set custom default icon. This is used when no icon is set for incoming notification messages.     See README(https://goo.gl/l4GJaQ) for more. --><meta-data    android:name="com.google.firebase.messaging.default_notification_icon"    android:resource="@drawable/ic_stat_ic_notification" /><!-- Set color used with incoming notification messages. This is used when no color is set for the incoming     notification message. See README(https://goo.gl/6BKBk7) for more. --><meta-data    android:name="com.google.firebase.messaging.default_notification_color"    android:resource="@color/colorAccent" />
  • (Optional) Android 8.0(API 수준 26) 이상부터는 알림 채널이 지원 및 권장됩니다. FCM은 기본적인 설정과 함께 기본 알림 채널을 제공합니다. 기본 채널을 직접 만들어 사용하려면 아래와 같이 default_notification_channel_id를 알림 채널 객체의 ID로 설정합니다. 수신 메시지에 알림 채널이 명시적으로 설정되지 않았으면 FCM에서 이 값을 사용합니다. 자세한 내용은알림 채널 관리를 참조하세요.
  • AndroidManifest.xml
  • <meta-data    android:name="com.google.firebase.messaging.default_notification_channel_id"    android:value="@string/default_notification_channel_id"/>
  • Android 앱의 기능에 FCM이 매우 중요한 경우 앱의 build.gradle에서 minSdkVersion 8 이상을 설정하세요. 그러면 Android 앱을 제대로 실행할 수 없는 환경에서는 앱을 설치할 수 없습니다.

 

Android FCM 앱 설정

Firebase 클라우드 메시징 Android 클라이언트 앱을 작성하려면 FirebaseMessaging API 및 Android Studio 1.4 이상과 Gradle을 사용합니다. 이 페이지에서는 Android 프로젝트에 Firebase를 추가하는 단계를 완료했다고 가정하고 안내합니다.

FCM 클라이언트에 Android 4.0 이상을 실행하며 Google Play 스토어 앱도 설치되어 있는 기기 또는 Google API로 Android 4.0을 실행하는 에뮬레이터가 필요합니다. Google Play 스토어를 통해서만 Android 앱을 배포하도록 제한되지는 않습니다.

Firebase 및 FCM SDK 설정

  1. 아직 추가하지 않았다면 Android 프로젝트에 Firebase를 추가합니다.
  2. Android 스튜디오에서 앱 수준 build.gradle 파일에 FCM 종속 항목을 추가합니다.
  3. dependencies {
        compile 'com.google.firebase:firebase-messaging:12.0.1'
    }

앱 매니페스트 수정

앱의 매니페스트에 다음을 추가합니다.

  • FirebaseMessagingService를 확장하는 서비스를 추가합니다. 백그라운드에서 앱의 알림을 수신하는 것 외에 다른 방식으로 메시지를 처리하려는 경우에 필요합니다. 포그라운드 앱의 알림 수신, 데이터 페이로드 수신, 업스트림 메시지 전송 등을 수행하려면 이 서비스를 확장해야 합니다.
  • <service    android:name=".MyFirebaseMessagingService">    <intent-filter>        <action android:name="com.google.firebase.MESSAGING_EVENT"/>    </intent-filter></service>AndroidManifest.xml
  • 등록 토큰 생성, 순환, 업데이트를 처리하기 위해 FirebaseInstanceIdService를 확장하는 서비스를 추가합니다. 특정 기기로 전송하거나 기기 그룹을 만드는 경우에 필요합니다.
  • <service    android:name=".MyFirebaseInstanceIDService">    <intent-filter>        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>    </intent-filter></service>AndroidManifest.xml
  • (Optional) Android 8.0(API 수준 26) 이상부터는 알림 채널이 지원 및 권장됩니다. FCM은 기본적인 설정과 함께 기본 알림 채널을 제공합니다. 기본 채널을 직접 만들어 사용하려면 아래와 같이 default_notification_channel_id를 알림 채널 객체의 ID로 설정합니다. 수신 메시지에 알림 채널이 명시적으로 설정되지 않았으면 FCM에서 이 값을 사용합니다. 자세한 내용은알림 채널 관리를 참조하세요.
  • <meta-data    android:name="com.google.firebase.messaging.default_notification_channel_id"    android:value="@string/default_notification_channel_id"/>AndroidManifest.xml
  • Android 앱의 기능에 FCM이 매우 중요한 경우 앱의 build.gradle에서 minSdkVersion 8 이상을 설정하세요. 그러면 Android 앱을 제대로 실행할 수 없는 환경에서는 앱을 설치할 수 없습니다.

 

 

FirebaseInstanceIdService

등록 토큰 생성, 순환, 업데이트를 처리에 대한 서비스를 하게 됩니다.

 

기기 등록 토큰 액세스

앱을 처음 시작할 때 FCM SDK에서 클라이언트 앱 인스턴스용 등록 토큰을 생성합니다. 단일 기기를 타겟팅하거나 기기 그룹을 만들려면 FirebaseInstanceIdService를 확장하여 이 토큰에 액세스해야 합니다.

이 섹션에서는 토큰을 검색하고 토큰의 변경을 모니터링하는 방법을 설명합니다. 토큰은 최초 시작 후에 회전될 수 있으므로 마지막으로 업데이트된 등록 토큰을 검색하는 것이 좋습니다.

다음과 같은 경우에 등록 토큰이 변경될 수 있습니다.

  • 앱에서 인스턴스 ID 삭제
  • 새 기기에서 앱 복원
  • 사용자가 앱 삭제/재설치
  • 사용자가 앱 데이터 소거

 

현재 등록 토큰 검색

현재 토큰을 검색하려면 FirebaseInstanceId.getInstance().getToken()을 호출합니다. 토큰이 아직 생성되지 않은 경우 null이 반환됩니다.

 

토큰 생성 모니터링

토큰이 새로 생성될 때마다 onTokenRefresh 콜백이 실행되므로 이 콜백의 컨텍스트에서 getToken을 호출하면 사용 가능한 현재 등록 토큰에 항상 액세스하게 됩니다. manifests에 서비스가 추가되었는지 확인한 다음 아래와 같이 onTokenRefresh의 Context에서 getToken을 호출하고 값을 기록합니다.

MyFirebaseInstanceIDService.java

 

public class MyFirebaseInstanceIdService extends FirebaseInstanceIdService {    @Override    public void onTokenRefresh() {        // Get updated InstanceID token.        String refreshedToken = FirebaseInstanceId.getInstance().getToken();        Log.d(TAG, "Refreshed token: " + refreshedToken);​        // If you want to send messages to this application instance or        // manage this apps subscriptions on the server side, send the        // Instance ID token to your app server.        sendRegistrationToServer(refreshedToken);    }}

토큰이 확보되었으면 앱 서버로 전송하고 원하는 방법으로 저장할 수 있습니다. API에 대한 자세한 내용은 Instance ID API 참조를 확인하세요.

 

FirebaseInstanceIDService

백그라운드에서 앱의 알림을 수신하는 것 외에 다른 방식으로 메시지를 처리하려는 경우에 필요합니다. 포그라운드 앱의 알림 수신, 데이터 페이로드 수신, 업스트림 메시지 전송 등을 수행하려면 이 서비스를 확장해야 합니다.

 

메시지 처리

메시지를 수신하려면 FirebaseMessagingService를 확장하는 서비스를 사용합니다. 서비스에서 onMessageReceivedonDeletedMessages 콜백을 재정의해야 합니다. 모든 메시지는 수신된 지 10초 이내에 처리되어야 합니다. 이후에는 Android에서 실행을 보장하지 않으며 언제든지 프로세스가 종료될 수 있습니다. 앱에서 메시지를 처리하는 데 시간이 더 필요하면 Firebase Job Dispatcher를 사용하세요.

 

앱 상태 알림 데이터 모두
포그라운드 onMessageReceived onMessageReceived onMessageReceived
백그라운드 작업표시줄 onMessageReceived 알림 : 작업표시줄<br />데이터:인텐트 부가 정보

 

알림의 모양을 맞춤설정하는 기본값을 설정하는 것이 좋습니다. 맞춤 기본 아이콘 및 맞춤 기본 색상을 지정하여 알림 페이로드에 해당 값이 설정되지 않았을 때 항상 적용할 수 있습니다.

application 태그 안에 다음 줄을 추가하여 맞춤 기본 아이콘 및 맞춤 색상을 설정합니다.

AndroidManifest.xml

 

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.     See README(https://goo.gl/l4GJaQ) for more. --><meta-data    android:name="com.google.firebase.messaging.default_notification_icon"    android:resource="@drawable/ic_stat_ic_notification" /><!-- Set color used with incoming notification messages. This is used when no color is set for the incoming     notification message. See README(https://goo.gl/6BKBk7) for more. --><meta-data    android:name="com.google.firebase.messaging.default_notification_color"    android:resource="@color/colorAccent" />AndroidManifest.xml

맞춤 기본 아이콘이 설정되지 않았고 알림 페이로드에도 아이콘이 설정되지 않았으면 Android에서 애플리케이션 아이콘을 흰색으로 렌더링해 표시합니다.

 

FirebaseInstanceIDService 의 onMessageReceived 재정의

FirebaseMessagingService.onMessageReceived 메소드를 재정의하면 수신된 RemoteMessage 객체를 기준으로 작업을 수행하고 메시지 데이터를 가져올 수 있습니다. 모든 메시지는 10초 이내에 수신 처리 되어야 하며 10초 이상의 실행 작업의 경우 Firebase Job Dispatcher를 사용하면 됩니다.

 

public class MyFirebaseMessagingService extends FirebaseMessagingService {    @Override    public void onMessageReceived(RemoteMessage remoteMessage) {//        super.onMessageReceived(remoteMessage);​        // Handle FCM Message        Log.d(Constants.Companion.getLOG_TAG(), remoteMessage.getFrom());​        // Check if message contains a data payload.        if (remoteMessage.getData().size() > 0){            Log.d(Constants.Companion.getLOG_TAG(), "Message data payload: " + remoteMessage.getData());​            // 만약 10초보다 더 많은 시간을 할당 받으려면//            scheduleJob();            // Handle 10초 할 경우            handleNow();        }​        // Check if message contains a notification payload.        if (remoteMessage.getNotification() != null){            Log.d(Constants.Companion.getLOG_TAG(), "Message Notification Body: " + remoteMessage.getNotification().getBody());        }    }​    /**    * 앱에서 메시지를 처리하는 데 시간이 더 필요하면 Firebase Job Dispatcher를 사용    */    private void scheduleJob(){        // [START dispatch_job]        FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));        Job myJob = dispatcher.newJobBuilder()                .setService(SGJobService.class)                .setTag("my-job-tag")                .build();        dispatcher.schedule(myJob);        // [END dispatch_job]    }​    private void handleNow(){        Log.d(Constants.Companion.getLOG_TAG(), "Short lived task is done.");    }​}

 

onDeletedMessages재정의

경우에 따라 FCM에서 메시지를 전달하지 못할 수 있습니다. 특정 기기가 연결될 때 앱에서 대기 중인 메시지가 너무 많거나(100개 초과) 기기가 한 달 이상 FCM에 연결되지 않았기 때문일 수 있습니다. 이러한 경우 FirebaseMessagingService.onDeletedMessages()에 콜백이 수신될 수 있습니다. 이 콜백을 수신한 앱 인스턴스는 앱 서버와 전체 동기화를 수행해야 합니다. 해당 기기의 앱으로 메시지를 보낸 지 4주 이상 경과한 경우 FCM은 onDeletedMessages()를 호출하지 않습니다.

SGFirebaseMessagingService.java

 

@Overridepublic void onDeletedMessages() {    Log.e(Constants.Companion.getLOG_TAG(), "Messageon DeletedMessages");}

 

백그라운드 앱에서 알림 메시지 처리

앱이 백그라운드 상태이면 Android에서 알림 메시지를 작업 표시줄로 전달합니다. 사용자가 알림을 탭하면 기본적으로 앱 런처가 열립니다.

여기에는 알림과 데이터 페이로드가 모두 들어 있는 메시지 및 알림 콘솔에서 보낸 모든 메시지가 포함됩니다. 이러한 경우 알림은 기기의 작업 표시줄로 전송되고 데이터 페이로드는 런처 활동의 인텐트 부가 정보로 전송됩니다.

애플리케이션 구성요소에 기본 아이콘 및 색상을 설정하는 메타데이터 요소를 추가합니다. Android는 수신 메시지에 아이콘 또는 색상이 명시적으로 설정되지 않은 경우 이 값을 사용합니다.

AndroidManifest.xml

 

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.     See README(https://goo.gl/l4GJaQ) for more. --><meta-data    android:name="com.google.firebase.messaging.default_notification_icon"    android:resource="@drawable/ic_stat_ic_notification" /><!-- Set color used with incoming notification messages. This is used when no color is set for the incoming     notification message. See README(https://goo.gl/6BKBk7) for more. --><meta-data    android:name="com.google.firebase.messaging.default_notification_color"    android:resource="@color/colorAccent" />

 

FCM 메신지 데이터 처리

앱 상태는 포그라운드, 백그라운드 두가지로 나눠지며 각 상태에 따라서 다음과 같이 동작하게 됩니다.

포그라운드는 MyFirebaseMessagingService.onMessageReceived 에 알림, 데이터가 오게 되며 작업표시줄에는 표시가 안됩니다.

백그라운드에서는 알림은 작업표시줄, 데이터는 MyFirebaseMessagingService.onMessageReceived 에 호출 됩니다. 하지만 알림과 데이터를 같이 보낼 시 알림은 작업표시줄, 데이터는 Intent로 데이터가 전송됩니다.

 

앱 상태 알림 데이터 모두
포그라운드 onMessageReceived onMessageReceived onMessageReceived
백그라운드 작업표시줄 onMessageReceived 알림 : 작업표시줄<br />데이터:인텐트 부가 정보

 

백그라운드 처리

백그라운드에서 Messaging 왔을 시 데이터는 인텐트로 전송됩니다. getIntent().getExtras() 로 인텐트로 전송된 데이터를 받을 수 있습니다.

MainActivity.kt

 

override fun onCreate(savedInstanceState: Bundle?) {    super.onCreate(savedInstanceState)    setContentView(R.layout.activity_main)    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {    // Create channel to show notifications.    val channelId = getString(R.string.default_notification_channel_id)    val channelName = getString(R.string.default_notification_channel_name)    val notificationManager = getSystemService(NotificationManager::class.java)    notificationManager!!.createNotificationChannel(NotificationChannel(channelId,    channelName, NotificationManager.IMPORTANCE_LOW))    }​    // Push Data 로 넘어 왔을 시 처    if (intent?.extras != null){        for (key: String in intent!!.extras!!.keySet()){        val value = intent!!.extras!!.get(key)        Log.d(Constants.LOG_TAG, "Key: ," + key + " Value: " + value);        }    }}

 

포그라운드 처리

포그라운드에서 푸시 왔을 시 MyFirebaseMessagingService.onMessageReceived 에 알림 데이터가 오게 됩니다.

포그라운드 상태에서 푸시의 데이터에 따른 화면 갱신이 필요한 경우가 있습니다. MyFirebaseMessagingService.onMessageReceived 로 전송받은 데이터를 포함한 Notification 생성합니다. 생성한 Notification을 클릭하면 MainActivity가 실행되면서 getIntent().getExtreas() 로 데이터를 가져와 상황에 따른 UI 변경이 가능합니다.

MyFirebaseMessagingService.java

 

private void sendNotification(Map<String, String> data){    Intent intent = new Intent(this, MainActivity.class);    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);​    // Push로 받은 데이터를 그대로 다시 intent에 넣어준다.    if (data != null && data.size() >0) {        for(String key : data.keySet()){            intent.putExtra(key, data.get(key));        }    }​    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);​    String channelId = getString(R.string.default_notification_channel_id);    Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId)        .setSmallIcon(R.drawable.ic_stat_ic_notification)        .setContentTitle("FCM Message")        .setAutoCancel(true)        .setSound(defaultSoundUri)        .setContentIntent(pendingIntent);​    NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);​    // Notification 채널을 설정합니다.    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {        NotificationChannel channel = new NotificationChannel(channelId, "Channel human readable title", NotificationManager.IMPORTANCE_DEFAULT);        notificationManager.createNotificationChannel(channel);    }​    notificationManager.notify(0, notificationBuilder.build());}

 

Firebase Consol 로 Push 보내기

Firebase Consol로 Push 보내어 정상적으로 동작하는지 확인하겠습니다.

 

Firebase > 성장 > Cloud Messaging

 

첫 번째 메시지를 보냅니다.

 

테스트를 위해서 단일 기기로 보내겠습니다.

메시지 내용은 TEST 로 하며 단일 기기의 토큰을 입력합니다.

FCM 토큰 값은 앱을 실행 하면 AppDelegate에서 print 한 값을 확인 할 수 있습니다.

 

//실제 토큰값은 더 길고 복잡합니다.InstanceID Token: AnLVPk:APA91bHUlPNOQaj-kXU2PwJQwOcLux3wXV2d1xcEvMQl2uWT....

 

모두 작성했으면 메시지 보내기 버튼을 클릭하여 메시지를 보냅니다.

Clould Messaging 전송 시 메시지 성공 여부 화면으로 전환되어 메시지 성공률 등 메시지 전송 현황을 확인할 수 있습니다.

 

 

 

정리

Android Firebase Clould Message(FCM) 클라이언트 설정과 푸시 테스트 하는 방법을 공유하였습니다.

앱에 없어서는 안되는 FCM 통신 구현을 앱의 특성에 맞게 응용하신다면 원하는 결과 얻으실 것입니다.

FCM 기능 및 설정에 대한 자세한 내용은 Google Clould Messaing 에서 확인할 수 있습니다.

반응형
댓글