GCM 구현1 - Android

 

 

안드로이드 : http://ghj1001020.tistory.com/783?category=719597

서버 : http://ghj1001020.tistory.com/784?category=756570

 

 

가이드 : https://developers.google.com/cloud-messaging/android/client

 

1. 앱은 GCM 토큰을 가져와서 앱에 저장합니다

2. 서버에서 앱에 저장된 GCM 토큰을 사용하여 메시지를 요청합니다

3. 앱이 GCM 메시지 수신하고 알림을 띄웁니다

* 테스트 용도 이므로 토큰을 서버에 저장하는 부분은 제외했습니다. (서버에서는 디바이스의 GCM 토큰을 하드코딩해서 보냅니다)

 

 

build.gradle
1
2
3
4
5
dependencies {
    ...
    //gcm
    implementation 'com.google.android.gms:play-services-gcm:11.8.0'
}
cs

 

 

AndroidManifest.xml

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
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    
 
    <application>
 
        ...
        <!-- GCM -->
        <!-- GCM으로 부터 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" />
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
 
                <category android:name="com.ghj.gcmex" />
            </intent-filter>
        </receiver>
 
        <!-- 등록 토큰 생성 및 업데이트 처리 -->
        <service android:name=".gcm.MyInstanceIDService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.android.gms.iid.InstanceID" />
            </intent-filter>
        </service>
 
        <!-- 메시지 수신처리 -->
        <service android:name=".gcm.MyGcmListenerService"
android:exported="false">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            </intent-filter>
        </service>
 
        <!-- 토큰 가져오기 -->
        <service android:name=".gcm.RegistrationIntentService"
            android:exported="false" />
 
    </application>

cs

* 메시지 수신할 때 절전모드를 유지하기위해 WAKE_LOCK 권한을 줍니다

* com.google.android.gms.gcm.GcmReceiver 은 GCM으로부터 메시지를 받는 리시버입니다

 

 

MyInstanceIDService.java

1
2
3
4
5
6
7
8
9
10
public class MyInstanceIDService extends InstanceIDListenerService {
 
 
    //등록 토큰이 업데이트 되면 호출된다
    @Override
    public void onTokenRefresh() {
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    }
}
cs

* GCM 토큰이 업데이트 되면 호출되는 서비스 입니다

* 토큰을 가져와서 앱에 저장하기 위해 RegistrationIntentService 서비스를 호출합니다

 

 

RegistrationIntentService.java

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
//IntentService : 작업을 수행하는 스레드를 별도로 생성 , stopService도 자동적으로 호출
public class RegistrationIntentService extends IntentService {
 
    private static final String TAG = "RegistIntentService";
 
    public RegistrationIntentService()
    {
        super( TAG );
    }
 
 
    //서비스 시작시 호출
    @Override
    protected void onHandleIntent(@Nullable Intent intent)
    {
        String senderId = getString(R.string.gcm_sender_id);
 
        try {
            synchronized ( TAG ) {
                //토큰 가져와서 앱에 저장
                InstanceID instanceID = InstanceID.getInstance(this);
                String token = instanceID.getToken( senderId , GoogleCloudMessaging.INSTANCE_ID_SCOPE , null);
 
                Log.d("GCM_Token" , token);
                saveGcmToken(token);
            }
        } catch ( Exception e ) {
            e.printStackTrace();
        }
    }
 
    //shared preferences 에 토큰 저장
    public void saveGcmToken(String token) {
        SharedPreferences pref = getSharedPreferences(getString(R.string.pref_gcm_token) , Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = pref.edit();
        editor.putString(getString(R.string.pref_key_gcm_token) , token);
        editor.commit();
    }
}
cs

* GCM 토큰을 가져와서 앱에 저장하는 서비스 입니다

 

 

MyGcmListenerService.java

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
public class MyGcmListenerService extends GcmListenerService {
 
    private final String TAG = "MyGcmListenerService";
 
    //알림
    private final String GCM_DATA_KEY_TITLE = "title";
    private final String GCM_DATA_KEY_BODY = "body";
    private static int NOTIFICATION_ID = 0;
    private final long[] ALARM_PATTERN = new long[]{ 100100100100 };
 
 
    //메시지 수신시 호출
    @Override
    public void onMessageReceived(String s, Bundle bundle) {
        //메시지 수신 후 알림 띄우기
        if( bundle != null ) {
            Log.d(TAG, "onMessageReceived : "+bundle.toString());
 
            String title = bundle.getString(GCM_DATA_KEY_TITLE , "");
            String body = bundle.getString(GCM_DATA_KEY_BODY , "");
            sendNotificaion(title , body);
        }
    }
 
    //알림에 띄우기
    public void sendNotificaion(String title, String body) {
        NotificationManager notiManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
 
        String chGroupId = getString(R.string.alarm_ch_group_id_gcm);
        String channelId = getString(R.string.alarm_ch_id_gcm);
        //26 오레오 이상
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if!checkNotificationChannelGroup(chGroupId) ) {
                //알림 채널 그룹
                NotificationChannelGroup notiGroup = new NotificationChannelGroup( chGroupId, getString(R.string.alarm_ch_group_name_gcm) );
                notiManager.createNotificationChannelGroup( notiGroup );
            }
 
            if!checkNotificationChannel(channelId) ) {
                //알림 채널
                NotificationChannel notiChannel = new NotificationChannel(channelId, getString(R.string.alarm_ch_name_gcm), NotificationManager.IMPORTANCE_HIGH);
                notiChannel.setGroup(chGroupId);
                notiChannel.enableLights(true);
                notiChannel.setLightColor(Color.GREEN);
                notiChannel.enableVibration(true);
                notiChannel.setVibrationPattern( ALARM_PATTERN );
                notiChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
                notiChannel.setShowBadge(true);
                notiManager.createNotificationChannel(notiChannel);
            }
        }
 
        //알림 생성
        String appName = getString(R.string.app_name);
 
        Intent intent = new Intent(this, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pi = PendingIntent.getActivity(this0, intent, PendingIntent.FLAG_UPDATE_CURRENT);   //이미 존재할 경우 이를 유지하고 추가 데이터만 새로운 Intent에 있는 것으로 대체
 
        NotificationCompat.Builder noti = new NotificationCompat.Builder(this, channelId);
        noti.setAutoCancel(true);   //클릭시 알림 제거
        noti.setContentTitle(title);
        noti.setContentText(body);
        noti.setTicker(appName);
        noti.setSmallIcon(R.mipmap.ic_launcher);
        noti.setContentIntent(pi);
        noti.setVibrate( ALARM_PATTERN );
        noti.setSound( RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) );
        noti.setOngoing(false);  //지우기 버튼으로 삭제 (true - 일반 알림 위에 정렬, 지우기 버튼으로 삭제 못함)
        noti.setOnlyAlertOnce(true);    //알림이 아직 표시되지 않은 경우 사운드, 진동, 티커만 재생되도록
        noti.setWhen( System.currentTimeMillis() ); //알림에서 보여지는 발생시간
        noti.setNumber(1);  //알림의 오른쪽 번호
        noti.setGroupSummary(true);
 
        if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) {
            noti.setVisibility( Notification.VISIBILITY_SECRET );   //보안화면에서 알림 보이지 않음
        }
 
        try {
            notiManager.notify(NOTIFICATION_ID++ , noti.build() );
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    //notification channel group 등록 체크
    public boolean checkNotificationChannelGroup(String groupId) {
        boolean result = false//true : 이미 등록됨 , false : 미등록
 
        if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ) {
            NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
            List<NotificationChannelGroup> groups = notificationManager.getNotificationChannelGroups();
 
            if( groups != null && groups.size() > 0 ) {
                for ( NotificationChannelGroup group : groups ) {
                    if( groupId.equalsIgnoreCase(group.getId()) ) {
                        result = true;
                        break;
                    }
                }
            }
        }
 
        return result;
    }
 
    //notification channel 등록 체크
    public boolean checkNotificationChannel( String channelId ) {
        if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ) {
            NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
            return notificationManager.getNotificationChannel(channelId) != null ? true : false;
        }
 
        return false;
    }
}
 
cs

* GCM 메시지를 수신한 후 알림을 띄웁니다

* GCM 메시지 수신이 되면 onMessageReceived 함수가 호출됩니다

 

 

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        getGcmToken();
    }
 
    //token 가져오기
    public void getGcmToken(){
        SharedPreferences pref = getSharedPreferences(getString(R.string.pref_gcm_token) , Context.MODE_PRIVATE);
        String token = pref.getString(getString(R.string.pref_key_gcm_token), "");
 
        if( TextUtils.isEmpty(token) ) {
            Intent intent = new Intent( this, RegistrationIntentService.class );
            startService( intent );
        }
        else {
            Log.d("GCM_Token", token);
        }
    }
}
cs

* MainActivity 시작시 GCM 토큰이 없으면 GCM 토큰을 가져오는 서비스를 시작합니다

+ Recent posts