건프의 소소한 개발이야기

[안드로이드] Google Cloud Message(GCM) 적용시키기 - (2) 본문

개발 이야기/안드로이드 이야기

[안드로이드] Google Cloud Message(GCM) 적용시키기 - (2)

건강한프로그래머 2016. 5. 7. 02:38

안녕하세요, 건프입니다.



시리즈 


[안드로이드] Google Cloud Message(GCM) 적용시키기 - (1)

http://ljs93kr.tistory.com/14

[안드로이드] Google Cloud Message(GCM) 적용시키기 - (2)

http://ljs93kr.tistory.com/15

[안드로이드] Google Cloud Message(GCM) 적용시키기 - (3)

http://ljs93kr.tistory.com/45


앞서 google service 에서 push server configuration key 와 file을 발급받았습니다.

http://ljs93kr.tistory.com/14

이제 안드로이드 스튜디오로 돌아와 작업해주면 됩니다.


1. 디팬던시 설정

가이드 라인을 확인해보면, google-services.json 파일을 app/ 아래에 옮긴뒤에

project-level 아래의 build.gradle 에 classpath 을 입력하고,

app-level 아래의 build.gradle에 plugin 을 입력하라고 되어 있습니다.

다음과 같이 진행하시면 됩니다.


project-level build.gradle


app-level build.gradle


그리고  app-level 의 build.gradle 에 다음과같이 라이브러리를 추가해주면 됩니다.

compile "com.google.android.gms:play-services-gcm:8.3.0"

여기단계에서 싱크 오류가 난다면, 적절히 오류메세지를 보면서, 해달라는대로 버전정보를 바꿔주면 됩니다. 


2. Manifest file 수정

AndroidManifest file도 약간 손 바줘야 합니다.

우선 퍼미션입니다.

<!-- [START gcm_permission] -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- [END gcm_permission] -->

GCM이 되기전, 서비스의 이름이 c2dm 였습니다. 아직도 그 흔적이 남아있음을 알 수 있습니다.


그리고 application 태그 아래, 기본적으로 작성해야할 서비스들과 리시버들이 있습니다.


3. receiver 

<!-- [START gcm_receiver] -->
<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.brianandroid.myzzung.coli.gcm" />
</intent-filter>
</receiver>
<!-- [END gcm_receiver] -->

바꿀 필요없이 그대로 사용하시면 됩니다.


4. GcmListenerService

<!-- [START gcm_listener_service] -->
<service
android:name="com.brianandroid.myzzung.coli.gcm.CoilGcmListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<!-- [END gcm_listener_service] -->

CoilGcmListenerService 클래스를 이따가 구현할 것입니다.

Gcm 을 수령했을때, 발동하는 서비스 클래스 입니다.


5. 기기별 구분 token(key)를 등록하는 서비스 입니다.

<!-- [START gcm_registration_service] -->
<service
android:name="com.brianandroid.myzzung.coli.gcm.RegisterationIntentService"
android:exported="false"/>
<!-- [END gcm_registration_service] -->

RegisterationIntentService 클래스를 이따가 구현할 겁니다.


6.  InstanceID 가 변했을 때, 동작하는 서비스 입니다.

<!-- [START instanceId_listener_service] -->
<service
android:name="com.brianandroid.myzzung.coli.gcm.CoilInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<!-- [END instanceId_listener_service] -->



7. 클래스 구현

7-1) CoilGcmListenerService.java

public class CoilGcmListenerService extends GcmListenerService {

@Override
public void onMessageReceived(String from, Bundle data) {
super.onMessageReceived(from, data);

String title = data.getString("title");
String message = data.getString("message");
String is_notifi = data.getString("notification_type");
if(is_notifi.equals("true")){
CoilNotification cnb = new CoilNotification(getApplicationContext());
cnb.sendNotification(title, message, CoilNotification.BY_GCM);
}
}
}


GCM 메세지가 수신되었을때, 동작하는 서비스 입니다.

CoilNotification 클래스는 노티피케이션 기능을 담당하는 모듈입니다. 이전 포스팅에서 설명한 적이 있으므로 생략하겠습니다.

http://ljs93kr.tistory.com/1


7-2) 사용자 token 등록하는 서비스 : RegisterationIntentService.java

public class RegisterationIntentService extends IntentService {

private static final String TAG = "RegistrationIntentService";

/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public RegisterationIntentService() {
super(TAG);
}

@SuppressLint("LongLogTag")
@Override
protected void onHandleIntent(Intent intent) {
// GCM Instance ID의 토큰을 가져오는 작업이 시작되면 LocalBoardcast로 GENERATING 액션을 알려 ProgressBar가 동작하도록 한다.
LocalBroadcastManager.getInstance(this)
.sendBroadcast(new Intent(QuickstartPreferences.REGISTRATION_GENERATING));

Log.d(TAG, "in Registerservice");
// GCM을 위한 Instance ID를 가져온다.
InstanceID instanceID = InstanceID.getInstance(this);
String token = null;
try {
synchronized (TAG) {
// GCM 앱을 등록하고 획득한 설정파일인 google-services.json을 기반으로 SenderID를 자동으로 가져온다.
String default_senderId = getString(R.string.gcm_defaultSenderId);
// GCM 기본 scope는 "GCM"이다.
String scope = GoogleCloudMessaging.INSTANCE_ID_SCOPE;
// Instance ID에 해당하는 토큰을 생성하여 가져온다.
token = instanceID.getToken(default_senderId, scope, null);

Log.i(TAG, "GCM Registration Token: " + token);
}
} catch (IOException e) {
e.printStackTrace();
}

// GCM Instance ID에 해당하는 토큰을 획득하면 LocalBoardcast에 COMPLETE 액션을 알린다.
// 이때 토큰을 함께 넘겨주어서 UI에 토큰 정보를 활용할 수 있도록 했다.
Intent registrationComplete = new Intent(QuickstartPreferences.REGISTRATION_COMPLETE);
registrationComplete.putExtra("token", token);
LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}
}


7-3) CoilInstanceIDListenerService.java

public class CoilInstanceIDListenerService extends InstanceIDListenerService {

private static final String TAG = "MyInstanceIDLS";

@Override
public void onTokenRefresh() {
Intent intent = new Intent(this, RegisterationIntentService.class);
startService(intent);
}
}


7-4) LocalBroadcastManager 에서 사용할 String Flag들

public class QuickstartPreferences {
public static final String REGISTRATION_READY = "registrationReady";
public static final String REGISTRATION_GENERATING = "registrationGenerating";
public static final String REGISTRATION_COMPLETE = "registrationComplete";
}


7-5) 보여질 화면의 xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.brianandroid.myzzung.coli.ui.SettingFragment">

<!-- TODO: Update blank fragment layout -->
<Button android:id="@+id/registrationButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="gcm token 받기" />

<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/informationTextView"
android:textAppearance="?android:attr/textAppearanceMedium"/>

<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/registrationProgressBar" />

</LinearLayout>


7-6) 보여질 화면의 java 코드

public class SettingFragment extends Fragment {

private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
private static final String TAG = "MainActivity";

private Button mRegistrationButton;
private ProgressBar mRegistrationProgressBar;
private BroadcastReceiver mRegistrationBroadcastReceiver;
private TextView mInformationTextView;

public SettingFragment() {
// Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
ViewGroup rootView = (ViewGroup)inflater.inflate(R.layout.fragment_setting, container, false);


registBroadcastReceiver();
setLocalBoradcastManager(getActivity());

// 토큰을 보여줄 TextView를 정의
mInformationTextView = (TextView) rootView.findViewById(R.id.informationTextView);
//mInformationTextView.setVisibility(View.GONE);
// 토큰을 가져오는 동안 인디케이터를 보여줄 ProgressBar를 정의
mRegistrationProgressBar = (ProgressBar) rootView.findViewById(R.id.registrationProgressBar);
mRegistrationProgressBar.setVisibility(ProgressBar.GONE);
// 토큰을 가져오는 Button을 정의
mRegistrationButton = (Button) rootView.findViewById(R.id.registrationButton);
mRegistrationButton.setOnClickListener(new View.OnClickListener() {
/**
* 버튼을 클릭하면 토큰을 가져오는 getInstanceIdToken() 메소드를 실행한다.
* @param view
*/
@Override
public void onClick(View view) {
Toast.makeText(getActivity(), "click", Toast.LENGTH_SHORT).show();
getInstanceIdToken();
}
});

return rootView;
}

/**
* Google Play Service를 사용할 수 있는 환경이지를 체크한다.
*/
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity());
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, getActivity(),
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.i(TAG, "This device is not supported.");
}
return false;
}
return true;
}

/**
* Instance ID를 이용하여 디바이스 토큰을 가져오는 RegistrationIntentService를 실행한다.
*/
public void getInstanceIdToken() {
if (checkPlayServices()) {
// Start IntentService to register this application with GCM.
Intent intent = new Intent(getActivity(), RegisterationIntentService.class);
getActivity().startService(intent);
}else{
Toast.makeText(getActivity(), "no in regis service", Toast.LENGTH_SHORT).show();
}
}

/**
* LocalBoardcastManager 를 등록한다
* @param context
*/
private void setLocalBoradcastManager(Context context){
LocalBroadcastManager.getInstance(context).registerReceiver(mRegistrationBroadcastReceiver,
new IntentFilter(QuickstartPreferences.REGISTRATION_READY));
LocalBroadcastManager.getInstance(context).registerReceiver(mRegistrationBroadcastReceiver,
new IntentFilter(QuickstartPreferences.REGISTRATION_GENERATING));
LocalBroadcastManager.getInstance(context).registerReceiver(mRegistrationBroadcastReceiver,
new IntentFilter(QuickstartPreferences.REGISTRATION_COMPLETE));
}

/**
* LocalBoardcastManager를 해제한다
* @param context
*/
private void deleteLocalBoardcastManager(Context context){
LocalBroadcastManager.getInstance(context).unregisterReceiver(mRegistrationBroadcastReceiver);
}

/**
* LocalBroadcast 리시버를 정의한다. 토큰을 획득하기 위한 READY, GENERATING, COMPLETE 액션에 따라 UI에 변화를 준다.
*/
public void registBroadcastReceiver(){
mRegistrationBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();


if(action.equals(QuickstartPreferences.REGISTRATION_READY)){
// 액션이 READY일 경우
mRegistrationProgressBar.setVisibility(ProgressBar.GONE);
mInformationTextView.setVisibility(View.GONE);
} else if(action.equals(QuickstartPreferences.REGISTRATION_GENERATING)){
// 액션이 GENERATING일 경우
mRegistrationProgressBar.setVisibility(ProgressBar.VISIBLE);
mInformationTextView.setVisibility(View.VISIBLE);
mInformationTextView.setText("gcm token 생성중...");
} else if(action.equals(QuickstartPreferences.REGISTRATION_COMPLETE)){
// 액션이 COMPLETE일 경우
mRegistrationProgressBar.setVisibility(ProgressBar.GONE);
mRegistrationButton.setText("gcm token 생성완료!");
mRegistrationButton.setEnabled(false);
String token = intent.getStringExtra("token");
mInformationTextView.setText(token);
}

}
};
}


}

각각의 코드가 어떤 기능을 하는지는, 차근차근 확인해보시면 알 수 있습니다.

여기서는 MainUI 화면에서 getInstanceIdToken() 을 요청하고, LocalBoardcast를 연결해놓습니다.

RegisterationIntentService 에서 사용자 Token 을 얻어오면, Boardcast로 send 합니다.

해당 Intent를 받은 Boardcast Receiver 가 MainUI 에서 잡아내 동작합니다.



이제 메세지를 푸시할 서버를 만들어낼 차례입니다.

Comments