본문 바로가기

개발 코딩 정보 공유/안드로이드 자바 코틀린

안드로이드 GCM을 FCM로 마이그레이션 해봅시다

 

 

 

 

 

GCM 을 FCM 으로 마이그레이션 합시다

 

 

 

 

 

 

 

 

응? 나를 뭐 어쩐다고?

 

 

 

 

 

 

 

구글정책에 따른 문제파악

 

다들 바꾸셨겠지만 오래된 플랫폼의 경우 아직도 구글 GCM을 활용한 푸시서비스 방식을 쓰고있습니다.

이미 구글에서 2018년 4월 10일 부터 GCM 사용중지 공고를 하였습니다. 그럼에도 GCM을 쓰셔야 겠다면...

안타깝지만 불가능 합니다.

 

" 2018 년 4 월 10 일부터 Google은 GCM을 사용 중지했습니다. "

 

" GCM 서버 및 클라이언트 API는 더 이상 사용되지 않으며 2019 년 4 월 11 일에 즉시 삭제됩니다 . "

 

" 신뢰할 수 있고 확장 가능한 GCM 인프라와 많은 새로운 기능을 상속하는 FCM ( Firebase Cloud Messaging)으로

GCM 앱을 마이그레이션 합니다. 자세한 내용은 마이그레이션 가이드 를 참조하십시오 . "

 

 

그렇다면 GCM을 FCM으로 잘 갈아 입혀줘야 겠죠. 

그렇게 복잡하지 않습니다. 일단은요...

몇가지 알고 가야할 사항이 있습니다.

 

1. GCMFCM SDK는 응용 프로그램 내에서 공존 할 수 없습니다.

2. GCM 토큰 은 수정되거나 갱신되지 않고 FCM에서 검색 GoogleCloudMessaging.register()되거나 

InstanceID.getToken()계속 작동합니다.

 

 

당연하게도 GCM과 FCM은 같이 쓸수 없습니다.

이번에 GCM 마이그레이션편의 큰 그림을 설명해드리자면 결국엔 GCM 관련을 다 지우고(로직부분은 그대로 두고) FCM 을 추가하는 것 입니다. 결론은 다 갈아 엎어야 함.

 

 

 

 

시작해 봅시다!

 

 

1. 우선은 구글 콘솔에서 프로젝트를 생성합니다.

 

URL : https://console.firebase.google.com/

 

기존의 생성 프로젝트가 있다면 해당앱을 추가해도 됩니다.

추가하면 "google-services.json" 파일을 받게 됩니다.

이 파일을 까보시면 여러가지 중요한 보안키가 들어있습니다. 해당파일은 공개적으로 공유 해놓으시면 안됩니다.

해당파일은 프로젝트의 app폴더 밑으로 복사해줍니다.

 
 
 
 
2. 라이브러리의 교체
 
앱수준의 build.gradle을 보면 기존에 
dependencies { com.google.android.gms : play-services-gcm : 15.0.1 " }
이런 비슷한 구분을 사용했을겁니다.
 
dependencies { "com.google.firebase : firebase-messaging : 17.3.0" }
이런식으로 변경해주십니다.
 
* 버전은 각자 알아서 최신에 맞게 설정합니다.

 

 

 

 

 

3.  AndroidManifest.xml (매니페스트) 의 수정

 

*** FCM SDK는 필수 수신기 기능뿐만 아니라 필요한 모든 권한을 자동으로 추가합니다

라고 합니다. 그러므로 불필요한 기존의 요소들은 제거 해줍니다.

 

<제거>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission android:name="<your-package-name>.permission.C2D_MESSAGE"
            android:protectionLevel="signature" />
<uses-permission android:name="<your-package-name>.permission.C2D_MESSAGE" />
 
...
 
<receiver
    android:name="com.google.android.gms.gcm.GcmReceiver"
    android:exported="true"
    android:permission="com.google.android.c2dm.permission.SEND" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <category android:name="com.example.gcm" />
    </intent-filter>
</receiver>
cs

 

 

 

 

 

 

***파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음

 

 

 

 

4. Service의 교체

https://developers.google.com/cloud-messaging/android/android-migrate-iid-service

 

단일 기기에 푸시를 쏘기 위해서는 토큰이 필요합니다.

IIDListenerService를 사용하여 구현해주셔야 합니다.

 
<교체>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//1.이놈을 
<service
    android:name=".MyInstanceIDListenerService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.android.gms.iid.InstanceID" />
    </intent-filter>
</service>
 
//2. 이놈으로 
<service
    android:name=".MyInstanceIDListenerService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
    </intent-filter>
</service>
cs
 
 
 
 
 
 

5. service 소스의 수정

onTokenRefresh 에서 생성된 토큰을 받아 서버에 저장하고나 로그로 찍어보거나 지지고 볶고 씹고 뜯고 맛보고 즐기고

 

<소스수정>

1
2
3
4
5
6
7
8
9
10
11
12
//1.이놈을
public class MyInstanceIDListenerService extends InstanceIDListenerService {
 
  ...
 
  @Override
  public void onTokenRefresh() {
      // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
      Intent intent = new Intent(this, RegistrationIntentService.class);
      startService(intent);
  }
}
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//2. 이놈으로
public class MyInstanceIDListenerService extends FirebaseInstanceIdService {
 
  ...
 
  /**
   * Called if InstanceID token is updated. This may occur if the security of
   * the previous token had been compromised. Note that this is also called
   * when the InstanceID token is initially generated, so this is where
   * you retrieve the token.
   */
  // [START refresh_token]
  @Override
  public void onTokenRefresh() {
      // Get updated InstanceID token.
      String refreshedToken = FirebaseInstanceId.getInstance().getToken();
      Log.d(TAG, "Refreshed token: " + refreshedToken);
      // TODO: Implement this method to send any registration to your app's servers.
      sendRegistrationToServer(refreshedToken);
  }
 
}
cs

 

 

 

 

 

6. 기존의 token 가져오는 소스 수정

1
2
3
4
5
InstanceID instanceID = InstanceID.getInstance(this);
  String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
          GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
  // [END get_token]
  Log.i(TAG, "GCM Registration Token: " + token);
cs

  

이런 비슷한 부분이 있을텐데요. 이건 이제 필요치 않습니다.

과감히 지워주시죠. 

 

현재의 토큰은 FirebaseInstanceId.getInstance().getToken();

이런식으로 받아올수 있습니다.

 

 

 

7. 푸시 받고 나서의 로직 구현

GcmListenerService 을 FirebaseMessagingService 로 변경/구현합니다.

*** notiChannel의 경우 api26 안드로이드 8.0 대비하여 구현함.

 

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class SFMessagingService extends FirebaseMessagingService {
 
    @Override
    public void onMessageReceived(RemoteMessage message) {
 
        String from = message.getFrom();
        Log.d(TAG, "From: " + from);
        setNotification(this, message);
 
    }
 
    private void setNotification(Context context, RemoteMessage remoteMessage) {
        //String notiBody = remoteMessage.getNotification().getBody();
        Map<StringString> data = remoteMessage.getData();
        if(data.isEmpty()){
            return;
        }
 
        Logger.e(TAG, data.toString());
 
        String type = data.get("type");
        String message = data.get("message");
        String bcn_cd = data.get("bcn_cd");
 
        ... 
 
        //알아서 구현
 
        ...
 
        //알림을 띄우던 화면이 동작중이라면 다이얼로그를 띄우던...
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, context.getString(R.string.noti_channel_id))
                .setLargeIcon(bitmap)
                .setSmallIcon(R.mipmap.ic_notification)
                .setColor(Color.parseColor("#c31531"))
                .setContentTitle(title)
                .setContentText(msg)
                .setPriority(NotificationCompat.PRIORITY_HIGH)
                .setAutoCancel(true)
                .setStyle(new NotificationCompat.BigTextStyle())
//                .setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);
 
        NotificationManager notificationManager =
                (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(index /* ID of notification */, notificationBuilder.build());
 
    }
}
cs

 

 

이정도 하면 앱에서의 마이그레이션은 완료됩니다.

https://console.firebase.google.com/project/[프로젝트Id]/notification

구글콘솔에서 테스트 메세지 전송이 가능합니다. 

 

다들 문제없이 변경되셨기를 바랍니다. 

서버쪽 설정은 다음편에서...

 

 

*** 에러가 나시나요? build.gradle 에 아래와같이 들어가 있는지 확인해보세요.

저도 구글 그대로 따라했다가 에러나서 한참 찾았네요.

 

api 'com.google.firebase:firebase-core:16.0.1'

api 'com.google.firebase:firebase-messaging:17.3.0'

 

 

참고 : 

https://developers.google.com/cloud-messaging/android/android-migrate-fcm